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,
   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, parse_zed_link};
   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, CharScopeContext, CodeLabel, CursorShape,
  125    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  126    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  127    TextObject, 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    ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  164};
  165use rand::seq::SliceRandom;
  166use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  167use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  168use selections_collection::{
  169    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  170};
  171use serde::{Deserialize, Serialize};
  172use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  173use smallvec::{SmallVec, smallvec};
  174use snippet::Snippet;
  175use std::{
  176    any::{Any, TypeId},
  177    borrow::Cow,
  178    cell::{OnceCell, RefCell},
  179    cmp::{self, Ordering, Reverse},
  180    iter::{self, Peekable},
  181    mem,
  182    num::NonZeroU32,
  183    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  184    path::{Path, PathBuf},
  185    rc::Rc,
  186    sync::Arc,
  187    time::{Duration, Instant},
  188};
  189use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  190use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  191use theme::{
  192    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  193    observe_buffer_font_size_adjustment,
  194};
  195use ui::{
  196    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  197    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  198};
  199use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  200use workspace::{
  201    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  202    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  203    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  204    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  205    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  206    searchable::SearchEvent,
  207};
  208
  209use crate::{
  210    code_context_menus::CompletionsMenuSource,
  211    editor_settings::MultiCursorModifier,
  212    hover_links::{find_url, find_url_from_range},
  213    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  214};
  215
  216pub const FILE_HEADER_HEIGHT: u32 = 2;
  217pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  218const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  219const MAX_LINE_LEN: usize = 1024;
  220const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  221const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  222pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  223#[doc(hidden)]
  224pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  225pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  226
  227pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  230
  231pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  232pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  233pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  234
  235pub type RenderDiffHunkControlsFn = Arc<
  236    dyn Fn(
  237        u32,
  238        &DiffHunkStatus,
  239        Range<Anchor>,
  240        bool,
  241        Pixels,
  242        &Entity<Editor>,
  243        &mut Window,
  244        &mut App,
  245    ) -> AnyElement,
  246>;
  247
  248enum ReportEditorEvent {
  249    Saved { auto_saved: bool },
  250    EditorOpened,
  251    Closed,
  252}
  253
  254impl ReportEditorEvent {
  255    pub fn event_type(&self) -> &'static str {
  256        match self {
  257            Self::Saved { .. } => "Editor Saved",
  258            Self::EditorOpened => "Editor Opened",
  259            Self::Closed => "Editor Closed",
  260        }
  261    }
  262}
  263
  264struct InlineValueCache {
  265    enabled: bool,
  266    inlays: Vec<InlayId>,
  267    refresh_task: Task<Option<()>>,
  268}
  269
  270impl InlineValueCache {
  271    fn new(enabled: bool) -> Self {
  272        Self {
  273            enabled,
  274            inlays: Vec::new(),
  275            refresh_task: Task::ready(None),
  276        }
  277    }
  278}
  279
  280#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  281pub enum InlayId {
  282    EditPrediction(u32),
  283    DebuggerValue(u32),
  284    // LSP
  285    Hint(u32),
  286    Color(u32),
  287}
  288
  289impl InlayId {
  290    fn id(&self) -> u32 {
  291        match self {
  292            Self::EditPrediction(id) => *id,
  293            Self::DebuggerValue(id) => *id,
  294            Self::Hint(id) => *id,
  295            Self::Color(id) => *id,
  296        }
  297    }
  298}
  299
  300pub enum ActiveDebugLine {}
  301pub enum DebugStackFrameLine {}
  302enum DocumentHighlightRead {}
  303enum DocumentHighlightWrite {}
  304enum InputComposition {}
  305pub enum PendingInput {}
  306enum SelectedTextHighlight {}
  307
  308pub enum ConflictsOuter {}
  309pub enum ConflictsOurs {}
  310pub enum ConflictsTheirs {}
  311pub enum ConflictsOursMarker {}
  312pub enum ConflictsTheirsMarker {}
  313
  314#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  315pub enum Navigated {
  316    Yes,
  317    No,
  318}
  319
  320impl Navigated {
  321    pub fn from_bool(yes: bool) -> Navigated {
  322        if yes { Navigated::Yes } else { Navigated::No }
  323    }
  324}
  325
  326#[derive(Debug, Clone, PartialEq, Eq)]
  327enum DisplayDiffHunk {
  328    Folded {
  329        display_row: DisplayRow,
  330    },
  331    Unfolded {
  332        is_created_file: bool,
  333        diff_base_byte_range: Range<usize>,
  334        display_row_range: Range<DisplayRow>,
  335        multi_buffer_range: Range<Anchor>,
  336        status: DiffHunkStatus,
  337    },
  338}
  339
  340pub enum HideMouseCursorOrigin {
  341    TypingAction,
  342    MovementAction,
  343}
  344
  345pub fn init_settings(cx: &mut App) {
  346    EditorSettings::register(cx);
  347}
  348
  349pub fn init(cx: &mut App) {
  350    init_settings(cx);
  351
  352    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  353
  354    workspace::register_project_item::<Editor>(cx);
  355    workspace::FollowableViewRegistry::register::<Editor>(cx);
  356    workspace::register_serializable_item::<Editor>(cx);
  357
  358    cx.observe_new(
  359        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  360            workspace.register_action(Editor::new_file);
  361            workspace.register_action(Editor::new_file_vertical);
  362            workspace.register_action(Editor::new_file_horizontal);
  363            workspace.register_action(Editor::cancel_language_server_work);
  364            workspace.register_action(Editor::toggle_focus);
  365        },
  366    )
  367    .detach();
  368
  369    cx.on_action(move |_: &workspace::NewFile, cx| {
  370        let app_state = workspace::AppState::global(cx);
  371        if let Some(app_state) = app_state.upgrade() {
  372            workspace::open_new(
  373                Default::default(),
  374                app_state,
  375                cx,
  376                |workspace, window, cx| {
  377                    Editor::new_file(workspace, &Default::default(), window, cx)
  378                },
  379            )
  380            .detach();
  381        }
  382    });
  383    cx.on_action(move |_: &workspace::NewWindow, cx| {
  384        let app_state = workspace::AppState::global(cx);
  385        if let Some(app_state) = app_state.upgrade() {
  386            workspace::open_new(
  387                Default::default(),
  388                app_state,
  389                cx,
  390                |workspace, window, cx| {
  391                    cx.activate(true);
  392                    Editor::new_file(workspace, &Default::default(), window, cx)
  393                },
  394            )
  395            .detach();
  396        }
  397    });
  398}
  399
  400pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  401    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  402}
  403
  404pub trait DiagnosticRenderer {
  405    fn render_group(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  408        buffer_id: BufferId,
  409        snapshot: EditorSnapshot,
  410        editor: WeakEntity<Editor>,
  411        cx: &mut App,
  412    ) -> Vec<BlockProperties<Anchor>>;
  413
  414    fn render_hover(
  415        &self,
  416        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  417        range: Range<Point>,
  418        buffer_id: BufferId,
  419        cx: &mut App,
  420    ) -> Option<Entity<markdown::Markdown>>;
  421
  422    fn open_link(
  423        &self,
  424        editor: &mut Editor,
  425        link: SharedString,
  426        window: &mut Window,
  427        cx: &mut Context<Editor>,
  428    );
  429}
  430
  431pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  432
  433impl GlobalDiagnosticRenderer {
  434    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  435        cx.try_global::<Self>().map(|g| g.0.clone())
  436    }
  437}
  438
  439impl gpui::Global for GlobalDiagnosticRenderer {}
  440pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  441    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  442}
  443
  444pub struct SearchWithinRange;
  445
  446trait InvalidationRegion {
  447    fn ranges(&self) -> &[Range<Anchor>];
  448}
  449
  450#[derive(Clone, Debug, PartialEq)]
  451pub enum SelectPhase {
  452    Begin {
  453        position: DisplayPoint,
  454        add: bool,
  455        click_count: usize,
  456    },
  457    BeginColumnar {
  458        position: DisplayPoint,
  459        reset: bool,
  460        mode: ColumnarMode,
  461        goal_column: u32,
  462    },
  463    Extend {
  464        position: DisplayPoint,
  465        click_count: usize,
  466    },
  467    Update {
  468        position: DisplayPoint,
  469        goal_column: u32,
  470        scroll_delta: gpui::Point<f32>,
  471    },
  472    End,
  473}
  474
  475#[derive(Clone, Debug, PartialEq)]
  476pub enum ColumnarMode {
  477    FromMouse,
  478    FromSelection,
  479}
  480
  481#[derive(Clone, Debug)]
  482pub enum SelectMode {
  483    Character,
  484    Word(Range<Anchor>),
  485    Line(Range<Anchor>),
  486    All,
  487}
  488
  489#[derive(Clone, PartialEq, Eq, Debug)]
  490pub enum EditorMode {
  491    SingleLine,
  492    AutoHeight {
  493        min_lines: usize,
  494        max_lines: Option<usize>,
  495    },
  496    Full {
  497        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  498        scale_ui_elements_with_buffer_font_size: bool,
  499        /// When set to `true`, the editor will render a background for the active line.
  500        show_active_line_background: bool,
  501        /// When set to `true`, the editor's height will be determined by its content.
  502        sized_by_content: bool,
  503    },
  504    Minimap {
  505        parent: WeakEntity<Editor>,
  506    },
  507}
  508
  509impl EditorMode {
  510    pub fn full() -> Self {
  511        Self::Full {
  512            scale_ui_elements_with_buffer_font_size: true,
  513            show_active_line_background: true,
  514            sized_by_content: false,
  515        }
  516    }
  517
  518    #[inline]
  519    pub fn is_full(&self) -> bool {
  520        matches!(self, Self::Full { .. })
  521    }
  522
  523    #[inline]
  524    pub fn is_single_line(&self) -> bool {
  525        matches!(self, Self::SingleLine { .. })
  526    }
  527
  528    #[inline]
  529    fn is_minimap(&self) -> bool {
  530        matches!(self, Self::Minimap { .. })
  531    }
  532}
  533
  534#[derive(Copy, Clone, Debug)]
  535pub enum SoftWrap {
  536    /// Prefer not to wrap at all.
  537    ///
  538    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  539    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  540    GitDiff,
  541    /// Prefer a single line generally, unless an overly long line is encountered.
  542    None,
  543    /// Soft wrap lines that exceed the editor width.
  544    EditorWidth,
  545    /// Soft wrap lines at the preferred line length.
  546    Column(u32),
  547    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  548    Bounded(u32),
  549}
  550
  551#[derive(Clone)]
  552pub struct EditorStyle {
  553    pub background: Hsla,
  554    pub border: Hsla,
  555    pub local_player: PlayerColor,
  556    pub text: TextStyle,
  557    pub scrollbar_width: Pixels,
  558    pub syntax: Arc<SyntaxTheme>,
  559    pub status: StatusColors,
  560    pub inlay_hints_style: HighlightStyle,
  561    pub edit_prediction_styles: EditPredictionStyles,
  562    pub unnecessary_code_fade: f32,
  563    pub show_underlines: bool,
  564}
  565
  566impl Default for EditorStyle {
  567    fn default() -> Self {
  568        Self {
  569            background: Hsla::default(),
  570            border: Hsla::default(),
  571            local_player: PlayerColor::default(),
  572            text: TextStyle::default(),
  573            scrollbar_width: Pixels::default(),
  574            syntax: Default::default(),
  575            // HACK: Status colors don't have a real default.
  576            // We should look into removing the status colors from the editor
  577            // style and retrieve them directly from the theme.
  578            status: StatusColors::dark(),
  579            inlay_hints_style: HighlightStyle::default(),
  580            edit_prediction_styles: EditPredictionStyles {
  581                insertion: HighlightStyle::default(),
  582                whitespace: HighlightStyle::default(),
  583            },
  584            unnecessary_code_fade: Default::default(),
  585            show_underlines: true,
  586        }
  587    }
  588}
  589
  590pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  591    let show_background = language_settings::language_settings(None, None, cx)
  592        .inlay_hints
  593        .show_background;
  594
  595    let mut style = cx.theme().syntax().get("hint");
  596
  597    if style.color.is_none() {
  598        style.color = Some(cx.theme().status().hint);
  599    }
  600
  601    if !show_background {
  602        style.background_color = None;
  603        return style;
  604    }
  605
  606    if style.background_color.is_none() {
  607        style.background_color = Some(cx.theme().status().hint_background);
  608    }
  609
  610    style
  611}
  612
  613pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  614    EditPredictionStyles {
  615        insertion: HighlightStyle {
  616            color: Some(cx.theme().status().predictive),
  617            ..HighlightStyle::default()
  618        },
  619        whitespace: HighlightStyle {
  620            background_color: Some(cx.theme().status().created_background),
  621            ..HighlightStyle::default()
  622        },
  623    }
  624}
  625
  626type CompletionId = usize;
  627
  628pub(crate) enum EditDisplayMode {
  629    TabAccept,
  630    DiffPopover,
  631    Inline,
  632}
  633
  634enum EditPrediction {
  635    Edit {
  636        edits: Vec<(Range<Anchor>, String)>,
  637        edit_preview: Option<EditPreview>,
  638        display_mode: EditDisplayMode,
  639        snapshot: BufferSnapshot,
  640    },
  641    /// Move to a specific location in the active editor
  642    MoveWithin {
  643        target: Anchor,
  644        snapshot: BufferSnapshot,
  645    },
  646    /// Move to a specific location in a different editor (not the active one)
  647    MoveOutside {
  648        target: language::Anchor,
  649        snapshot: BufferSnapshot,
  650    },
  651}
  652
  653struct EditPredictionState {
  654    inlay_ids: Vec<InlayId>,
  655    completion: EditPrediction,
  656    completion_id: Option<SharedString>,
  657    invalidation_range: Option<Range<Anchor>>,
  658}
  659
  660enum EditPredictionSettings {
  661    Disabled,
  662    Enabled {
  663        show_in_menu: bool,
  664        preview_requires_modifier: bool,
  665    },
  666}
  667
  668enum EditPredictionHighlight {}
  669
  670#[derive(Debug, Clone)]
  671struct InlineDiagnostic {
  672    message: SharedString,
  673    group_id: usize,
  674    is_primary: bool,
  675    start: Point,
  676    severity: lsp::DiagnosticSeverity,
  677}
  678
  679pub enum MenuEditPredictionsPolicy {
  680    Never,
  681    ByProvider,
  682}
  683
  684pub enum EditPredictionPreview {
  685    /// Modifier is not pressed
  686    Inactive { released_too_fast: bool },
  687    /// Modifier pressed
  688    Active {
  689        since: Instant,
  690        previous_scroll_position: Option<ScrollAnchor>,
  691    },
  692}
  693
  694impl EditPredictionPreview {
  695    pub fn released_too_fast(&self) -> bool {
  696        match self {
  697            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  698            EditPredictionPreview::Active { .. } => false,
  699        }
  700    }
  701
  702    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  703        if let EditPredictionPreview::Active {
  704            previous_scroll_position,
  705            ..
  706        } = self
  707        {
  708            *previous_scroll_position = scroll_position;
  709        }
  710    }
  711}
  712
  713pub struct ContextMenuOptions {
  714    pub min_entries_visible: usize,
  715    pub max_entries_visible: usize,
  716    pub placement: Option<ContextMenuPlacement>,
  717}
  718
  719#[derive(Debug, Clone, PartialEq, Eq)]
  720pub enum ContextMenuPlacement {
  721    Above,
  722    Below,
  723}
  724
  725#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  726struct EditorActionId(usize);
  727
  728impl EditorActionId {
  729    pub fn post_inc(&mut self) -> Self {
  730        let answer = self.0;
  731
  732        *self = Self(answer + 1);
  733
  734        Self(answer)
  735    }
  736}
  737
  738// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  739// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  740
  741type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  742type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  743
  744#[derive(Default)]
  745struct ScrollbarMarkerState {
  746    scrollbar_size: Size<Pixels>,
  747    dirty: bool,
  748    markers: Arc<[PaintQuad]>,
  749    pending_refresh: Option<Task<Result<()>>>,
  750}
  751
  752impl ScrollbarMarkerState {
  753    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  754        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  755    }
  756}
  757
  758#[derive(Clone, Copy, PartialEq, Eq)]
  759pub enum MinimapVisibility {
  760    Disabled,
  761    Enabled {
  762        /// The configuration currently present in the users settings.
  763        setting_configuration: bool,
  764        /// Whether to override the currently set visibility from the users setting.
  765        toggle_override: bool,
  766    },
  767}
  768
  769impl MinimapVisibility {
  770    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  771        if mode.is_full() {
  772            Self::Enabled {
  773                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  774                toggle_override: false,
  775            }
  776        } else {
  777            Self::Disabled
  778        }
  779    }
  780
  781    fn hidden(&self) -> Self {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => Self::Enabled {
  787                setting_configuration,
  788                toggle_override: setting_configuration,
  789            },
  790            Self::Disabled => Self::Disabled,
  791        }
  792    }
  793
  794    fn disabled(&self) -> bool {
  795        matches!(*self, Self::Disabled)
  796    }
  797
  798    fn settings_visibility(&self) -> bool {
  799        match *self {
  800            Self::Enabled {
  801                setting_configuration,
  802                ..
  803            } => setting_configuration,
  804            _ => false,
  805        }
  806    }
  807
  808    fn visible(&self) -> bool {
  809        match *self {
  810            Self::Enabled {
  811                setting_configuration,
  812                toggle_override,
  813            } => setting_configuration ^ toggle_override,
  814            _ => false,
  815        }
  816    }
  817
  818    fn toggle_visibility(&self) -> Self {
  819        match *self {
  820            Self::Enabled {
  821                toggle_override,
  822                setting_configuration,
  823            } => Self::Enabled {
  824                setting_configuration,
  825                toggle_override: !toggle_override,
  826            },
  827            Self::Disabled => Self::Disabled,
  828        }
  829    }
  830}
  831
  832#[derive(Clone, Debug)]
  833struct RunnableTasks {
  834    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  835    offset: multi_buffer::Anchor,
  836    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  837    column: u32,
  838    // Values of all named captures, including those starting with '_'
  839    extra_variables: HashMap<String, String>,
  840    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  841    context_range: Range<BufferOffset>,
  842}
  843
  844impl RunnableTasks {
  845    fn resolve<'a>(
  846        &'a self,
  847        cx: &'a task::TaskContext,
  848    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  849        self.templates.iter().filter_map(|(kind, template)| {
  850            template
  851                .resolve_task(&kind.to_id_base(), cx)
  852                .map(|task| (kind.clone(), task))
  853        })
  854    }
  855}
  856
  857#[derive(Clone)]
  858pub struct ResolvedTasks {
  859    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  860    position: Anchor,
  861}
  862
  863#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  864struct BufferOffset(usize);
  865
  866/// Addons allow storing per-editor state in other crates (e.g. Vim)
  867pub trait Addon: 'static {
  868    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  869
  870    fn render_buffer_header_controls(
  871        &self,
  872        _: &ExcerptInfo,
  873        _: &Window,
  874        _: &App,
  875    ) -> Option<AnyElement> {
  876        None
  877    }
  878
  879    fn to_any(&self) -> &dyn std::any::Any;
  880
  881    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  882        None
  883    }
  884}
  885
  886struct ChangeLocation {
  887    current: Option<Vec<Anchor>>,
  888    original: Vec<Anchor>,
  889}
  890impl ChangeLocation {
  891    fn locations(&self) -> &[Anchor] {
  892        self.current.as_ref().unwrap_or(&self.original)
  893    }
  894}
  895
  896/// A set of caret positions, registered when the editor was edited.
  897pub struct ChangeList {
  898    changes: Vec<ChangeLocation>,
  899    /// Currently "selected" change.
  900    position: Option<usize>,
  901}
  902
  903impl ChangeList {
  904    pub fn new() -> Self {
  905        Self {
  906            changes: Vec::new(),
  907            position: None,
  908        }
  909    }
  910
  911    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  912    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  913    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  914        if self.changes.is_empty() {
  915            return None;
  916        }
  917
  918        let prev = self.position.unwrap_or(self.changes.len());
  919        let next = if direction == Direction::Prev {
  920            prev.saturating_sub(count)
  921        } else {
  922            (prev + count).min(self.changes.len() - 1)
  923        };
  924        self.position = Some(next);
  925        self.changes.get(next).map(|change| change.locations())
  926    }
  927
  928    /// Adds a new change to the list, resetting the change list position.
  929    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  930        self.position.take();
  931        if let Some(last) = self.changes.last_mut()
  932            && group
  933        {
  934            last.current = Some(new_positions)
  935        } else {
  936            self.changes.push(ChangeLocation {
  937                original: new_positions,
  938                current: None,
  939            });
  940        }
  941    }
  942
  943    pub fn last(&self) -> Option<&[Anchor]> {
  944        self.changes.last().map(|change| change.locations())
  945    }
  946
  947    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  948        self.changes.last().map(|change| change.original.as_slice())
  949    }
  950
  951    pub fn invert_last_group(&mut self) {
  952        if let Some(last) = self.changes.last_mut()
  953            && let Some(current) = last.current.as_mut()
  954        {
  955            mem::swap(&mut last.original, current);
  956        }
  957    }
  958}
  959
  960#[derive(Clone)]
  961struct InlineBlamePopoverState {
  962    scroll_handle: ScrollHandle,
  963    commit_message: Option<ParsedCommitMessage>,
  964    markdown: Entity<Markdown>,
  965}
  966
  967struct InlineBlamePopover {
  968    position: gpui::Point<Pixels>,
  969    hide_task: Option<Task<()>>,
  970    popover_bounds: Option<Bounds<Pixels>>,
  971    popover_state: InlineBlamePopoverState,
  972    keyboard_grace: bool,
  973}
  974
  975enum SelectionDragState {
  976    /// State when no drag related activity is detected.
  977    None,
  978    /// State when the mouse is down on a selection that is about to be dragged.
  979    ReadyToDrag {
  980        selection: Selection<Anchor>,
  981        click_position: gpui::Point<Pixels>,
  982        mouse_down_time: Instant,
  983    },
  984    /// State when the mouse is dragging the selection in the editor.
  985    Dragging {
  986        selection: Selection<Anchor>,
  987        drop_cursor: Selection<Anchor>,
  988        hide_drop_cursor: bool,
  989    },
  990}
  991
  992enum ColumnarSelectionState {
  993    FromMouse {
  994        selection_tail: Anchor,
  995        display_point: Option<DisplayPoint>,
  996    },
  997    FromSelection {
  998        selection_tail: Anchor,
  999    },
 1000}
 1001
 1002/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1003/// a breakpoint on them.
 1004#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1005struct PhantomBreakpointIndicator {
 1006    display_row: DisplayRow,
 1007    /// There's a small debounce between hovering over the line and showing the indicator.
 1008    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1009    is_active: bool,
 1010    collides_with_existing_breakpoint: bool,
 1011}
 1012
 1013/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1014///
 1015/// See the [module level documentation](self) for more information.
 1016pub struct Editor {
 1017    focus_handle: FocusHandle,
 1018    last_focused_descendant: Option<WeakFocusHandle>,
 1019    /// The text buffer being edited
 1020    buffer: Entity<MultiBuffer>,
 1021    /// Map of how text in the buffer should be displayed.
 1022    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1023    pub display_map: Entity<DisplayMap>,
 1024    placeholder_display_map: Option<Entity<DisplayMap>>,
 1025    pub selections: SelectionsCollection,
 1026    pub scroll_manager: ScrollManager,
 1027    /// When inline assist editors are linked, they all render cursors because
 1028    /// typing enters text into each of them, even the ones that aren't focused.
 1029    pub(crate) show_cursor_when_unfocused: bool,
 1030    columnar_selection_state: Option<ColumnarSelectionState>,
 1031    add_selections_state: Option<AddSelectionsState>,
 1032    select_next_state: Option<SelectNextState>,
 1033    select_prev_state: Option<SelectNextState>,
 1034    selection_history: SelectionHistory,
 1035    defer_selection_effects: bool,
 1036    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1037    autoclose_regions: Vec<AutocloseRegion>,
 1038    snippet_stack: InvalidationStack<SnippetState>,
 1039    select_syntax_node_history: SelectSyntaxNodeHistory,
 1040    ime_transaction: Option<TransactionId>,
 1041    pub diagnostics_max_severity: DiagnosticSeverity,
 1042    active_diagnostics: ActiveDiagnostic,
 1043    show_inline_diagnostics: bool,
 1044    inline_diagnostics_update: Task<()>,
 1045    inline_diagnostics_enabled: bool,
 1046    diagnostics_enabled: bool,
 1047    word_completions_enabled: bool,
 1048    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1049    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1050    hard_wrap: Option<usize>,
 1051    project: Option<Entity<Project>>,
 1052    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1053    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1054    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1055    blink_manager: Entity<BlinkManager>,
 1056    show_cursor_names: bool,
 1057    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1058    pub show_local_selections: bool,
 1059    mode: EditorMode,
 1060    show_breadcrumbs: bool,
 1061    show_gutter: bool,
 1062    show_scrollbars: ScrollbarAxes,
 1063    minimap_visibility: MinimapVisibility,
 1064    offset_content: bool,
 1065    disable_expand_excerpt_buttons: bool,
 1066    show_line_numbers: Option<bool>,
 1067    use_relative_line_numbers: Option<bool>,
 1068    show_git_diff_gutter: Option<bool>,
 1069    show_code_actions: Option<bool>,
 1070    show_runnables: Option<bool>,
 1071    show_breakpoints: Option<bool>,
 1072    show_wrap_guides: Option<bool>,
 1073    show_indent_guides: Option<bool>,
 1074    highlight_order: usize,
 1075    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1076    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1077    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1078    scrollbar_marker_state: ScrollbarMarkerState,
 1079    active_indent_guides_state: ActiveIndentGuidesState,
 1080    nav_history: Option<ItemNavHistory>,
 1081    context_menu: RefCell<Option<CodeContextMenu>>,
 1082    context_menu_options: Option<ContextMenuOptions>,
 1083    mouse_context_menu: Option<MouseContextMenu>,
 1084    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1085    inline_blame_popover: Option<InlineBlamePopover>,
 1086    inline_blame_popover_show_task: Option<Task<()>>,
 1087    signature_help_state: SignatureHelpState,
 1088    auto_signature_help: Option<bool>,
 1089    find_all_references_task_sources: Vec<Anchor>,
 1090    next_completion_id: CompletionId,
 1091    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1092    code_actions_task: Option<Task<Result<()>>>,
 1093    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    document_highlights_task: Option<Task<()>>,
 1096    linked_editing_range_task: Option<Task<Option<()>>>,
 1097    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1098    pending_rename: Option<RenameState>,
 1099    searchable: bool,
 1100    cursor_shape: CursorShape,
 1101    current_line_highlight: Option<CurrentLineHighlight>,
 1102    collapse_matches: bool,
 1103    autoindent_mode: Option<AutoindentMode>,
 1104    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1105    input_enabled: bool,
 1106    use_modal_editing: bool,
 1107    read_only: bool,
 1108    leader_id: Option<CollaboratorId>,
 1109    remote_id: Option<ViewId>,
 1110    pub hover_state: HoverState,
 1111    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1112    gutter_hovered: bool,
 1113    hovered_link_state: Option<HoveredLinkState>,
 1114    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1115    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1116    active_edit_prediction: Option<EditPredictionState>,
 1117    /// Used to prevent flickering as the user types while the menu is open
 1118    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1119    edit_prediction_settings: EditPredictionSettings,
 1120    edit_predictions_hidden_for_vim_mode: bool,
 1121    show_edit_predictions_override: Option<bool>,
 1122    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1123    edit_prediction_preview: EditPredictionPreview,
 1124    edit_prediction_indent_conflict: bool,
 1125    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1126    inlay_hint_cache: InlayHintCache,
 1127    next_inlay_id: u32,
 1128    next_color_inlay_id: u32,
 1129    _subscriptions: Vec<Subscription>,
 1130    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1131    gutter_dimensions: GutterDimensions,
 1132    style: Option<EditorStyle>,
 1133    text_style_refinement: Option<TextStyleRefinement>,
 1134    next_editor_action_id: EditorActionId,
 1135    editor_actions: Rc<
 1136        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1137    >,
 1138    use_autoclose: bool,
 1139    use_auto_surround: bool,
 1140    auto_replace_emoji_shortcode: bool,
 1141    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1142    show_git_blame_gutter: bool,
 1143    show_git_blame_inline: bool,
 1144    show_git_blame_inline_delay_task: Option<Task<()>>,
 1145    git_blame_inline_enabled: bool,
 1146    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1147    serialize_dirty_buffers: bool,
 1148    show_selection_menu: Option<bool>,
 1149    blame: Option<Entity<GitBlame>>,
 1150    blame_subscription: Option<Subscription>,
 1151    custom_context_menu: Option<
 1152        Box<
 1153            dyn 'static
 1154                + Fn(
 1155                    &mut Self,
 1156                    DisplayPoint,
 1157                    &mut Window,
 1158                    &mut Context<Self>,
 1159                ) -> Option<Entity<ui::ContextMenu>>,
 1160        >,
 1161    >,
 1162    last_bounds: Option<Bounds<Pixels>>,
 1163    last_position_map: Option<Rc<PositionMap>>,
 1164    expect_bounds_change: Option<Bounds<Pixels>>,
 1165    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1166    tasks_update_task: Option<Task<()>>,
 1167    breakpoint_store: Option<Entity<BreakpointStore>>,
 1168    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1169    hovered_diff_hunk_row: Option<DisplayRow>,
 1170    pull_diagnostics_task: Task<()>,
 1171    in_project_search: bool,
 1172    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1173    breadcrumb_header: Option<String>,
 1174    focused_block: Option<FocusedBlock>,
 1175    next_scroll_position: NextScrollCursorCenterTopBottom,
 1176    addons: HashMap<TypeId, Box<dyn Addon>>,
 1177    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1178    load_diff_task: Option<Shared<Task<()>>>,
 1179    /// Whether we are temporarily displaying a diff other than git's
 1180    temporary_diff_override: bool,
 1181    selection_mark_mode: bool,
 1182    toggle_fold_multiple_buffers: Task<()>,
 1183    _scroll_cursor_center_top_bottom_task: Task<()>,
 1184    serialize_selections: Task<()>,
 1185    serialize_folds: Task<()>,
 1186    mouse_cursor_hidden: bool,
 1187    minimap: Option<Entity<Self>>,
 1188    hide_mouse_mode: HideMouseMode,
 1189    pub change_list: ChangeList,
 1190    inline_value_cache: InlineValueCache,
 1191    selection_drag_state: SelectionDragState,
 1192    colors: Option<LspColorData>,
 1193    folding_newlines: Task<()>,
 1194    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1195}
 1196
 1197#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1198enum NextScrollCursorCenterTopBottom {
 1199    #[default]
 1200    Center,
 1201    Top,
 1202    Bottom,
 1203}
 1204
 1205impl NextScrollCursorCenterTopBottom {
 1206    fn next(&self) -> Self {
 1207        match self {
 1208            Self::Center => Self::Top,
 1209            Self::Top => Self::Bottom,
 1210            Self::Bottom => Self::Center,
 1211        }
 1212    }
 1213}
 1214
 1215#[derive(Clone)]
 1216pub struct EditorSnapshot {
 1217    pub mode: EditorMode,
 1218    show_gutter: bool,
 1219    show_line_numbers: Option<bool>,
 1220    show_git_diff_gutter: Option<bool>,
 1221    show_code_actions: Option<bool>,
 1222    show_runnables: Option<bool>,
 1223    show_breakpoints: Option<bool>,
 1224    git_blame_gutter_max_author_length: Option<usize>,
 1225    pub display_snapshot: DisplaySnapshot,
 1226    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1227    is_focused: bool,
 1228    scroll_anchor: ScrollAnchor,
 1229    ongoing_scroll: OngoingScroll,
 1230    current_line_highlight: CurrentLineHighlight,
 1231    gutter_hovered: bool,
 1232}
 1233
 1234#[derive(Default, Debug, Clone, Copy)]
 1235pub struct GutterDimensions {
 1236    pub left_padding: Pixels,
 1237    pub right_padding: Pixels,
 1238    pub width: Pixels,
 1239    pub margin: Pixels,
 1240    pub git_blame_entries_width: Option<Pixels>,
 1241}
 1242
 1243impl GutterDimensions {
 1244    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1245        Self {
 1246            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1247            ..Default::default()
 1248        }
 1249    }
 1250
 1251    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1252        -cx.text_system().descent(font_id, font_size)
 1253    }
 1254    /// The full width of the space taken up by the gutter.
 1255    pub fn full_width(&self) -> Pixels {
 1256        self.margin + self.width
 1257    }
 1258
 1259    /// The width of the space reserved for the fold indicators,
 1260    /// use alongside 'justify_end' and `gutter_width` to
 1261    /// right align content with the line numbers
 1262    pub fn fold_area_width(&self) -> Pixels {
 1263        self.margin + self.right_padding
 1264    }
 1265}
 1266
 1267struct CharacterDimensions {
 1268    em_width: Pixels,
 1269    em_advance: Pixels,
 1270    line_height: Pixels,
 1271}
 1272
 1273#[derive(Debug)]
 1274pub struct RemoteSelection {
 1275    pub replica_id: ReplicaId,
 1276    pub selection: Selection<Anchor>,
 1277    pub cursor_shape: CursorShape,
 1278    pub collaborator_id: CollaboratorId,
 1279    pub line_mode: bool,
 1280    pub user_name: Option<SharedString>,
 1281    pub color: PlayerColor,
 1282}
 1283
 1284#[derive(Clone, Debug)]
 1285struct SelectionHistoryEntry {
 1286    selections: Arc<[Selection<Anchor>]>,
 1287    select_next_state: Option<SelectNextState>,
 1288    select_prev_state: Option<SelectNextState>,
 1289    add_selections_state: Option<AddSelectionsState>,
 1290}
 1291
 1292#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1293enum SelectionHistoryMode {
 1294    Normal,
 1295    Undoing,
 1296    Redoing,
 1297    Skipping,
 1298}
 1299
 1300#[derive(Clone, PartialEq, Eq, Hash)]
 1301struct HoveredCursor {
 1302    replica_id: u16,
 1303    selection_id: usize,
 1304}
 1305
 1306impl Default for SelectionHistoryMode {
 1307    fn default() -> Self {
 1308        Self::Normal
 1309    }
 1310}
 1311
 1312#[derive(Debug)]
 1313/// SelectionEffects controls the side-effects of updating the selection.
 1314///
 1315/// The default behaviour does "what you mostly want":
 1316/// - it pushes to the nav history if the cursor moved by >10 lines
 1317/// - it re-triggers completion requests
 1318/// - it scrolls to fit
 1319///
 1320/// You might want to modify these behaviours. For example when doing a "jump"
 1321/// like go to definition, we always want to add to nav history; but when scrolling
 1322/// in vim mode we never do.
 1323///
 1324/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1325/// move.
 1326#[derive(Clone)]
 1327pub struct SelectionEffects {
 1328    nav_history: Option<bool>,
 1329    completions: bool,
 1330    scroll: Option<Autoscroll>,
 1331}
 1332
 1333impl Default for SelectionEffects {
 1334    fn default() -> Self {
 1335        Self {
 1336            nav_history: None,
 1337            completions: true,
 1338            scroll: Some(Autoscroll::fit()),
 1339        }
 1340    }
 1341}
 1342impl SelectionEffects {
 1343    pub fn scroll(scroll: Autoscroll) -> Self {
 1344        Self {
 1345            scroll: Some(scroll),
 1346            ..Default::default()
 1347        }
 1348    }
 1349
 1350    pub fn no_scroll() -> Self {
 1351        Self {
 1352            scroll: None,
 1353            ..Default::default()
 1354        }
 1355    }
 1356
 1357    pub fn completions(self, completions: bool) -> Self {
 1358        Self {
 1359            completions,
 1360            ..self
 1361        }
 1362    }
 1363
 1364    pub fn nav_history(self, nav_history: bool) -> Self {
 1365        Self {
 1366            nav_history: Some(nav_history),
 1367            ..self
 1368        }
 1369    }
 1370}
 1371
 1372struct DeferredSelectionEffectsState {
 1373    changed: bool,
 1374    effects: SelectionEffects,
 1375    old_cursor_position: Anchor,
 1376    history_entry: SelectionHistoryEntry,
 1377}
 1378
 1379#[derive(Default)]
 1380struct SelectionHistory {
 1381    #[allow(clippy::type_complexity)]
 1382    selections_by_transaction:
 1383        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1384    mode: SelectionHistoryMode,
 1385    undo_stack: VecDeque<SelectionHistoryEntry>,
 1386    redo_stack: VecDeque<SelectionHistoryEntry>,
 1387}
 1388
 1389impl SelectionHistory {
 1390    #[track_caller]
 1391    fn insert_transaction(
 1392        &mut self,
 1393        transaction_id: TransactionId,
 1394        selections: Arc<[Selection<Anchor>]>,
 1395    ) {
 1396        if selections.is_empty() {
 1397            log::error!(
 1398                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1399                std::panic::Location::caller()
 1400            );
 1401            return;
 1402        }
 1403        self.selections_by_transaction
 1404            .insert(transaction_id, (selections, None));
 1405    }
 1406
 1407    #[allow(clippy::type_complexity)]
 1408    fn transaction(
 1409        &self,
 1410        transaction_id: TransactionId,
 1411    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1412        self.selections_by_transaction.get(&transaction_id)
 1413    }
 1414
 1415    #[allow(clippy::type_complexity)]
 1416    fn transaction_mut(
 1417        &mut self,
 1418        transaction_id: TransactionId,
 1419    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1420        self.selections_by_transaction.get_mut(&transaction_id)
 1421    }
 1422
 1423    fn push(&mut self, entry: SelectionHistoryEntry) {
 1424        if !entry.selections.is_empty() {
 1425            match self.mode {
 1426                SelectionHistoryMode::Normal => {
 1427                    self.push_undo(entry);
 1428                    self.redo_stack.clear();
 1429                }
 1430                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1431                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1432                SelectionHistoryMode::Skipping => {}
 1433            }
 1434        }
 1435    }
 1436
 1437    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1438        if self
 1439            .undo_stack
 1440            .back()
 1441            .is_none_or(|e| e.selections != entry.selections)
 1442        {
 1443            self.undo_stack.push_back(entry);
 1444            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1445                self.undo_stack.pop_front();
 1446            }
 1447        }
 1448    }
 1449
 1450    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1451        if self
 1452            .redo_stack
 1453            .back()
 1454            .is_none_or(|e| e.selections != entry.selections)
 1455        {
 1456            self.redo_stack.push_back(entry);
 1457            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1458                self.redo_stack.pop_front();
 1459            }
 1460        }
 1461    }
 1462}
 1463
 1464#[derive(Clone, Copy)]
 1465pub struct RowHighlightOptions {
 1466    pub autoscroll: bool,
 1467    pub include_gutter: bool,
 1468}
 1469
 1470impl Default for RowHighlightOptions {
 1471    fn default() -> Self {
 1472        Self {
 1473            autoscroll: Default::default(),
 1474            include_gutter: true,
 1475        }
 1476    }
 1477}
 1478
 1479struct RowHighlight {
 1480    index: usize,
 1481    range: Range<Anchor>,
 1482    color: Hsla,
 1483    options: RowHighlightOptions,
 1484    type_id: TypeId,
 1485}
 1486
 1487#[derive(Clone, Debug)]
 1488struct AddSelectionsState {
 1489    groups: Vec<AddSelectionsGroup>,
 1490}
 1491
 1492#[derive(Clone, Debug)]
 1493struct AddSelectionsGroup {
 1494    above: bool,
 1495    stack: Vec<usize>,
 1496}
 1497
 1498#[derive(Clone)]
 1499struct SelectNextState {
 1500    query: AhoCorasick,
 1501    wordwise: bool,
 1502    done: bool,
 1503}
 1504
 1505impl std::fmt::Debug for SelectNextState {
 1506    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1507        f.debug_struct(std::any::type_name::<Self>())
 1508            .field("wordwise", &self.wordwise)
 1509            .field("done", &self.done)
 1510            .finish()
 1511    }
 1512}
 1513
 1514#[derive(Debug)]
 1515struct AutocloseRegion {
 1516    selection_id: usize,
 1517    range: Range<Anchor>,
 1518    pair: BracketPair,
 1519}
 1520
 1521#[derive(Debug)]
 1522struct SnippetState {
 1523    ranges: Vec<Vec<Range<Anchor>>>,
 1524    active_index: usize,
 1525    choices: Vec<Option<Vec<String>>>,
 1526}
 1527
 1528#[doc(hidden)]
 1529pub struct RenameState {
 1530    pub range: Range<Anchor>,
 1531    pub old_name: Arc<str>,
 1532    pub editor: Entity<Editor>,
 1533    block_id: CustomBlockId,
 1534}
 1535
 1536struct InvalidationStack<T>(Vec<T>);
 1537
 1538struct RegisteredEditPredictionProvider {
 1539    provider: Arc<dyn EditPredictionProviderHandle>,
 1540    _subscription: Subscription,
 1541}
 1542
 1543#[derive(Debug, PartialEq, Eq)]
 1544pub struct ActiveDiagnosticGroup {
 1545    pub active_range: Range<Anchor>,
 1546    pub active_message: String,
 1547    pub group_id: usize,
 1548    pub blocks: HashSet<CustomBlockId>,
 1549}
 1550
 1551#[derive(Debug, PartialEq, Eq)]
 1552
 1553pub(crate) enum ActiveDiagnostic {
 1554    None,
 1555    All,
 1556    Group(ActiveDiagnosticGroup),
 1557}
 1558
 1559#[derive(Serialize, Deserialize, Clone, Debug)]
 1560pub struct ClipboardSelection {
 1561    /// The number of bytes in this selection.
 1562    pub len: usize,
 1563    /// Whether this was a full-line selection.
 1564    pub is_entire_line: bool,
 1565    /// The indentation of the first line when this content was originally copied.
 1566    pub first_line_indent: u32,
 1567}
 1568
 1569// selections, scroll behavior, was newest selection reversed
 1570type SelectSyntaxNodeHistoryState = (
 1571    Box<[Selection<usize>]>,
 1572    SelectSyntaxNodeScrollBehavior,
 1573    bool,
 1574);
 1575
 1576#[derive(Default)]
 1577struct SelectSyntaxNodeHistory {
 1578    stack: Vec<SelectSyntaxNodeHistoryState>,
 1579    // disable temporarily to allow changing selections without losing the stack
 1580    pub disable_clearing: bool,
 1581}
 1582
 1583impl SelectSyntaxNodeHistory {
 1584    pub fn try_clear(&mut self) {
 1585        if !self.disable_clearing {
 1586            self.stack.clear();
 1587        }
 1588    }
 1589
 1590    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1591        self.stack.push(selection);
 1592    }
 1593
 1594    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1595        self.stack.pop()
 1596    }
 1597}
 1598
 1599enum SelectSyntaxNodeScrollBehavior {
 1600    CursorTop,
 1601    FitSelection,
 1602    CursorBottom,
 1603}
 1604
 1605#[derive(Debug)]
 1606pub(crate) struct NavigationData {
 1607    cursor_anchor: Anchor,
 1608    cursor_position: Point,
 1609    scroll_anchor: ScrollAnchor,
 1610    scroll_top_row: u32,
 1611}
 1612
 1613#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1614pub enum GotoDefinitionKind {
 1615    Symbol,
 1616    Declaration,
 1617    Type,
 1618    Implementation,
 1619}
 1620
 1621#[derive(Debug, Clone)]
 1622enum InlayHintRefreshReason {
 1623    ModifiersChanged(bool),
 1624    Toggle(bool),
 1625    SettingsChange(InlayHintSettings),
 1626    NewLinesShown,
 1627    BufferEdited(HashSet<Arc<Language>>),
 1628    RefreshRequested,
 1629    ExcerptsRemoved(Vec<ExcerptId>),
 1630}
 1631
 1632impl InlayHintRefreshReason {
 1633    fn description(&self) -> &'static str {
 1634        match self {
 1635            Self::ModifiersChanged(_) => "modifiers changed",
 1636            Self::Toggle(_) => "toggle",
 1637            Self::SettingsChange(_) => "settings change",
 1638            Self::NewLinesShown => "new lines shown",
 1639            Self::BufferEdited(_) => "buffer edited",
 1640            Self::RefreshRequested => "refresh requested",
 1641            Self::ExcerptsRemoved(_) => "excerpts removed",
 1642        }
 1643    }
 1644}
 1645
 1646pub enum FormatTarget {
 1647    Buffers(HashSet<Entity<Buffer>>),
 1648    Ranges(Vec<Range<MultiBufferPoint>>),
 1649}
 1650
 1651pub(crate) struct FocusedBlock {
 1652    id: BlockId,
 1653    focus_handle: WeakFocusHandle,
 1654}
 1655
 1656#[derive(Clone)]
 1657enum JumpData {
 1658    MultiBufferRow {
 1659        row: MultiBufferRow,
 1660        line_offset_from_top: u32,
 1661    },
 1662    MultiBufferPoint {
 1663        excerpt_id: ExcerptId,
 1664        position: Point,
 1665        anchor: text::Anchor,
 1666        line_offset_from_top: u32,
 1667    },
 1668}
 1669
 1670pub enum MultibufferSelectionMode {
 1671    First,
 1672    All,
 1673}
 1674
 1675#[derive(Clone, Copy, Debug, Default)]
 1676pub struct RewrapOptions {
 1677    pub override_language_settings: bool,
 1678    pub preserve_existing_whitespace: bool,
 1679}
 1680
 1681impl Editor {
 1682    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1683        let buffer = cx.new(|cx| Buffer::local("", cx));
 1684        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1685        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1686    }
 1687
 1688    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1689        let buffer = cx.new(|cx| Buffer::local("", cx));
 1690        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1691        Self::new(EditorMode::full(), buffer, None, window, cx)
 1692    }
 1693
 1694    pub fn auto_height(
 1695        min_lines: usize,
 1696        max_lines: usize,
 1697        window: &mut Window,
 1698        cx: &mut Context<Self>,
 1699    ) -> Self {
 1700        let buffer = cx.new(|cx| Buffer::local("", cx));
 1701        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1702        Self::new(
 1703            EditorMode::AutoHeight {
 1704                min_lines,
 1705                max_lines: Some(max_lines),
 1706            },
 1707            buffer,
 1708            None,
 1709            window,
 1710            cx,
 1711        )
 1712    }
 1713
 1714    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1715    /// The editor grows as tall as needed to fit its content.
 1716    pub fn auto_height_unbounded(
 1717        min_lines: usize,
 1718        window: &mut Window,
 1719        cx: &mut Context<Self>,
 1720    ) -> Self {
 1721        let buffer = cx.new(|cx| Buffer::local("", cx));
 1722        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1723        Self::new(
 1724            EditorMode::AutoHeight {
 1725                min_lines,
 1726                max_lines: None,
 1727            },
 1728            buffer,
 1729            None,
 1730            window,
 1731            cx,
 1732        )
 1733    }
 1734
 1735    pub fn for_buffer(
 1736        buffer: Entity<Buffer>,
 1737        project: Option<Entity<Project>>,
 1738        window: &mut Window,
 1739        cx: &mut Context<Self>,
 1740    ) -> Self {
 1741        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1742        Self::new(EditorMode::full(), buffer, project, window, cx)
 1743    }
 1744
 1745    pub fn for_multibuffer(
 1746        buffer: Entity<MultiBuffer>,
 1747        project: Option<Entity<Project>>,
 1748        window: &mut Window,
 1749        cx: &mut Context<Self>,
 1750    ) -> Self {
 1751        Self::new(EditorMode::full(), buffer, project, window, cx)
 1752    }
 1753
 1754    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1755        let mut clone = Self::new(
 1756            self.mode.clone(),
 1757            self.buffer.clone(),
 1758            self.project.clone(),
 1759            window,
 1760            cx,
 1761        );
 1762        self.display_map.update(cx, |display_map, cx| {
 1763            let snapshot = display_map.snapshot(cx);
 1764            clone.display_map.update(cx, |display_map, cx| {
 1765                display_map.set_state(&snapshot, cx);
 1766            });
 1767        });
 1768        clone.folds_did_change(cx);
 1769        clone.selections.clone_state(&self.selections);
 1770        clone.scroll_manager.clone_state(&self.scroll_manager);
 1771        clone.searchable = self.searchable;
 1772        clone.read_only = self.read_only;
 1773        clone
 1774    }
 1775
 1776    pub fn new(
 1777        mode: EditorMode,
 1778        buffer: Entity<MultiBuffer>,
 1779        project: Option<Entity<Project>>,
 1780        window: &mut Window,
 1781        cx: &mut Context<Self>,
 1782    ) -> Self {
 1783        Editor::new_internal(mode, buffer, project, None, window, cx)
 1784    }
 1785
 1786    fn new_internal(
 1787        mode: EditorMode,
 1788        buffer: Entity<MultiBuffer>,
 1789        project: Option<Entity<Project>>,
 1790        display_map: Option<Entity<DisplayMap>>,
 1791        window: &mut Window,
 1792        cx: &mut Context<Self>,
 1793    ) -> Self {
 1794        debug_assert!(
 1795            display_map.is_none() || mode.is_minimap(),
 1796            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1797        );
 1798
 1799        let full_mode = mode.is_full();
 1800        let is_minimap = mode.is_minimap();
 1801        let diagnostics_max_severity = if full_mode {
 1802            EditorSettings::get_global(cx)
 1803                .diagnostics_max_severity
 1804                .unwrap_or(DiagnosticSeverity::Hint)
 1805        } else {
 1806            DiagnosticSeverity::Off
 1807        };
 1808        let style = window.text_style();
 1809        let font_size = style.font_size.to_pixels(window.rem_size());
 1810        let editor = cx.entity().downgrade();
 1811        let fold_placeholder = FoldPlaceholder {
 1812            constrain_width: false,
 1813            render: Arc::new(move |fold_id, fold_range, cx| {
 1814                let editor = editor.clone();
 1815                div()
 1816                    .id(fold_id)
 1817                    .bg(cx.theme().colors().ghost_element_background)
 1818                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1819                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1820                    .rounded_xs()
 1821                    .size_full()
 1822                    .cursor_pointer()
 1823                    .child("")
 1824                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1825                    .on_click(move |_, _window, cx| {
 1826                        editor
 1827                            .update(cx, |editor, cx| {
 1828                                editor.unfold_ranges(
 1829                                    &[fold_range.start..fold_range.end],
 1830                                    true,
 1831                                    false,
 1832                                    cx,
 1833                                );
 1834                                cx.stop_propagation();
 1835                            })
 1836                            .ok();
 1837                    })
 1838                    .into_any()
 1839            }),
 1840            merge_adjacent: true,
 1841            ..FoldPlaceholder::default()
 1842        };
 1843        let display_map = display_map.unwrap_or_else(|| {
 1844            cx.new(|cx| {
 1845                DisplayMap::new(
 1846                    buffer.clone(),
 1847                    style.font(),
 1848                    font_size,
 1849                    None,
 1850                    FILE_HEADER_HEIGHT,
 1851                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1852                    fold_placeholder,
 1853                    diagnostics_max_severity,
 1854                    cx,
 1855                )
 1856            })
 1857        });
 1858
 1859        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1860
 1861        let blink_manager = cx.new(|cx| {
 1862            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1863            if is_minimap {
 1864                blink_manager.disable(cx);
 1865            }
 1866            blink_manager
 1867        });
 1868
 1869        let soft_wrap_mode_override =
 1870            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1871
 1872        let mut project_subscriptions = Vec::new();
 1873        if full_mode && let Some(project) = project.as_ref() {
 1874            project_subscriptions.push(cx.subscribe_in(
 1875                project,
 1876                window,
 1877                |editor, _, event, window, cx| match event {
 1878                    project::Event::RefreshCodeLens => {
 1879                        // we always query lens with actions, without storing them, always refreshing them
 1880                    }
 1881                    project::Event::RefreshInlayHints => {
 1882                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1883                    }
 1884                    project::Event::LanguageServerAdded(..)
 1885                    | project::Event::LanguageServerRemoved(..) => {
 1886                        if editor.tasks_update_task.is_none() {
 1887                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1888                        }
 1889                    }
 1890                    project::Event::SnippetEdit(id, snippet_edits) => {
 1891                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1892                            let focus_handle = editor.focus_handle(cx);
 1893                            if focus_handle.is_focused(window) {
 1894                                let snapshot = buffer.read(cx).snapshot();
 1895                                for (range, snippet) in snippet_edits {
 1896                                    let editor_range =
 1897                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1898                                    editor
 1899                                        .insert_snippet(
 1900                                            &[editor_range],
 1901                                            snippet.clone(),
 1902                                            window,
 1903                                            cx,
 1904                                        )
 1905                                        .ok();
 1906                                }
 1907                            }
 1908                        }
 1909                    }
 1910                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1911                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1912                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1913                        }
 1914                    }
 1915
 1916                    project::Event::EntryRenamed(transaction) => {
 1917                        let Some(workspace) = editor.workspace() else {
 1918                            return;
 1919                        };
 1920                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1921                        else {
 1922                            return;
 1923                        };
 1924                        if active_editor.entity_id() == cx.entity_id() {
 1925                            let edited_buffers_already_open = {
 1926                                let other_editors: Vec<Entity<Editor>> = workspace
 1927                                    .read(cx)
 1928                                    .panes()
 1929                                    .iter()
 1930                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1931                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1932                                    .collect();
 1933
 1934                                transaction.0.keys().all(|buffer| {
 1935                                    other_editors.iter().any(|editor| {
 1936                                        let multi_buffer = editor.read(cx).buffer();
 1937                                        multi_buffer.read(cx).is_singleton()
 1938                                            && multi_buffer.read(cx).as_singleton().map_or(
 1939                                                false,
 1940                                                |singleton| {
 1941                                                    singleton.entity_id() == buffer.entity_id()
 1942                                                },
 1943                                            )
 1944                                    })
 1945                                })
 1946                            };
 1947
 1948                            if !edited_buffers_already_open {
 1949                                let workspace = workspace.downgrade();
 1950                                let transaction = transaction.clone();
 1951                                cx.defer_in(window, move |_, window, cx| {
 1952                                    cx.spawn_in(window, async move |editor, cx| {
 1953                                        Self::open_project_transaction(
 1954                                            &editor,
 1955                                            workspace,
 1956                                            transaction,
 1957                                            "Rename".to_string(),
 1958                                            cx,
 1959                                        )
 1960                                        .await
 1961                                        .ok()
 1962                                    })
 1963                                    .detach();
 1964                                });
 1965                            }
 1966                        }
 1967                    }
 1968
 1969                    _ => {}
 1970                },
 1971            ));
 1972            if let Some(task_inventory) = project
 1973                .read(cx)
 1974                .task_store()
 1975                .read(cx)
 1976                .task_inventory()
 1977                .cloned()
 1978            {
 1979                project_subscriptions.push(cx.observe_in(
 1980                    &task_inventory,
 1981                    window,
 1982                    |editor, _, window, cx| {
 1983                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1984                    },
 1985                ));
 1986            };
 1987
 1988            project_subscriptions.push(cx.subscribe_in(
 1989                &project.read(cx).breakpoint_store(),
 1990                window,
 1991                |editor, _, event, window, cx| match event {
 1992                    BreakpointStoreEvent::ClearDebugLines => {
 1993                        editor.clear_row_highlights::<ActiveDebugLine>();
 1994                        editor.refresh_inline_values(cx);
 1995                    }
 1996                    BreakpointStoreEvent::SetDebugLine => {
 1997                        if editor.go_to_active_debug_line(window, cx) {
 1998                            cx.stop_propagation();
 1999                        }
 2000
 2001                        editor.refresh_inline_values(cx);
 2002                    }
 2003                    _ => {}
 2004                },
 2005            ));
 2006            let git_store = project.read(cx).git_store().clone();
 2007            let project = project.clone();
 2008            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2009                if let GitStoreEvent::RepositoryUpdated(
 2010                    _,
 2011                    RepositoryEvent::Updated {
 2012                        new_instance: true, ..
 2013                    },
 2014                    _,
 2015                ) = event
 2016                {
 2017                    this.load_diff_task = Some(
 2018                        update_uncommitted_diff_for_buffer(
 2019                            cx.entity(),
 2020                            &project,
 2021                            this.buffer.read(cx).all_buffers(),
 2022                            this.buffer.clone(),
 2023                            cx,
 2024                        )
 2025                        .shared(),
 2026                    );
 2027                }
 2028            }));
 2029        }
 2030
 2031        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2032
 2033        let inlay_hint_settings =
 2034            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2035        let focus_handle = cx.focus_handle();
 2036        if !is_minimap {
 2037            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2038                .detach();
 2039            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2040                .detach();
 2041            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2042                .detach();
 2043            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2044                .detach();
 2045            cx.observe_pending_input(window, Self::observe_pending_input)
 2046                .detach();
 2047        }
 2048
 2049        let show_indent_guides =
 2050            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2051                Some(false)
 2052            } else {
 2053                None
 2054            };
 2055
 2056        let breakpoint_store = match (&mode, project.as_ref()) {
 2057            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2058            _ => None,
 2059        };
 2060
 2061        let mut code_action_providers = Vec::new();
 2062        let mut load_uncommitted_diff = None;
 2063        if let Some(project) = project.clone() {
 2064            load_uncommitted_diff = Some(
 2065                update_uncommitted_diff_for_buffer(
 2066                    cx.entity(),
 2067                    &project,
 2068                    buffer.read(cx).all_buffers(),
 2069                    buffer.clone(),
 2070                    cx,
 2071                )
 2072                .shared(),
 2073            );
 2074            code_action_providers.push(Rc::new(project) as Rc<_>);
 2075        }
 2076
 2077        let mut editor = Self {
 2078            focus_handle,
 2079            show_cursor_when_unfocused: false,
 2080            last_focused_descendant: None,
 2081            buffer: buffer.clone(),
 2082            display_map: display_map.clone(),
 2083            placeholder_display_map: None,
 2084            selections,
 2085            scroll_manager: ScrollManager::new(cx),
 2086            columnar_selection_state: None,
 2087            add_selections_state: None,
 2088            select_next_state: None,
 2089            select_prev_state: None,
 2090            selection_history: SelectionHistory::default(),
 2091            defer_selection_effects: false,
 2092            deferred_selection_effects_state: None,
 2093            autoclose_regions: Vec::new(),
 2094            snippet_stack: InvalidationStack::default(),
 2095            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2096            ime_transaction: None,
 2097            active_diagnostics: ActiveDiagnostic::None,
 2098            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2099            inline_diagnostics_update: Task::ready(()),
 2100            inline_diagnostics: Vec::new(),
 2101            soft_wrap_mode_override,
 2102            diagnostics_max_severity,
 2103            hard_wrap: None,
 2104            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2105            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2106            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2107            project,
 2108            blink_manager: blink_manager.clone(),
 2109            show_local_selections: true,
 2110            show_scrollbars: ScrollbarAxes {
 2111                horizontal: full_mode,
 2112                vertical: full_mode,
 2113            },
 2114            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2115            offset_content: !matches!(mode, EditorMode::SingleLine),
 2116            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2117            show_gutter: full_mode,
 2118            show_line_numbers: (!full_mode).then_some(false),
 2119            use_relative_line_numbers: None,
 2120            disable_expand_excerpt_buttons: !full_mode,
 2121            show_git_diff_gutter: None,
 2122            show_code_actions: None,
 2123            show_runnables: None,
 2124            show_breakpoints: None,
 2125            show_wrap_guides: None,
 2126            show_indent_guides,
 2127            highlight_order: 0,
 2128            highlighted_rows: HashMap::default(),
 2129            background_highlights: HashMap::default(),
 2130            gutter_highlights: HashMap::default(),
 2131            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2132            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2133            nav_history: None,
 2134            context_menu: RefCell::new(None),
 2135            context_menu_options: None,
 2136            mouse_context_menu: None,
 2137            completion_tasks: Vec::new(),
 2138            inline_blame_popover: None,
 2139            inline_blame_popover_show_task: None,
 2140            signature_help_state: SignatureHelpState::default(),
 2141            auto_signature_help: None,
 2142            find_all_references_task_sources: Vec::new(),
 2143            next_completion_id: 0,
 2144            next_inlay_id: 0,
 2145            code_action_providers,
 2146            available_code_actions: None,
 2147            code_actions_task: None,
 2148            quick_selection_highlight_task: None,
 2149            debounced_selection_highlight_task: None,
 2150            document_highlights_task: None,
 2151            linked_editing_range_task: None,
 2152            pending_rename: None,
 2153            searchable: !is_minimap,
 2154            cursor_shape: EditorSettings::get_global(cx)
 2155                .cursor_shape
 2156                .unwrap_or_default(),
 2157            current_line_highlight: None,
 2158            autoindent_mode: Some(AutoindentMode::EachLine),
 2159            collapse_matches: false,
 2160            workspace: None,
 2161            input_enabled: !is_minimap,
 2162            use_modal_editing: full_mode,
 2163            read_only: is_minimap,
 2164            use_autoclose: true,
 2165            use_auto_surround: true,
 2166            auto_replace_emoji_shortcode: false,
 2167            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2168            leader_id: None,
 2169            remote_id: None,
 2170            hover_state: HoverState::default(),
 2171            pending_mouse_down: None,
 2172            hovered_link_state: None,
 2173            edit_prediction_provider: None,
 2174            active_edit_prediction: None,
 2175            stale_edit_prediction_in_menu: None,
 2176            edit_prediction_preview: EditPredictionPreview::Inactive {
 2177                released_too_fast: false,
 2178            },
 2179            inline_diagnostics_enabled: full_mode,
 2180            diagnostics_enabled: full_mode,
 2181            word_completions_enabled: full_mode,
 2182            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2183            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2184            gutter_hovered: false,
 2185            pixel_position_of_newest_cursor: None,
 2186            last_bounds: None,
 2187            last_position_map: None,
 2188            expect_bounds_change: None,
 2189            gutter_dimensions: GutterDimensions::default(),
 2190            style: None,
 2191            show_cursor_names: false,
 2192            hovered_cursors: HashMap::default(),
 2193            next_editor_action_id: EditorActionId::default(),
 2194            editor_actions: Rc::default(),
 2195            edit_predictions_hidden_for_vim_mode: false,
 2196            show_edit_predictions_override: None,
 2197            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2198            edit_prediction_settings: EditPredictionSettings::Disabled,
 2199            edit_prediction_indent_conflict: false,
 2200            edit_prediction_requires_modifier_in_indent_conflict: true,
 2201            custom_context_menu: None,
 2202            show_git_blame_gutter: false,
 2203            show_git_blame_inline: false,
 2204            show_selection_menu: None,
 2205            show_git_blame_inline_delay_task: None,
 2206            git_blame_inline_enabled: full_mode
 2207                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2208            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2209            serialize_dirty_buffers: !is_minimap
 2210                && ProjectSettings::get_global(cx)
 2211                    .session
 2212                    .restore_unsaved_buffers,
 2213            blame: None,
 2214            blame_subscription: None,
 2215            tasks: BTreeMap::default(),
 2216
 2217            breakpoint_store,
 2218            gutter_breakpoint_indicator: (None, None),
 2219            hovered_diff_hunk_row: None,
 2220            _subscriptions: (!is_minimap)
 2221                .then(|| {
 2222                    vec![
 2223                        cx.observe(&buffer, Self::on_buffer_changed),
 2224                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2225                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2226                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2227                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2228                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2229                        cx.observe_window_activation(window, |editor, window, cx| {
 2230                            let active = window.is_window_active();
 2231                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2232                                if active {
 2233                                    blink_manager.enable(cx);
 2234                                } else {
 2235                                    blink_manager.disable(cx);
 2236                                }
 2237                            });
 2238                            if active {
 2239                                editor.show_mouse_cursor(cx);
 2240                            }
 2241                        }),
 2242                    ]
 2243                })
 2244                .unwrap_or_default(),
 2245            tasks_update_task: None,
 2246            pull_diagnostics_task: Task::ready(()),
 2247            colors: None,
 2248            next_color_inlay_id: 0,
 2249            linked_edit_ranges: Default::default(),
 2250            in_project_search: false,
 2251            previous_search_ranges: None,
 2252            breadcrumb_header: None,
 2253            focused_block: None,
 2254            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2255            addons: HashMap::default(),
 2256            registered_buffers: HashMap::default(),
 2257            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2258            selection_mark_mode: false,
 2259            toggle_fold_multiple_buffers: Task::ready(()),
 2260            serialize_selections: Task::ready(()),
 2261            serialize_folds: Task::ready(()),
 2262            text_style_refinement: None,
 2263            load_diff_task: load_uncommitted_diff,
 2264            temporary_diff_override: false,
 2265            mouse_cursor_hidden: false,
 2266            minimap: None,
 2267            hide_mouse_mode: EditorSettings::get_global(cx)
 2268                .hide_mouse
 2269                .unwrap_or_default(),
 2270            change_list: ChangeList::new(),
 2271            mode,
 2272            selection_drag_state: SelectionDragState::None,
 2273            folding_newlines: Task::ready(()),
 2274            lookup_key: None,
 2275        };
 2276
 2277        if is_minimap {
 2278            return editor;
 2279        }
 2280
 2281        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2282            editor
 2283                ._subscriptions
 2284                .push(cx.observe(breakpoints, |_, _, cx| {
 2285                    cx.notify();
 2286                }));
 2287        }
 2288        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2289        editor._subscriptions.extend(project_subscriptions);
 2290
 2291        editor._subscriptions.push(cx.subscribe_in(
 2292            &cx.entity(),
 2293            window,
 2294            |editor, _, e: &EditorEvent, window, cx| match e {
 2295                EditorEvent::ScrollPositionChanged { local, .. } => {
 2296                    if *local {
 2297                        let new_anchor = editor.scroll_manager.anchor();
 2298                        let snapshot = editor.snapshot(window, cx);
 2299                        editor.update_restoration_data(cx, move |data| {
 2300                            data.scroll_position = (
 2301                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2302                                new_anchor.offset,
 2303                            );
 2304                        });
 2305                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2306                        editor.inline_blame_popover.take();
 2307                    }
 2308                }
 2309                EditorEvent::Edited { .. } => {
 2310                    if !vim_enabled(cx) {
 2311                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2312                        let pop_state = editor
 2313                            .change_list
 2314                            .last()
 2315                            .map(|previous| {
 2316                                previous.len() == selections.len()
 2317                                    && previous.iter().enumerate().all(|(ix, p)| {
 2318                                        p.to_display_point(&map).row()
 2319                                            == selections[ix].head().row()
 2320                                    })
 2321                            })
 2322                            .unwrap_or(false);
 2323                        let new_positions = selections
 2324                            .into_iter()
 2325                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2326                            .collect();
 2327                        editor
 2328                            .change_list
 2329                            .push_to_change_list(pop_state, new_positions);
 2330                    }
 2331                }
 2332                _ => (),
 2333            },
 2334        ));
 2335
 2336        if let Some(dap_store) = editor
 2337            .project
 2338            .as_ref()
 2339            .map(|project| project.read(cx).dap_store())
 2340        {
 2341            let weak_editor = cx.weak_entity();
 2342
 2343            editor
 2344                ._subscriptions
 2345                .push(
 2346                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2347                        let session_entity = cx.entity();
 2348                        weak_editor
 2349                            .update(cx, |editor, cx| {
 2350                                editor._subscriptions.push(
 2351                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2352                                );
 2353                            })
 2354                            .ok();
 2355                    }),
 2356                );
 2357
 2358            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2359                editor
 2360                    ._subscriptions
 2361                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2362            }
 2363        }
 2364
 2365        // skip adding the initial selection to selection history
 2366        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2367        editor.end_selection(window, cx);
 2368        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2369
 2370        editor.scroll_manager.show_scrollbars(window, cx);
 2371        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2372
 2373        if full_mode {
 2374            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2375            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2376
 2377            if editor.git_blame_inline_enabled {
 2378                editor.start_git_blame_inline(false, window, cx);
 2379            }
 2380
 2381            editor.go_to_active_debug_line(window, cx);
 2382
 2383            if let Some(buffer) = buffer.read(cx).as_singleton()
 2384                && let Some(project) = editor.project()
 2385            {
 2386                let handle = project.update(cx, |project, cx| {
 2387                    project.register_buffer_with_language_servers(&buffer, cx)
 2388                });
 2389                editor
 2390                    .registered_buffers
 2391                    .insert(buffer.read(cx).remote_id(), handle);
 2392            }
 2393
 2394            editor.minimap =
 2395                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2396            editor.colors = Some(LspColorData::new(cx));
 2397            editor.update_lsp_data(false, None, window, cx);
 2398        }
 2399
 2400        if editor.mode.is_full() {
 2401            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2402        }
 2403
 2404        editor
 2405    }
 2406
 2407    pub fn deploy_mouse_context_menu(
 2408        &mut self,
 2409        position: gpui::Point<Pixels>,
 2410        context_menu: Entity<ContextMenu>,
 2411        window: &mut Window,
 2412        cx: &mut Context<Self>,
 2413    ) {
 2414        self.mouse_context_menu = Some(MouseContextMenu::new(
 2415            self,
 2416            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2417            context_menu,
 2418            window,
 2419            cx,
 2420        ));
 2421    }
 2422
 2423    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2424        self.mouse_context_menu
 2425            .as_ref()
 2426            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2427    }
 2428
 2429    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2430        if self
 2431            .selections
 2432            .pending_anchor()
 2433            .is_some_and(|pending_selection| {
 2434                let snapshot = self.buffer().read(cx).snapshot(cx);
 2435                pending_selection.range().includes(range, &snapshot)
 2436            })
 2437        {
 2438            return true;
 2439        }
 2440
 2441        self.selections
 2442            .disjoint_in_range::<usize>(range.clone(), cx)
 2443            .into_iter()
 2444            .any(|selection| {
 2445                // This is needed to cover a corner case, if we just check for an existing
 2446                // selection in the fold range, having a cursor at the start of the fold
 2447                // marks it as selected. Non-empty selections don't cause this.
 2448                let length = selection.end - selection.start;
 2449                length > 0
 2450            })
 2451    }
 2452
 2453    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2454        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2455    }
 2456
 2457    fn key_context_internal(
 2458        &self,
 2459        has_active_edit_prediction: bool,
 2460        window: &Window,
 2461        cx: &App,
 2462    ) -> KeyContext {
 2463        let mut key_context = KeyContext::new_with_defaults();
 2464        key_context.add("Editor");
 2465        let mode = match self.mode {
 2466            EditorMode::SingleLine => "single_line",
 2467            EditorMode::AutoHeight { .. } => "auto_height",
 2468            EditorMode::Minimap { .. } => "minimap",
 2469            EditorMode::Full { .. } => "full",
 2470        };
 2471
 2472        if EditorSettings::jupyter_enabled(cx) {
 2473            key_context.add("jupyter");
 2474        }
 2475
 2476        key_context.set("mode", mode);
 2477        if self.pending_rename.is_some() {
 2478            key_context.add("renaming");
 2479        }
 2480
 2481        match self.context_menu.borrow().as_ref() {
 2482            Some(CodeContextMenu::Completions(menu)) => {
 2483                if menu.visible() {
 2484                    key_context.add("menu");
 2485                    key_context.add("showing_completions");
 2486                }
 2487            }
 2488            Some(CodeContextMenu::CodeActions(menu)) => {
 2489                if menu.visible() {
 2490                    key_context.add("menu");
 2491                    key_context.add("showing_code_actions")
 2492                }
 2493            }
 2494            None => {}
 2495        }
 2496
 2497        if self.signature_help_state.has_multiple_signatures() {
 2498            key_context.add("showing_signature_help");
 2499        }
 2500
 2501        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2502        if !self.focus_handle(cx).contains_focused(window, cx)
 2503            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2504        {
 2505            for addon in self.addons.values() {
 2506                addon.extend_key_context(&mut key_context, cx)
 2507            }
 2508        }
 2509
 2510        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2511            if let Some(extension) = singleton_buffer
 2512                .read(cx)
 2513                .file()
 2514                .and_then(|file| file.path().extension())
 2515            {
 2516                key_context.set("extension", extension.to_string());
 2517            }
 2518        } else {
 2519            key_context.add("multibuffer");
 2520        }
 2521
 2522        if has_active_edit_prediction {
 2523            if self.edit_prediction_in_conflict() {
 2524                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2525            } else {
 2526                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2527                key_context.add("copilot_suggestion");
 2528            }
 2529        }
 2530
 2531        if self.selection_mark_mode {
 2532            key_context.add("selection_mode");
 2533        }
 2534
 2535        key_context
 2536    }
 2537
 2538    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2539        self.last_bounds.as_ref()
 2540    }
 2541
 2542    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2543        if self.mouse_cursor_hidden {
 2544            self.mouse_cursor_hidden = false;
 2545            cx.notify();
 2546        }
 2547    }
 2548
 2549    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2550        let hide_mouse_cursor = match origin {
 2551            HideMouseCursorOrigin::TypingAction => {
 2552                matches!(
 2553                    self.hide_mouse_mode,
 2554                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2555                )
 2556            }
 2557            HideMouseCursorOrigin::MovementAction => {
 2558                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2559            }
 2560        };
 2561        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2562            self.mouse_cursor_hidden = hide_mouse_cursor;
 2563            cx.notify();
 2564        }
 2565    }
 2566
 2567    pub fn edit_prediction_in_conflict(&self) -> bool {
 2568        if !self.show_edit_predictions_in_menu() {
 2569            return false;
 2570        }
 2571
 2572        let showing_completions = self
 2573            .context_menu
 2574            .borrow()
 2575            .as_ref()
 2576            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2577
 2578        showing_completions
 2579            || self.edit_prediction_requires_modifier()
 2580            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2581            // bindings to insert tab characters.
 2582            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2583    }
 2584
 2585    pub fn accept_edit_prediction_keybind(
 2586        &self,
 2587        accept_partial: bool,
 2588        window: &Window,
 2589        cx: &App,
 2590    ) -> AcceptEditPredictionBinding {
 2591        let key_context = self.key_context_internal(true, window, cx);
 2592        let in_conflict = self.edit_prediction_in_conflict();
 2593
 2594        let bindings = if accept_partial {
 2595            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2596        } else {
 2597            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2598        };
 2599
 2600        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2601        // just the first one.
 2602        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2603            !in_conflict
 2604                || binding
 2605                    .keystrokes()
 2606                    .first()
 2607                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2608        }))
 2609    }
 2610
 2611    pub fn new_file(
 2612        workspace: &mut Workspace,
 2613        _: &workspace::NewFile,
 2614        window: &mut Window,
 2615        cx: &mut Context<Workspace>,
 2616    ) {
 2617        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2618            "Failed to create buffer",
 2619            window,
 2620            cx,
 2621            |e, _, _| match e.error_code() {
 2622                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2623                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2624                e.error_tag("required").unwrap_or("the latest version")
 2625            )),
 2626                _ => None,
 2627            },
 2628        );
 2629    }
 2630
 2631    pub fn new_in_workspace(
 2632        workspace: &mut Workspace,
 2633        window: &mut Window,
 2634        cx: &mut Context<Workspace>,
 2635    ) -> Task<Result<Entity<Editor>>> {
 2636        let project = workspace.project().clone();
 2637        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2638
 2639        cx.spawn_in(window, async move |workspace, cx| {
 2640            let buffer = create.await?;
 2641            workspace.update_in(cx, |workspace, window, cx| {
 2642                let editor =
 2643                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2644                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2645                editor
 2646            })
 2647        })
 2648    }
 2649
 2650    fn new_file_vertical(
 2651        workspace: &mut Workspace,
 2652        _: &workspace::NewFileSplitVertical,
 2653        window: &mut Window,
 2654        cx: &mut Context<Workspace>,
 2655    ) {
 2656        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2657    }
 2658
 2659    fn new_file_horizontal(
 2660        workspace: &mut Workspace,
 2661        _: &workspace::NewFileSplitHorizontal,
 2662        window: &mut Window,
 2663        cx: &mut Context<Workspace>,
 2664    ) {
 2665        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2666    }
 2667
 2668    fn new_file_in_direction(
 2669        workspace: &mut Workspace,
 2670        direction: SplitDirection,
 2671        window: &mut Window,
 2672        cx: &mut Context<Workspace>,
 2673    ) {
 2674        let project = workspace.project().clone();
 2675        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2676
 2677        cx.spawn_in(window, async move |workspace, cx| {
 2678            let buffer = create.await?;
 2679            workspace.update_in(cx, move |workspace, window, cx| {
 2680                workspace.split_item(
 2681                    direction,
 2682                    Box::new(
 2683                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2684                    ),
 2685                    window,
 2686                    cx,
 2687                )
 2688            })?;
 2689            anyhow::Ok(())
 2690        })
 2691        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2692            match e.error_code() {
 2693                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2694                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2695                e.error_tag("required").unwrap_or("the latest version")
 2696            )),
 2697                _ => None,
 2698            }
 2699        });
 2700    }
 2701
 2702    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2703        self.leader_id
 2704    }
 2705
 2706    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2707        &self.buffer
 2708    }
 2709
 2710    pub fn project(&self) -> Option<&Entity<Project>> {
 2711        self.project.as_ref()
 2712    }
 2713
 2714    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2715        self.workspace.as_ref()?.0.upgrade()
 2716    }
 2717
 2718    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2719        self.buffer().read(cx).title(cx)
 2720    }
 2721
 2722    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2723        let git_blame_gutter_max_author_length = self
 2724            .render_git_blame_gutter(cx)
 2725            .then(|| {
 2726                if let Some(blame) = self.blame.as_ref() {
 2727                    let max_author_length =
 2728                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2729                    Some(max_author_length)
 2730                } else {
 2731                    None
 2732                }
 2733            })
 2734            .flatten();
 2735
 2736        EditorSnapshot {
 2737            mode: self.mode.clone(),
 2738            show_gutter: self.show_gutter,
 2739            show_line_numbers: self.show_line_numbers,
 2740            show_git_diff_gutter: self.show_git_diff_gutter,
 2741            show_code_actions: self.show_code_actions,
 2742            show_runnables: self.show_runnables,
 2743            show_breakpoints: self.show_breakpoints,
 2744            git_blame_gutter_max_author_length,
 2745            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2746            placeholder_display_snapshot: self
 2747                .placeholder_display_map
 2748                .as_ref()
 2749                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2750            scroll_anchor: self.scroll_manager.anchor(),
 2751            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2752            is_focused: self.focus_handle.is_focused(window),
 2753            current_line_highlight: self
 2754                .current_line_highlight
 2755                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2756            gutter_hovered: self.gutter_hovered,
 2757        }
 2758    }
 2759
 2760    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2761        self.buffer.read(cx).language_at(point, cx)
 2762    }
 2763
 2764    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2765        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2766    }
 2767
 2768    pub fn active_excerpt(
 2769        &self,
 2770        cx: &App,
 2771    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2772        self.buffer
 2773            .read(cx)
 2774            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2775    }
 2776
 2777    pub fn mode(&self) -> &EditorMode {
 2778        &self.mode
 2779    }
 2780
 2781    pub fn set_mode(&mut self, mode: EditorMode) {
 2782        self.mode = mode;
 2783    }
 2784
 2785    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2786        self.collaboration_hub.as_deref()
 2787    }
 2788
 2789    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2790        self.collaboration_hub = Some(hub);
 2791    }
 2792
 2793    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2794        self.in_project_search = in_project_search;
 2795    }
 2796
 2797    pub fn set_custom_context_menu(
 2798        &mut self,
 2799        f: impl 'static
 2800        + Fn(
 2801            &mut Self,
 2802            DisplayPoint,
 2803            &mut Window,
 2804            &mut Context<Self>,
 2805        ) -> Option<Entity<ui::ContextMenu>>,
 2806    ) {
 2807        self.custom_context_menu = Some(Box::new(f))
 2808    }
 2809
 2810    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2811        self.completion_provider = provider;
 2812    }
 2813
 2814    #[cfg(any(test, feature = "test-support"))]
 2815    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2816        self.completion_provider.clone()
 2817    }
 2818
 2819    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2820        self.semantics_provider.clone()
 2821    }
 2822
 2823    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2824        self.semantics_provider = provider;
 2825    }
 2826
 2827    pub fn set_edit_prediction_provider<T>(
 2828        &mut self,
 2829        provider: Option<Entity<T>>,
 2830        window: &mut Window,
 2831        cx: &mut Context<Self>,
 2832    ) where
 2833        T: EditPredictionProvider,
 2834    {
 2835        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2836            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2837                if this.focus_handle.is_focused(window) {
 2838                    this.update_visible_edit_prediction(window, cx);
 2839                }
 2840            }),
 2841            provider: Arc::new(provider),
 2842        });
 2843        self.update_edit_prediction_settings(cx);
 2844        self.refresh_edit_prediction(false, false, window, cx);
 2845    }
 2846
 2847    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2848        self.placeholder_display_map
 2849            .as_ref()
 2850            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2851    }
 2852
 2853    pub fn set_placeholder_text(
 2854        &mut self,
 2855        placeholder_text: &str,
 2856        window: &mut Window,
 2857        cx: &mut Context<Self>,
 2858    ) {
 2859        let multibuffer = cx
 2860            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2861
 2862        let style = window.text_style();
 2863
 2864        self.placeholder_display_map = Some(cx.new(|cx| {
 2865            DisplayMap::new(
 2866                multibuffer,
 2867                style.font(),
 2868                style.font_size.to_pixels(window.rem_size()),
 2869                None,
 2870                FILE_HEADER_HEIGHT,
 2871                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2872                Default::default(),
 2873                DiagnosticSeverity::Off,
 2874                cx,
 2875            )
 2876        }));
 2877        cx.notify();
 2878    }
 2879
 2880    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2881        self.cursor_shape = cursor_shape;
 2882
 2883        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2884        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2885
 2886        cx.notify();
 2887    }
 2888
 2889    pub fn set_current_line_highlight(
 2890        &mut self,
 2891        current_line_highlight: Option<CurrentLineHighlight>,
 2892    ) {
 2893        self.current_line_highlight = current_line_highlight;
 2894    }
 2895
 2896    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2897        self.collapse_matches = collapse_matches;
 2898    }
 2899
 2900    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2901        let buffers = self.buffer.read(cx).all_buffers();
 2902        let Some(project) = self.project.as_ref() else {
 2903            return;
 2904        };
 2905        project.update(cx, |project, cx| {
 2906            for buffer in buffers {
 2907                self.registered_buffers
 2908                    .entry(buffer.read(cx).remote_id())
 2909                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2910            }
 2911        })
 2912    }
 2913
 2914    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2915        if self.collapse_matches {
 2916            return range.start..range.start;
 2917        }
 2918        range.clone()
 2919    }
 2920
 2921    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2922        if self.display_map.read(cx).clip_at_line_ends != clip {
 2923            self.display_map
 2924                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2925        }
 2926    }
 2927
 2928    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2929        self.input_enabled = input_enabled;
 2930    }
 2931
 2932    pub fn set_edit_predictions_hidden_for_vim_mode(
 2933        &mut self,
 2934        hidden: bool,
 2935        window: &mut Window,
 2936        cx: &mut Context<Self>,
 2937    ) {
 2938        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2939            self.edit_predictions_hidden_for_vim_mode = hidden;
 2940            if hidden {
 2941                self.update_visible_edit_prediction(window, cx);
 2942            } else {
 2943                self.refresh_edit_prediction(true, false, window, cx);
 2944            }
 2945        }
 2946    }
 2947
 2948    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2949        self.menu_edit_predictions_policy = value;
 2950    }
 2951
 2952    pub fn set_autoindent(&mut self, autoindent: bool) {
 2953        if autoindent {
 2954            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2955        } else {
 2956            self.autoindent_mode = None;
 2957        }
 2958    }
 2959
 2960    pub fn read_only(&self, cx: &App) -> bool {
 2961        self.read_only || self.buffer.read(cx).read_only()
 2962    }
 2963
 2964    pub fn set_read_only(&mut self, read_only: bool) {
 2965        self.read_only = read_only;
 2966    }
 2967
 2968    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2969        self.use_autoclose = autoclose;
 2970    }
 2971
 2972    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2973        self.use_auto_surround = auto_surround;
 2974    }
 2975
 2976    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2977        self.auto_replace_emoji_shortcode = auto_replace;
 2978    }
 2979
 2980    pub fn toggle_edit_predictions(
 2981        &mut self,
 2982        _: &ToggleEditPrediction,
 2983        window: &mut Window,
 2984        cx: &mut Context<Self>,
 2985    ) {
 2986        if self.show_edit_predictions_override.is_some() {
 2987            self.set_show_edit_predictions(None, window, cx);
 2988        } else {
 2989            let show_edit_predictions = !self.edit_predictions_enabled();
 2990            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2991        }
 2992    }
 2993
 2994    pub fn set_show_edit_predictions(
 2995        &mut self,
 2996        show_edit_predictions: Option<bool>,
 2997        window: &mut Window,
 2998        cx: &mut Context<Self>,
 2999    ) {
 3000        self.show_edit_predictions_override = show_edit_predictions;
 3001        self.update_edit_prediction_settings(cx);
 3002
 3003        if let Some(false) = show_edit_predictions {
 3004            self.discard_edit_prediction(false, cx);
 3005        } else {
 3006            self.refresh_edit_prediction(false, true, window, cx);
 3007        }
 3008    }
 3009
 3010    fn edit_predictions_disabled_in_scope(
 3011        &self,
 3012        buffer: &Entity<Buffer>,
 3013        buffer_position: language::Anchor,
 3014        cx: &App,
 3015    ) -> bool {
 3016        let snapshot = buffer.read(cx).snapshot();
 3017        let settings = snapshot.settings_at(buffer_position, cx);
 3018
 3019        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3020            return false;
 3021        };
 3022
 3023        scope.override_name().is_some_and(|scope_name| {
 3024            settings
 3025                .edit_predictions_disabled_in
 3026                .iter()
 3027                .any(|s| s == scope_name)
 3028        })
 3029    }
 3030
 3031    pub fn set_use_modal_editing(&mut self, to: bool) {
 3032        self.use_modal_editing = to;
 3033    }
 3034
 3035    pub fn use_modal_editing(&self) -> bool {
 3036        self.use_modal_editing
 3037    }
 3038
 3039    fn selections_did_change(
 3040        &mut self,
 3041        local: bool,
 3042        old_cursor_position: &Anchor,
 3043        effects: SelectionEffects,
 3044        window: &mut Window,
 3045        cx: &mut Context<Self>,
 3046    ) {
 3047        window.invalidate_character_coordinates();
 3048
 3049        // Copy selections to primary selection buffer
 3050        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3051        if local {
 3052            let selections = self.selections.all::<usize>(cx);
 3053            let buffer_handle = self.buffer.read(cx).read(cx);
 3054
 3055            let mut text = String::new();
 3056            for (index, selection) in selections.iter().enumerate() {
 3057                let text_for_selection = buffer_handle
 3058                    .text_for_range(selection.start..selection.end)
 3059                    .collect::<String>();
 3060
 3061                text.push_str(&text_for_selection);
 3062                if index != selections.len() - 1 {
 3063                    text.push('\n');
 3064                }
 3065            }
 3066
 3067            if !text.is_empty() {
 3068                cx.write_to_primary(ClipboardItem::new_string(text));
 3069            }
 3070        }
 3071
 3072        let selection_anchors = self.selections.disjoint_anchors_arc();
 3073
 3074        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3075            self.buffer.update(cx, |buffer, cx| {
 3076                buffer.set_active_selections(
 3077                    &selection_anchors,
 3078                    self.selections.line_mode(),
 3079                    self.cursor_shape,
 3080                    cx,
 3081                )
 3082            });
 3083        }
 3084        let display_map = self
 3085            .display_map
 3086            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3087        let buffer = &display_map.buffer_snapshot;
 3088        if self.selections.count() == 1 {
 3089            self.add_selections_state = None;
 3090        }
 3091        self.select_next_state = None;
 3092        self.select_prev_state = None;
 3093        self.select_syntax_node_history.try_clear();
 3094        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3095        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3096        self.take_rename(false, window, cx);
 3097
 3098        let newest_selection = self.selections.newest_anchor();
 3099        let new_cursor_position = newest_selection.head();
 3100        let selection_start = newest_selection.start;
 3101
 3102        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3103            self.push_to_nav_history(
 3104                *old_cursor_position,
 3105                Some(new_cursor_position.to_point(buffer)),
 3106                false,
 3107                effects.nav_history == Some(true),
 3108                cx,
 3109            );
 3110        }
 3111
 3112        if local {
 3113            if let Some(buffer_id) = new_cursor_position.buffer_id
 3114                && !self.registered_buffers.contains_key(&buffer_id)
 3115                && let Some(project) = self.project.as_ref()
 3116            {
 3117                project.update(cx, |project, cx| {
 3118                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3119                        return;
 3120                    };
 3121                    self.registered_buffers.insert(
 3122                        buffer_id,
 3123                        project.register_buffer_with_language_servers(&buffer, cx),
 3124                    );
 3125                })
 3126            }
 3127
 3128            let mut context_menu = self.context_menu.borrow_mut();
 3129            let completion_menu = match context_menu.as_ref() {
 3130                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3131                Some(CodeContextMenu::CodeActions(_)) => {
 3132                    *context_menu = None;
 3133                    None
 3134                }
 3135                None => None,
 3136            };
 3137            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3138            drop(context_menu);
 3139
 3140            if effects.completions
 3141                && let Some(completion_position) = completion_position
 3142            {
 3143                let start_offset = selection_start.to_offset(buffer);
 3144                let position_matches = start_offset == completion_position.to_offset(buffer);
 3145                let continue_showing = if position_matches {
 3146                    if self.snippet_stack.is_empty() {
 3147                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3148                            == Some(CharKind::Word)
 3149                    } else {
 3150                        // Snippet choices can be shown even when the cursor is in whitespace.
 3151                        // Dismissing the menu with actions like backspace is handled by
 3152                        // invalidation regions.
 3153                        true
 3154                    }
 3155                } else {
 3156                    false
 3157                };
 3158
 3159                if continue_showing {
 3160                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3161                } else {
 3162                    self.hide_context_menu(window, cx);
 3163                }
 3164            }
 3165
 3166            hide_hover(self, cx);
 3167
 3168            if old_cursor_position.to_display_point(&display_map).row()
 3169                != new_cursor_position.to_display_point(&display_map).row()
 3170            {
 3171                self.available_code_actions.take();
 3172            }
 3173            self.refresh_code_actions(window, cx);
 3174            self.refresh_document_highlights(cx);
 3175            self.refresh_selected_text_highlights(false, window, cx);
 3176            refresh_matching_bracket_highlights(self, window, cx);
 3177            self.update_visible_edit_prediction(window, cx);
 3178            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3179            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3180            self.inline_blame_popover.take();
 3181            if self.git_blame_inline_enabled {
 3182                self.start_inline_blame_timer(window, cx);
 3183            }
 3184        }
 3185
 3186        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3187        cx.emit(EditorEvent::SelectionsChanged { local });
 3188
 3189        let selections = &self.selections.disjoint_anchors_arc();
 3190        if selections.len() == 1 {
 3191            cx.emit(SearchEvent::ActiveMatchChanged)
 3192        }
 3193        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3194            let inmemory_selections = selections
 3195                .iter()
 3196                .map(|s| {
 3197                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3198                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3199                })
 3200                .collect();
 3201            self.update_restoration_data(cx, |data| {
 3202                data.selections = inmemory_selections;
 3203            });
 3204
 3205            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3206                && let Some(workspace_id) =
 3207                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3208            {
 3209                let snapshot = self.buffer().read(cx).snapshot(cx);
 3210                let selections = selections.clone();
 3211                let background_executor = cx.background_executor().clone();
 3212                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3213                self.serialize_selections = cx.background_spawn(async move {
 3214                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3215                    let db_selections = selections
 3216                        .iter()
 3217                        .map(|selection| {
 3218                            (
 3219                                selection.start.to_offset(&snapshot),
 3220                                selection.end.to_offset(&snapshot),
 3221                            )
 3222                        })
 3223                        .collect();
 3224
 3225                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3226                        .await
 3227                        .with_context(|| {
 3228                            format!(
 3229                                "persisting editor selections for editor {editor_id}, \
 3230                                workspace {workspace_id:?}"
 3231                            )
 3232                        })
 3233                        .log_err();
 3234                });
 3235            }
 3236        }
 3237
 3238        cx.notify();
 3239    }
 3240
 3241    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3242        use text::ToOffset as _;
 3243        use text::ToPoint as _;
 3244
 3245        if self.mode.is_minimap()
 3246            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3247        {
 3248            return;
 3249        }
 3250
 3251        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3252            return;
 3253        };
 3254
 3255        let snapshot = singleton.read(cx).snapshot();
 3256        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3257            let display_snapshot = display_map.snapshot(cx);
 3258
 3259            display_snapshot
 3260                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3261                .map(|fold| {
 3262                    fold.range.start.text_anchor.to_point(&snapshot)
 3263                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3264                })
 3265                .collect()
 3266        });
 3267        self.update_restoration_data(cx, |data| {
 3268            data.folds = inmemory_folds;
 3269        });
 3270
 3271        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3272            return;
 3273        };
 3274        let background_executor = cx.background_executor().clone();
 3275        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3276        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3277            display_map
 3278                .snapshot(cx)
 3279                .folds_in_range(0..snapshot.len())
 3280                .map(|fold| {
 3281                    (
 3282                        fold.range.start.text_anchor.to_offset(&snapshot),
 3283                        fold.range.end.text_anchor.to_offset(&snapshot),
 3284                    )
 3285                })
 3286                .collect()
 3287        });
 3288        self.serialize_folds = cx.background_spawn(async move {
 3289            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3290            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3291                .await
 3292                .with_context(|| {
 3293                    format!(
 3294                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3295                    )
 3296                })
 3297                .log_err();
 3298        });
 3299    }
 3300
 3301    pub fn sync_selections(
 3302        &mut self,
 3303        other: Entity<Editor>,
 3304        cx: &mut Context<Self>,
 3305    ) -> gpui::Subscription {
 3306        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3307        if !other_selections.is_empty() {
 3308            self.selections.change_with(cx, |selections| {
 3309                selections.select_anchors(other_selections);
 3310            });
 3311        }
 3312
 3313        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3314            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3315                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3316                if other_selections.is_empty() {
 3317                    return;
 3318                }
 3319                this.selections.change_with(cx, |selections| {
 3320                    selections.select_anchors(other_selections);
 3321                });
 3322            }
 3323        });
 3324
 3325        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3326            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3327                let these_selections = this.selections.disjoint_anchors().to_vec();
 3328                if these_selections.is_empty() {
 3329                    return;
 3330                }
 3331                other.update(cx, |other_editor, cx| {
 3332                    other_editor.selections.change_with(cx, |selections| {
 3333                        selections.select_anchors(these_selections);
 3334                    })
 3335                });
 3336            }
 3337        });
 3338
 3339        Subscription::join(other_subscription, this_subscription)
 3340    }
 3341
 3342    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3343    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3344    /// effects of selection change occur at the end of the transaction.
 3345    pub fn change_selections<R>(
 3346        &mut self,
 3347        effects: SelectionEffects,
 3348        window: &mut Window,
 3349        cx: &mut Context<Self>,
 3350        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3351    ) -> R {
 3352        if let Some(state) = &mut self.deferred_selection_effects_state {
 3353            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3354            state.effects.completions = effects.completions;
 3355            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3356            let (changed, result) = self.selections.change_with(cx, change);
 3357            state.changed |= changed;
 3358            return result;
 3359        }
 3360        let mut state = DeferredSelectionEffectsState {
 3361            changed: false,
 3362            effects,
 3363            old_cursor_position: self.selections.newest_anchor().head(),
 3364            history_entry: SelectionHistoryEntry {
 3365                selections: self.selections.disjoint_anchors_arc(),
 3366                select_next_state: self.select_next_state.clone(),
 3367                select_prev_state: self.select_prev_state.clone(),
 3368                add_selections_state: self.add_selections_state.clone(),
 3369            },
 3370        };
 3371        let (changed, result) = self.selections.change_with(cx, change);
 3372        state.changed = state.changed || changed;
 3373        if self.defer_selection_effects {
 3374            self.deferred_selection_effects_state = Some(state);
 3375        } else {
 3376            self.apply_selection_effects(state, window, cx);
 3377        }
 3378        result
 3379    }
 3380
 3381    /// Defers the effects of selection change, so that the effects of multiple calls to
 3382    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3383    /// to selection history and the state of popovers based on selection position aren't
 3384    /// erroneously updated.
 3385    pub fn with_selection_effects_deferred<R>(
 3386        &mut self,
 3387        window: &mut Window,
 3388        cx: &mut Context<Self>,
 3389        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3390    ) -> R {
 3391        let already_deferred = self.defer_selection_effects;
 3392        self.defer_selection_effects = true;
 3393        let result = update(self, window, cx);
 3394        if !already_deferred {
 3395            self.defer_selection_effects = false;
 3396            if let Some(state) = self.deferred_selection_effects_state.take() {
 3397                self.apply_selection_effects(state, window, cx);
 3398            }
 3399        }
 3400        result
 3401    }
 3402
 3403    fn apply_selection_effects(
 3404        &mut self,
 3405        state: DeferredSelectionEffectsState,
 3406        window: &mut Window,
 3407        cx: &mut Context<Self>,
 3408    ) {
 3409        if state.changed {
 3410            self.selection_history.push(state.history_entry);
 3411
 3412            if let Some(autoscroll) = state.effects.scroll {
 3413                self.request_autoscroll(autoscroll, cx);
 3414            }
 3415
 3416            let old_cursor_position = &state.old_cursor_position;
 3417
 3418            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3419
 3420            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3421                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3422            }
 3423        }
 3424    }
 3425
 3426    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3427    where
 3428        I: IntoIterator<Item = (Range<S>, T)>,
 3429        S: ToOffset,
 3430        T: Into<Arc<str>>,
 3431    {
 3432        if self.read_only(cx) {
 3433            return;
 3434        }
 3435
 3436        self.buffer
 3437            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3438    }
 3439
 3440    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3441    where
 3442        I: IntoIterator<Item = (Range<S>, T)>,
 3443        S: ToOffset,
 3444        T: Into<Arc<str>>,
 3445    {
 3446        if self.read_only(cx) {
 3447            return;
 3448        }
 3449
 3450        self.buffer.update(cx, |buffer, cx| {
 3451            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3452        });
 3453    }
 3454
 3455    pub fn edit_with_block_indent<I, S, T>(
 3456        &mut self,
 3457        edits: I,
 3458        original_indent_columns: Vec<Option<u32>>,
 3459        cx: &mut Context<Self>,
 3460    ) where
 3461        I: IntoIterator<Item = (Range<S>, T)>,
 3462        S: ToOffset,
 3463        T: Into<Arc<str>>,
 3464    {
 3465        if self.read_only(cx) {
 3466            return;
 3467        }
 3468
 3469        self.buffer.update(cx, |buffer, cx| {
 3470            buffer.edit(
 3471                edits,
 3472                Some(AutoindentMode::Block {
 3473                    original_indent_columns,
 3474                }),
 3475                cx,
 3476            )
 3477        });
 3478    }
 3479
 3480    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3481        self.hide_context_menu(window, cx);
 3482
 3483        match phase {
 3484            SelectPhase::Begin {
 3485                position,
 3486                add,
 3487                click_count,
 3488            } => self.begin_selection(position, add, click_count, window, cx),
 3489            SelectPhase::BeginColumnar {
 3490                position,
 3491                goal_column,
 3492                reset,
 3493                mode,
 3494            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3495            SelectPhase::Extend {
 3496                position,
 3497                click_count,
 3498            } => self.extend_selection(position, click_count, window, cx),
 3499            SelectPhase::Update {
 3500                position,
 3501                goal_column,
 3502                scroll_delta,
 3503            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3504            SelectPhase::End => self.end_selection(window, cx),
 3505        }
 3506    }
 3507
 3508    fn extend_selection(
 3509        &mut self,
 3510        position: DisplayPoint,
 3511        click_count: usize,
 3512        window: &mut Window,
 3513        cx: &mut Context<Self>,
 3514    ) {
 3515        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3516        let tail = self.selections.newest::<usize>(cx).tail();
 3517        self.begin_selection(position, false, click_count, window, cx);
 3518
 3519        let position = position.to_offset(&display_map, Bias::Left);
 3520        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3521
 3522        let mut pending_selection = self
 3523            .selections
 3524            .pending_anchor()
 3525            .cloned()
 3526            .expect("extend_selection not called with pending selection");
 3527        if position >= tail {
 3528            pending_selection.start = tail_anchor;
 3529        } else {
 3530            pending_selection.end = tail_anchor;
 3531            pending_selection.reversed = true;
 3532        }
 3533
 3534        let mut pending_mode = self.selections.pending_mode().unwrap();
 3535        match &mut pending_mode {
 3536            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3537            _ => {}
 3538        }
 3539
 3540        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3541            SelectionEffects::scroll(Autoscroll::fit())
 3542        } else {
 3543            SelectionEffects::no_scroll()
 3544        };
 3545
 3546        self.change_selections(effects, window, cx, |s| {
 3547            s.set_pending(pending_selection.clone(), pending_mode)
 3548        });
 3549    }
 3550
 3551    fn begin_selection(
 3552        &mut self,
 3553        position: DisplayPoint,
 3554        add: bool,
 3555        click_count: usize,
 3556        window: &mut Window,
 3557        cx: &mut Context<Self>,
 3558    ) {
 3559        if !self.focus_handle.is_focused(window) {
 3560            self.last_focused_descendant = None;
 3561            window.focus(&self.focus_handle);
 3562        }
 3563
 3564        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3565        let buffer = &display_map.buffer_snapshot;
 3566        let position = display_map.clip_point(position, Bias::Left);
 3567
 3568        let start;
 3569        let end;
 3570        let mode;
 3571        let mut auto_scroll;
 3572        match click_count {
 3573            1 => {
 3574                start = buffer.anchor_before(position.to_point(&display_map));
 3575                end = start;
 3576                mode = SelectMode::Character;
 3577                auto_scroll = true;
 3578            }
 3579            2 => {
 3580                let position = display_map
 3581                    .clip_point(position, Bias::Left)
 3582                    .to_offset(&display_map, Bias::Left);
 3583                let (range, _) = buffer.surrounding_word(position, None);
 3584                start = buffer.anchor_before(range.start);
 3585                end = buffer.anchor_before(range.end);
 3586                mode = SelectMode::Word(start..end);
 3587                auto_scroll = true;
 3588            }
 3589            3 => {
 3590                let position = display_map
 3591                    .clip_point(position, Bias::Left)
 3592                    .to_point(&display_map);
 3593                let line_start = display_map.prev_line_boundary(position).0;
 3594                let next_line_start = buffer.clip_point(
 3595                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3596                    Bias::Left,
 3597                );
 3598                start = buffer.anchor_before(line_start);
 3599                end = buffer.anchor_before(next_line_start);
 3600                mode = SelectMode::Line(start..end);
 3601                auto_scroll = true;
 3602            }
 3603            _ => {
 3604                start = buffer.anchor_before(0);
 3605                end = buffer.anchor_before(buffer.len());
 3606                mode = SelectMode::All;
 3607                auto_scroll = false;
 3608            }
 3609        }
 3610        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3611
 3612        let point_to_delete: Option<usize> = {
 3613            let selected_points: Vec<Selection<Point>> =
 3614                self.selections.disjoint_in_range(start..end, cx);
 3615
 3616            if !add || click_count > 1 {
 3617                None
 3618            } else if !selected_points.is_empty() {
 3619                Some(selected_points[0].id)
 3620            } else {
 3621                let clicked_point_already_selected =
 3622                    self.selections.disjoint_anchors().iter().find(|selection| {
 3623                        selection.start.to_point(buffer) == start.to_point(buffer)
 3624                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3625                    });
 3626
 3627                clicked_point_already_selected.map(|selection| selection.id)
 3628            }
 3629        };
 3630
 3631        let selections_count = self.selections.count();
 3632        let effects = if auto_scroll {
 3633            SelectionEffects::default()
 3634        } else {
 3635            SelectionEffects::no_scroll()
 3636        };
 3637
 3638        self.change_selections(effects, window, cx, |s| {
 3639            if let Some(point_to_delete) = point_to_delete {
 3640                s.delete(point_to_delete);
 3641
 3642                if selections_count == 1 {
 3643                    s.set_pending_anchor_range(start..end, mode);
 3644                }
 3645            } else {
 3646                if !add {
 3647                    s.clear_disjoint();
 3648                }
 3649
 3650                s.set_pending_anchor_range(start..end, mode);
 3651            }
 3652        });
 3653    }
 3654
 3655    fn begin_columnar_selection(
 3656        &mut self,
 3657        position: DisplayPoint,
 3658        goal_column: u32,
 3659        reset: bool,
 3660        mode: ColumnarMode,
 3661        window: &mut Window,
 3662        cx: &mut Context<Self>,
 3663    ) {
 3664        if !self.focus_handle.is_focused(window) {
 3665            self.last_focused_descendant = None;
 3666            window.focus(&self.focus_handle);
 3667        }
 3668
 3669        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3670
 3671        if reset {
 3672            let pointer_position = display_map
 3673                .buffer_snapshot
 3674                .anchor_before(position.to_point(&display_map));
 3675
 3676            self.change_selections(
 3677                SelectionEffects::scroll(Autoscroll::newest()),
 3678                window,
 3679                cx,
 3680                |s| {
 3681                    s.clear_disjoint();
 3682                    s.set_pending_anchor_range(
 3683                        pointer_position..pointer_position,
 3684                        SelectMode::Character,
 3685                    );
 3686                },
 3687            );
 3688        };
 3689
 3690        let tail = self.selections.newest::<Point>(cx).tail();
 3691        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3692        self.columnar_selection_state = match mode {
 3693            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3694                selection_tail: selection_anchor,
 3695                display_point: if reset {
 3696                    if position.column() != goal_column {
 3697                        Some(DisplayPoint::new(position.row(), goal_column))
 3698                    } else {
 3699                        None
 3700                    }
 3701                } else {
 3702                    None
 3703                },
 3704            }),
 3705            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3706                selection_tail: selection_anchor,
 3707            }),
 3708        };
 3709
 3710        if !reset {
 3711            self.select_columns(position, goal_column, &display_map, window, cx);
 3712        }
 3713    }
 3714
 3715    fn update_selection(
 3716        &mut self,
 3717        position: DisplayPoint,
 3718        goal_column: u32,
 3719        scroll_delta: gpui::Point<f32>,
 3720        window: &mut Window,
 3721        cx: &mut Context<Self>,
 3722    ) {
 3723        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3724
 3725        if self.columnar_selection_state.is_some() {
 3726            self.select_columns(position, goal_column, &display_map, window, cx);
 3727        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3728            let buffer = &display_map.buffer_snapshot;
 3729            let head;
 3730            let tail;
 3731            let mode = self.selections.pending_mode().unwrap();
 3732            match &mode {
 3733                SelectMode::Character => {
 3734                    head = position.to_point(&display_map);
 3735                    tail = pending.tail().to_point(buffer);
 3736                }
 3737                SelectMode::Word(original_range) => {
 3738                    let offset = display_map
 3739                        .clip_point(position, Bias::Left)
 3740                        .to_offset(&display_map, Bias::Left);
 3741                    let original_range = original_range.to_offset(buffer);
 3742
 3743                    let head_offset = if buffer.is_inside_word(offset, None)
 3744                        || original_range.contains(&offset)
 3745                    {
 3746                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3747                        if word_range.start < original_range.start {
 3748                            word_range.start
 3749                        } else {
 3750                            word_range.end
 3751                        }
 3752                    } else {
 3753                        offset
 3754                    };
 3755
 3756                    head = head_offset.to_point(buffer);
 3757                    if head_offset <= original_range.start {
 3758                        tail = original_range.end.to_point(buffer);
 3759                    } else {
 3760                        tail = original_range.start.to_point(buffer);
 3761                    }
 3762                }
 3763                SelectMode::Line(original_range) => {
 3764                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3765
 3766                    let position = display_map
 3767                        .clip_point(position, Bias::Left)
 3768                        .to_point(&display_map);
 3769                    let line_start = display_map.prev_line_boundary(position).0;
 3770                    let next_line_start = buffer.clip_point(
 3771                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3772                        Bias::Left,
 3773                    );
 3774
 3775                    if line_start < original_range.start {
 3776                        head = line_start
 3777                    } else {
 3778                        head = next_line_start
 3779                    }
 3780
 3781                    if head <= original_range.start {
 3782                        tail = original_range.end;
 3783                    } else {
 3784                        tail = original_range.start;
 3785                    }
 3786                }
 3787                SelectMode::All => {
 3788                    return;
 3789                }
 3790            };
 3791
 3792            if head < tail {
 3793                pending.start = buffer.anchor_before(head);
 3794                pending.end = buffer.anchor_before(tail);
 3795                pending.reversed = true;
 3796            } else {
 3797                pending.start = buffer.anchor_before(tail);
 3798                pending.end = buffer.anchor_before(head);
 3799                pending.reversed = false;
 3800            }
 3801
 3802            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3803                s.set_pending(pending.clone(), mode);
 3804            });
 3805        } else {
 3806            log::error!("update_selection dispatched with no pending selection");
 3807            return;
 3808        }
 3809
 3810        self.apply_scroll_delta(scroll_delta, window, cx);
 3811        cx.notify();
 3812    }
 3813
 3814    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3815        self.columnar_selection_state.take();
 3816        if self.selections.pending_anchor().is_some() {
 3817            let selections = self.selections.all::<usize>(cx);
 3818            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3819                s.select(selections);
 3820                s.clear_pending();
 3821            });
 3822        }
 3823    }
 3824
 3825    fn select_columns(
 3826        &mut self,
 3827        head: DisplayPoint,
 3828        goal_column: u32,
 3829        display_map: &DisplaySnapshot,
 3830        window: &mut Window,
 3831        cx: &mut Context<Self>,
 3832    ) {
 3833        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3834            return;
 3835        };
 3836
 3837        let tail = match columnar_state {
 3838            ColumnarSelectionState::FromMouse {
 3839                selection_tail,
 3840                display_point,
 3841            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3842            ColumnarSelectionState::FromSelection { selection_tail } => {
 3843                selection_tail.to_display_point(display_map)
 3844            }
 3845        };
 3846
 3847        let start_row = cmp::min(tail.row(), head.row());
 3848        let end_row = cmp::max(tail.row(), head.row());
 3849        let start_column = cmp::min(tail.column(), goal_column);
 3850        let end_column = cmp::max(tail.column(), goal_column);
 3851        let reversed = start_column < tail.column();
 3852
 3853        let selection_ranges = (start_row.0..=end_row.0)
 3854            .map(DisplayRow)
 3855            .filter_map(|row| {
 3856                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3857                    || start_column <= display_map.line_len(row))
 3858                    && !display_map.is_block_line(row)
 3859                {
 3860                    let start = display_map
 3861                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3862                        .to_point(display_map);
 3863                    let end = display_map
 3864                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3865                        .to_point(display_map);
 3866                    if reversed {
 3867                        Some(end..start)
 3868                    } else {
 3869                        Some(start..end)
 3870                    }
 3871                } else {
 3872                    None
 3873                }
 3874            })
 3875            .collect::<Vec<_>>();
 3876
 3877        let ranges = match columnar_state {
 3878            ColumnarSelectionState::FromMouse { .. } => {
 3879                let mut non_empty_ranges = selection_ranges
 3880                    .iter()
 3881                    .filter(|selection_range| selection_range.start != selection_range.end)
 3882                    .peekable();
 3883                if non_empty_ranges.peek().is_some() {
 3884                    non_empty_ranges.cloned().collect()
 3885                } else {
 3886                    selection_ranges
 3887                }
 3888            }
 3889            _ => selection_ranges,
 3890        };
 3891
 3892        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3893            s.select_ranges(ranges);
 3894        });
 3895        cx.notify();
 3896    }
 3897
 3898    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3899        self.selections
 3900            .all_adjusted(cx)
 3901            .iter()
 3902            .any(|selection| !selection.is_empty())
 3903    }
 3904
 3905    pub fn has_pending_nonempty_selection(&self) -> bool {
 3906        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3907            Some(Selection { start, end, .. }) => start != end,
 3908            None => false,
 3909        };
 3910
 3911        pending_nonempty_selection
 3912            || (self.columnar_selection_state.is_some()
 3913                && self.selections.disjoint_anchors().len() > 1)
 3914    }
 3915
 3916    pub fn has_pending_selection(&self) -> bool {
 3917        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3918    }
 3919
 3920    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3921        self.selection_mark_mode = false;
 3922        self.selection_drag_state = SelectionDragState::None;
 3923
 3924        if self.clear_expanded_diff_hunks(cx) {
 3925            cx.notify();
 3926            return;
 3927        }
 3928        if self.dismiss_menus_and_popups(true, window, cx) {
 3929            return;
 3930        }
 3931
 3932        if self.mode.is_full()
 3933            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3934        {
 3935            return;
 3936        }
 3937
 3938        cx.propagate();
 3939    }
 3940
 3941    pub fn dismiss_menus_and_popups(
 3942        &mut self,
 3943        is_user_requested: bool,
 3944        window: &mut Window,
 3945        cx: &mut Context<Self>,
 3946    ) -> bool {
 3947        if self.take_rename(false, window, cx).is_some() {
 3948            return true;
 3949        }
 3950
 3951        if hide_hover(self, cx) {
 3952            return true;
 3953        }
 3954
 3955        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3956            return true;
 3957        }
 3958
 3959        if self.hide_context_menu(window, cx).is_some() {
 3960            return true;
 3961        }
 3962
 3963        if self.mouse_context_menu.take().is_some() {
 3964            return true;
 3965        }
 3966
 3967        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3968            return true;
 3969        }
 3970
 3971        if self.snippet_stack.pop().is_some() {
 3972            return true;
 3973        }
 3974
 3975        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3976            self.dismiss_diagnostics(cx);
 3977            return true;
 3978        }
 3979
 3980        false
 3981    }
 3982
 3983    fn linked_editing_ranges_for(
 3984        &self,
 3985        selection: Range<text::Anchor>,
 3986        cx: &App,
 3987    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3988        if self.linked_edit_ranges.is_empty() {
 3989            return None;
 3990        }
 3991        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3992            selection.end.buffer_id.and_then(|end_buffer_id| {
 3993                if selection.start.buffer_id != Some(end_buffer_id) {
 3994                    return None;
 3995                }
 3996                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3997                let snapshot = buffer.read(cx).snapshot();
 3998                self.linked_edit_ranges
 3999                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4000                    .map(|ranges| (ranges, snapshot, buffer))
 4001            })?;
 4002        use text::ToOffset as TO;
 4003        // find offset from the start of current range to current cursor position
 4004        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4005
 4006        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4007        let start_difference = start_offset - start_byte_offset;
 4008        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4009        let end_difference = end_offset - start_byte_offset;
 4010        // Current range has associated linked ranges.
 4011        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4012        for range in linked_ranges.iter() {
 4013            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4014            let end_offset = start_offset + end_difference;
 4015            let start_offset = start_offset + start_difference;
 4016            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4017                continue;
 4018            }
 4019            if self.selections.disjoint_anchor_ranges().any(|s| {
 4020                if s.start.buffer_id != selection.start.buffer_id
 4021                    || s.end.buffer_id != selection.end.buffer_id
 4022                {
 4023                    return false;
 4024                }
 4025                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4026                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4027            }) {
 4028                continue;
 4029            }
 4030            let start = buffer_snapshot.anchor_after(start_offset);
 4031            let end = buffer_snapshot.anchor_after(end_offset);
 4032            linked_edits
 4033                .entry(buffer.clone())
 4034                .or_default()
 4035                .push(start..end);
 4036        }
 4037        Some(linked_edits)
 4038    }
 4039
 4040    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4041        let text: Arc<str> = text.into();
 4042
 4043        if self.read_only(cx) {
 4044            return;
 4045        }
 4046
 4047        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4048
 4049        let selections = self.selections.all_adjusted(cx);
 4050        let mut bracket_inserted = false;
 4051        let mut edits = Vec::new();
 4052        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4053        let mut new_selections = Vec::with_capacity(selections.len());
 4054        let mut new_autoclose_regions = Vec::new();
 4055        let snapshot = self.buffer.read(cx).read(cx);
 4056        let mut clear_linked_edit_ranges = false;
 4057
 4058        for (selection, autoclose_region) in
 4059            self.selections_with_autoclose_regions(selections, &snapshot)
 4060        {
 4061            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4062                // Determine if the inserted text matches the opening or closing
 4063                // bracket of any of this language's bracket pairs.
 4064                let mut bracket_pair = None;
 4065                let mut is_bracket_pair_start = false;
 4066                let mut is_bracket_pair_end = false;
 4067                if !text.is_empty() {
 4068                    let mut bracket_pair_matching_end = None;
 4069                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4070                    //  and they are removing the character that triggered IME popup.
 4071                    for (pair, enabled) in scope.brackets() {
 4072                        if !pair.close && !pair.surround {
 4073                            continue;
 4074                        }
 4075
 4076                        if enabled && pair.start.ends_with(text.as_ref()) {
 4077                            let prefix_len = pair.start.len() - text.len();
 4078                            let preceding_text_matches_prefix = prefix_len == 0
 4079                                || (selection.start.column >= (prefix_len as u32)
 4080                                    && snapshot.contains_str_at(
 4081                                        Point::new(
 4082                                            selection.start.row,
 4083                                            selection.start.column - (prefix_len as u32),
 4084                                        ),
 4085                                        &pair.start[..prefix_len],
 4086                                    ));
 4087                            if preceding_text_matches_prefix {
 4088                                bracket_pair = Some(pair.clone());
 4089                                is_bracket_pair_start = true;
 4090                                break;
 4091                            }
 4092                        }
 4093                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4094                        {
 4095                            // take first bracket pair matching end, but don't break in case a later bracket
 4096                            // pair matches start
 4097                            bracket_pair_matching_end = Some(pair.clone());
 4098                        }
 4099                    }
 4100                    if let Some(end) = bracket_pair_matching_end
 4101                        && bracket_pair.is_none()
 4102                    {
 4103                        bracket_pair = Some(end);
 4104                        is_bracket_pair_end = true;
 4105                    }
 4106                }
 4107
 4108                if let Some(bracket_pair) = bracket_pair {
 4109                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4110                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4111                    let auto_surround =
 4112                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4113                    if selection.is_empty() {
 4114                        if is_bracket_pair_start {
 4115                            // If the inserted text is a suffix of an opening bracket and the
 4116                            // selection is preceded by the rest of the opening bracket, then
 4117                            // insert the closing bracket.
 4118                            let following_text_allows_autoclose = snapshot
 4119                                .chars_at(selection.start)
 4120                                .next()
 4121                                .is_none_or(|c| scope.should_autoclose_before(c));
 4122
 4123                            let preceding_text_allows_autoclose = selection.start.column == 0
 4124                                || snapshot
 4125                                    .reversed_chars_at(selection.start)
 4126                                    .next()
 4127                                    .is_none_or(|c| {
 4128                                        bracket_pair.start != bracket_pair.end
 4129                                            || !snapshot
 4130                                                .char_classifier_at(selection.start)
 4131                                                .is_word(c)
 4132                                    });
 4133
 4134                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4135                                && bracket_pair.start.len() == 1
 4136                            {
 4137                                let target = bracket_pair.start.chars().next().unwrap();
 4138                                let current_line_count = snapshot
 4139                                    .reversed_chars_at(selection.start)
 4140                                    .take_while(|&c| c != '\n')
 4141                                    .filter(|&c| c == target)
 4142                                    .count();
 4143                                current_line_count % 2 == 1
 4144                            } else {
 4145                                false
 4146                            };
 4147
 4148                            if autoclose
 4149                                && bracket_pair.close
 4150                                && following_text_allows_autoclose
 4151                                && preceding_text_allows_autoclose
 4152                                && !is_closing_quote
 4153                            {
 4154                                let anchor = snapshot.anchor_before(selection.end);
 4155                                new_selections.push((selection.map(|_| anchor), text.len()));
 4156                                new_autoclose_regions.push((
 4157                                    anchor,
 4158                                    text.len(),
 4159                                    selection.id,
 4160                                    bracket_pair.clone(),
 4161                                ));
 4162                                edits.push((
 4163                                    selection.range(),
 4164                                    format!("{}{}", text, bracket_pair.end).into(),
 4165                                ));
 4166                                bracket_inserted = true;
 4167                                continue;
 4168                            }
 4169                        }
 4170
 4171                        if let Some(region) = autoclose_region {
 4172                            // If the selection is followed by an auto-inserted closing bracket,
 4173                            // then don't insert that closing bracket again; just move the selection
 4174                            // past the closing bracket.
 4175                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4176                                && text.as_ref() == region.pair.end.as_str()
 4177                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4178                            if should_skip {
 4179                                let anchor = snapshot.anchor_after(selection.end);
 4180                                new_selections
 4181                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4182                                continue;
 4183                            }
 4184                        }
 4185
 4186                        let always_treat_brackets_as_autoclosed = snapshot
 4187                            .language_settings_at(selection.start, cx)
 4188                            .always_treat_brackets_as_autoclosed;
 4189                        if always_treat_brackets_as_autoclosed
 4190                            && is_bracket_pair_end
 4191                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4192                        {
 4193                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4194                            // and the inserted text is a closing bracket and the selection is followed
 4195                            // by the closing bracket then move the selection past the closing bracket.
 4196                            let anchor = snapshot.anchor_after(selection.end);
 4197                            new_selections.push((selection.map(|_| anchor), text.len()));
 4198                            continue;
 4199                        }
 4200                    }
 4201                    // If an opening bracket is 1 character long and is typed while
 4202                    // text is selected, then surround that text with the bracket pair.
 4203                    else if auto_surround
 4204                        && bracket_pair.surround
 4205                        && is_bracket_pair_start
 4206                        && bracket_pair.start.chars().count() == 1
 4207                    {
 4208                        edits.push((selection.start..selection.start, text.clone()));
 4209                        edits.push((
 4210                            selection.end..selection.end,
 4211                            bracket_pair.end.as_str().into(),
 4212                        ));
 4213                        bracket_inserted = true;
 4214                        new_selections.push((
 4215                            Selection {
 4216                                id: selection.id,
 4217                                start: snapshot.anchor_after(selection.start),
 4218                                end: snapshot.anchor_before(selection.end),
 4219                                reversed: selection.reversed,
 4220                                goal: selection.goal,
 4221                            },
 4222                            0,
 4223                        ));
 4224                        continue;
 4225                    }
 4226                }
 4227            }
 4228
 4229            if self.auto_replace_emoji_shortcode
 4230                && selection.is_empty()
 4231                && text.as_ref().ends_with(':')
 4232                && let Some(possible_emoji_short_code) =
 4233                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4234                && !possible_emoji_short_code.is_empty()
 4235                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4236            {
 4237                let emoji_shortcode_start = Point::new(
 4238                    selection.start.row,
 4239                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4240                );
 4241
 4242                // Remove shortcode from buffer
 4243                edits.push((
 4244                    emoji_shortcode_start..selection.start,
 4245                    "".to_string().into(),
 4246                ));
 4247                new_selections.push((
 4248                    Selection {
 4249                        id: selection.id,
 4250                        start: snapshot.anchor_after(emoji_shortcode_start),
 4251                        end: snapshot.anchor_before(selection.start),
 4252                        reversed: selection.reversed,
 4253                        goal: selection.goal,
 4254                    },
 4255                    0,
 4256                ));
 4257
 4258                // Insert emoji
 4259                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4260                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4261                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4262
 4263                continue;
 4264            }
 4265
 4266            // If not handling any auto-close operation, then just replace the selected
 4267            // text with the given input and move the selection to the end of the
 4268            // newly inserted text.
 4269            let anchor = snapshot.anchor_after(selection.end);
 4270            if !self.linked_edit_ranges.is_empty() {
 4271                let start_anchor = snapshot.anchor_before(selection.start);
 4272
 4273                let is_word_char = text.chars().next().is_none_or(|char| {
 4274                    let classifier = snapshot
 4275                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4276                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4277                    classifier.is_word(char)
 4278                });
 4279
 4280                if is_word_char {
 4281                    if let Some(ranges) = self
 4282                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4283                    {
 4284                        for (buffer, edits) in ranges {
 4285                            linked_edits
 4286                                .entry(buffer.clone())
 4287                                .or_default()
 4288                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4289                        }
 4290                    }
 4291                } else {
 4292                    clear_linked_edit_ranges = true;
 4293                }
 4294            }
 4295
 4296            new_selections.push((selection.map(|_| anchor), 0));
 4297            edits.push((selection.start..selection.end, text.clone()));
 4298        }
 4299
 4300        drop(snapshot);
 4301
 4302        self.transact(window, cx, |this, window, cx| {
 4303            if clear_linked_edit_ranges {
 4304                this.linked_edit_ranges.clear();
 4305            }
 4306            let initial_buffer_versions =
 4307                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4308
 4309            this.buffer.update(cx, |buffer, cx| {
 4310                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4311            });
 4312            for (buffer, edits) in linked_edits {
 4313                buffer.update(cx, |buffer, cx| {
 4314                    let snapshot = buffer.snapshot();
 4315                    let edits = edits
 4316                        .into_iter()
 4317                        .map(|(range, text)| {
 4318                            use text::ToPoint as TP;
 4319                            let end_point = TP::to_point(&range.end, &snapshot);
 4320                            let start_point = TP::to_point(&range.start, &snapshot);
 4321                            (start_point..end_point, text)
 4322                        })
 4323                        .sorted_by_key(|(range, _)| range.start);
 4324                    buffer.edit(edits, None, cx);
 4325                })
 4326            }
 4327            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4328            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4329            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4330            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4331                .zip(new_selection_deltas)
 4332                .map(|(selection, delta)| Selection {
 4333                    id: selection.id,
 4334                    start: selection.start + delta,
 4335                    end: selection.end + delta,
 4336                    reversed: selection.reversed,
 4337                    goal: SelectionGoal::None,
 4338                })
 4339                .collect::<Vec<_>>();
 4340
 4341            let mut i = 0;
 4342            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4343                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4344                let start = map.buffer_snapshot.anchor_before(position);
 4345                let end = map.buffer_snapshot.anchor_after(position);
 4346                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4347                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4348                        Ordering::Less => i += 1,
 4349                        Ordering::Greater => break,
 4350                        Ordering::Equal => {
 4351                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4352                                Ordering::Less => i += 1,
 4353                                Ordering::Equal => break,
 4354                                Ordering::Greater => break,
 4355                            }
 4356                        }
 4357                    }
 4358                }
 4359                this.autoclose_regions.insert(
 4360                    i,
 4361                    AutocloseRegion {
 4362                        selection_id,
 4363                        range: start..end,
 4364                        pair,
 4365                    },
 4366                );
 4367            }
 4368
 4369            let had_active_edit_prediction = this.has_active_edit_prediction();
 4370            this.change_selections(
 4371                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4372                window,
 4373                cx,
 4374                |s| s.select(new_selections),
 4375            );
 4376
 4377            if !bracket_inserted
 4378                && let Some(on_type_format_task) =
 4379                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4380            {
 4381                on_type_format_task.detach_and_log_err(cx);
 4382            }
 4383
 4384            let editor_settings = EditorSettings::get_global(cx);
 4385            if bracket_inserted
 4386                && (editor_settings.auto_signature_help
 4387                    || editor_settings.show_signature_help_after_edits)
 4388            {
 4389                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4390            }
 4391
 4392            let trigger_in_words =
 4393                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4394            if this.hard_wrap.is_some() {
 4395                let latest: Range<Point> = this.selections.newest(cx).range();
 4396                if latest.is_empty()
 4397                    && this
 4398                        .buffer()
 4399                        .read(cx)
 4400                        .snapshot(cx)
 4401                        .line_len(MultiBufferRow(latest.start.row))
 4402                        == latest.start.column
 4403                {
 4404                    this.rewrap_impl(
 4405                        RewrapOptions {
 4406                            override_language_settings: true,
 4407                            preserve_existing_whitespace: true,
 4408                        },
 4409                        cx,
 4410                    )
 4411                }
 4412            }
 4413            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4414            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4415            this.refresh_edit_prediction(true, false, window, cx);
 4416            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4417        });
 4418    }
 4419
 4420    fn find_possible_emoji_shortcode_at_position(
 4421        snapshot: &MultiBufferSnapshot,
 4422        position: Point,
 4423    ) -> Option<String> {
 4424        let mut chars = Vec::new();
 4425        let mut found_colon = false;
 4426        for char in snapshot.reversed_chars_at(position).take(100) {
 4427            // Found a possible emoji shortcode in the middle of the buffer
 4428            if found_colon {
 4429                if char.is_whitespace() {
 4430                    chars.reverse();
 4431                    return Some(chars.iter().collect());
 4432                }
 4433                // If the previous character is not a whitespace, we are in the middle of a word
 4434                // and we only want to complete the shortcode if the word is made up of other emojis
 4435                let mut containing_word = String::new();
 4436                for ch in snapshot
 4437                    .reversed_chars_at(position)
 4438                    .skip(chars.len() + 1)
 4439                    .take(100)
 4440                {
 4441                    if ch.is_whitespace() {
 4442                        break;
 4443                    }
 4444                    containing_word.push(ch);
 4445                }
 4446                let containing_word = containing_word.chars().rev().collect::<String>();
 4447                if util::word_consists_of_emojis(containing_word.as_str()) {
 4448                    chars.reverse();
 4449                    return Some(chars.iter().collect());
 4450                }
 4451            }
 4452
 4453            if char.is_whitespace() || !char.is_ascii() {
 4454                return None;
 4455            }
 4456            if char == ':' {
 4457                found_colon = true;
 4458            } else {
 4459                chars.push(char);
 4460            }
 4461        }
 4462        // Found a possible emoji shortcode at the beginning of the buffer
 4463        chars.reverse();
 4464        Some(chars.iter().collect())
 4465    }
 4466
 4467    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4468        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4469        self.transact(window, cx, |this, window, cx| {
 4470            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4471                let selections = this.selections.all::<usize>(cx);
 4472                let multi_buffer = this.buffer.read(cx);
 4473                let buffer = multi_buffer.snapshot(cx);
 4474                selections
 4475                    .iter()
 4476                    .map(|selection| {
 4477                        let start_point = selection.start.to_point(&buffer);
 4478                        let mut existing_indent =
 4479                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4480                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4481                        let start = selection.start;
 4482                        let end = selection.end;
 4483                        let selection_is_empty = start == end;
 4484                        let language_scope = buffer.language_scope_at(start);
 4485                        let (
 4486                            comment_delimiter,
 4487                            doc_delimiter,
 4488                            insert_extra_newline,
 4489                            indent_on_newline,
 4490                            indent_on_extra_newline,
 4491                        ) = if let Some(language) = &language_scope {
 4492                            let mut insert_extra_newline =
 4493                                insert_extra_newline_brackets(&buffer, start..end, language)
 4494                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4495
 4496                            // Comment extension on newline is allowed only for cursor selections
 4497                            let comment_delimiter = maybe!({
 4498                                if !selection_is_empty {
 4499                                    return None;
 4500                                }
 4501
 4502                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4503                                    return None;
 4504                                }
 4505
 4506                                let delimiters = language.line_comment_prefixes();
 4507                                let max_len_of_delimiter =
 4508                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4509                                let (snapshot, range) =
 4510                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4511
 4512                                let num_of_whitespaces = snapshot
 4513                                    .chars_for_range(range.clone())
 4514                                    .take_while(|c| c.is_whitespace())
 4515                                    .count();
 4516                                let comment_candidate = snapshot
 4517                                    .chars_for_range(range.clone())
 4518                                    .skip(num_of_whitespaces)
 4519                                    .take(max_len_of_delimiter)
 4520                                    .collect::<String>();
 4521                                let (delimiter, trimmed_len) = delimiters
 4522                                    .iter()
 4523                                    .filter_map(|delimiter| {
 4524                                        let prefix = delimiter.trim_end();
 4525                                        if comment_candidate.starts_with(prefix) {
 4526                                            Some((delimiter, prefix.len()))
 4527                                        } else {
 4528                                            None
 4529                                        }
 4530                                    })
 4531                                    .max_by_key(|(_, len)| *len)?;
 4532
 4533                                if let Some(BlockCommentConfig {
 4534                                    start: block_start, ..
 4535                                }) = language.block_comment()
 4536                                {
 4537                                    let block_start_trimmed = block_start.trim_end();
 4538                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4539                                        let line_content = snapshot
 4540                                            .chars_for_range(range)
 4541                                            .skip(num_of_whitespaces)
 4542                                            .take(block_start_trimmed.len())
 4543                                            .collect::<String>();
 4544
 4545                                        if line_content.starts_with(block_start_trimmed) {
 4546                                            return None;
 4547                                        }
 4548                                    }
 4549                                }
 4550
 4551                                let cursor_is_placed_after_comment_marker =
 4552                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4553                                if cursor_is_placed_after_comment_marker {
 4554                                    Some(delimiter.clone())
 4555                                } else {
 4556                                    None
 4557                                }
 4558                            });
 4559
 4560                            let mut indent_on_newline = IndentSize::spaces(0);
 4561                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4562
 4563                            let doc_delimiter = maybe!({
 4564                                if !selection_is_empty {
 4565                                    return None;
 4566                                }
 4567
 4568                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4569                                    return None;
 4570                                }
 4571
 4572                                let BlockCommentConfig {
 4573                                    start: start_tag,
 4574                                    end: end_tag,
 4575                                    prefix: delimiter,
 4576                                    tab_size: len,
 4577                                } = language.documentation_comment()?;
 4578                                let is_within_block_comment = buffer
 4579                                    .language_scope_at(start_point)
 4580                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4581                                if !is_within_block_comment {
 4582                                    return None;
 4583                                }
 4584
 4585                                let (snapshot, range) =
 4586                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4587
 4588                                let num_of_whitespaces = snapshot
 4589                                    .chars_for_range(range.clone())
 4590                                    .take_while(|c| c.is_whitespace())
 4591                                    .count();
 4592
 4593                                // 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.
 4594                                let column = start_point.column;
 4595                                let cursor_is_after_start_tag = {
 4596                                    let start_tag_len = start_tag.len();
 4597                                    let start_tag_line = snapshot
 4598                                        .chars_for_range(range.clone())
 4599                                        .skip(num_of_whitespaces)
 4600                                        .take(start_tag_len)
 4601                                        .collect::<String>();
 4602                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4603                                        num_of_whitespaces + start_tag_len <= column as usize
 4604                                    } else {
 4605                                        false
 4606                                    }
 4607                                };
 4608
 4609                                let cursor_is_after_delimiter = {
 4610                                    let delimiter_trim = delimiter.trim_end();
 4611                                    let delimiter_line = snapshot
 4612                                        .chars_for_range(range.clone())
 4613                                        .skip(num_of_whitespaces)
 4614                                        .take(delimiter_trim.len())
 4615                                        .collect::<String>();
 4616                                    if delimiter_line.starts_with(delimiter_trim) {
 4617                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4618                                    } else {
 4619                                        false
 4620                                    }
 4621                                };
 4622
 4623                                let cursor_is_before_end_tag_if_exists = {
 4624                                    let mut char_position = 0u32;
 4625                                    let mut end_tag_offset = None;
 4626
 4627                                    'outer: for chunk in snapshot.text_for_range(range) {
 4628                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4629                                            let chars_before_match =
 4630                                                chunk[..byte_pos].chars().count() as u32;
 4631                                            end_tag_offset =
 4632                                                Some(char_position + chars_before_match);
 4633                                            break 'outer;
 4634                                        }
 4635                                        char_position += chunk.chars().count() as u32;
 4636                                    }
 4637
 4638                                    if let Some(end_tag_offset) = end_tag_offset {
 4639                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4640                                        if cursor_is_after_start_tag {
 4641                                            if cursor_is_before_end_tag {
 4642                                                insert_extra_newline = true;
 4643                                            }
 4644                                            let cursor_is_at_start_of_end_tag =
 4645                                                column == end_tag_offset;
 4646                                            if cursor_is_at_start_of_end_tag {
 4647                                                indent_on_extra_newline.len = *len;
 4648                                            }
 4649                                        }
 4650                                        cursor_is_before_end_tag
 4651                                    } else {
 4652                                        true
 4653                                    }
 4654                                };
 4655
 4656                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4657                                    && cursor_is_before_end_tag_if_exists
 4658                                {
 4659                                    if cursor_is_after_start_tag {
 4660                                        indent_on_newline.len = *len;
 4661                                    }
 4662                                    Some(delimiter.clone())
 4663                                } else {
 4664                                    None
 4665                                }
 4666                            });
 4667
 4668                            (
 4669                                comment_delimiter,
 4670                                doc_delimiter,
 4671                                insert_extra_newline,
 4672                                indent_on_newline,
 4673                                indent_on_extra_newline,
 4674                            )
 4675                        } else {
 4676                            (
 4677                                None,
 4678                                None,
 4679                                false,
 4680                                IndentSize::default(),
 4681                                IndentSize::default(),
 4682                            )
 4683                        };
 4684
 4685                        let prevent_auto_indent = doc_delimiter.is_some();
 4686                        let delimiter = comment_delimiter.or(doc_delimiter);
 4687
 4688                        let capacity_for_delimiter =
 4689                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4690                        let mut new_text = String::with_capacity(
 4691                            1 + capacity_for_delimiter
 4692                                + existing_indent.len as usize
 4693                                + indent_on_newline.len as usize
 4694                                + indent_on_extra_newline.len as usize,
 4695                        );
 4696                        new_text.push('\n');
 4697                        new_text.extend(existing_indent.chars());
 4698                        new_text.extend(indent_on_newline.chars());
 4699
 4700                        if let Some(delimiter) = &delimiter {
 4701                            new_text.push_str(delimiter);
 4702                        }
 4703
 4704                        if insert_extra_newline {
 4705                            new_text.push('\n');
 4706                            new_text.extend(existing_indent.chars());
 4707                            new_text.extend(indent_on_extra_newline.chars());
 4708                        }
 4709
 4710                        let anchor = buffer.anchor_after(end);
 4711                        let new_selection = selection.map(|_| anchor);
 4712                        (
 4713                            ((start..end, new_text), prevent_auto_indent),
 4714                            (insert_extra_newline, new_selection),
 4715                        )
 4716                    })
 4717                    .unzip()
 4718            };
 4719
 4720            let mut auto_indent_edits = Vec::new();
 4721            let mut edits = Vec::new();
 4722            for (edit, prevent_auto_indent) in edits_with_flags {
 4723                if prevent_auto_indent {
 4724                    edits.push(edit);
 4725                } else {
 4726                    auto_indent_edits.push(edit);
 4727                }
 4728            }
 4729            if !edits.is_empty() {
 4730                this.edit(edits, cx);
 4731            }
 4732            if !auto_indent_edits.is_empty() {
 4733                this.edit_with_autoindent(auto_indent_edits, cx);
 4734            }
 4735
 4736            let buffer = this.buffer.read(cx).snapshot(cx);
 4737            let new_selections = selection_info
 4738                .into_iter()
 4739                .map(|(extra_newline_inserted, new_selection)| {
 4740                    let mut cursor = new_selection.end.to_point(&buffer);
 4741                    if extra_newline_inserted {
 4742                        cursor.row -= 1;
 4743                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4744                    }
 4745                    new_selection.map(|_| cursor)
 4746                })
 4747                .collect();
 4748
 4749            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4750            this.refresh_edit_prediction(true, false, window, cx);
 4751        });
 4752    }
 4753
 4754    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4755        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4756
 4757        let buffer = self.buffer.read(cx);
 4758        let snapshot = buffer.snapshot(cx);
 4759
 4760        let mut edits = Vec::new();
 4761        let mut rows = Vec::new();
 4762
 4763        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4764            let cursor = selection.head();
 4765            let row = cursor.row;
 4766
 4767            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4768
 4769            let newline = "\n".to_string();
 4770            edits.push((start_of_line..start_of_line, newline));
 4771
 4772            rows.push(row + rows_inserted as u32);
 4773        }
 4774
 4775        self.transact(window, cx, |editor, window, cx| {
 4776            editor.edit(edits, cx);
 4777
 4778            editor.change_selections(Default::default(), window, cx, |s| {
 4779                let mut index = 0;
 4780                s.move_cursors_with(|map, _, _| {
 4781                    let row = rows[index];
 4782                    index += 1;
 4783
 4784                    let point = Point::new(row, 0);
 4785                    let boundary = map.next_line_boundary(point).1;
 4786                    let clipped = map.clip_point(boundary, Bias::Left);
 4787
 4788                    (clipped, SelectionGoal::None)
 4789                });
 4790            });
 4791
 4792            let mut indent_edits = Vec::new();
 4793            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4794            for row in rows {
 4795                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4796                for (row, indent) in indents {
 4797                    if indent.len == 0 {
 4798                        continue;
 4799                    }
 4800
 4801                    let text = match indent.kind {
 4802                        IndentKind::Space => " ".repeat(indent.len as usize),
 4803                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4804                    };
 4805                    let point = Point::new(row.0, 0);
 4806                    indent_edits.push((point..point, text));
 4807                }
 4808            }
 4809            editor.edit(indent_edits, cx);
 4810        });
 4811    }
 4812
 4813    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4814        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4815
 4816        let buffer = self.buffer.read(cx);
 4817        let snapshot = buffer.snapshot(cx);
 4818
 4819        let mut edits = Vec::new();
 4820        let mut rows = Vec::new();
 4821        let mut rows_inserted = 0;
 4822
 4823        for selection in self.selections.all_adjusted(cx) {
 4824            let cursor = selection.head();
 4825            let row = cursor.row;
 4826
 4827            let point = Point::new(row + 1, 0);
 4828            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4829
 4830            let newline = "\n".to_string();
 4831            edits.push((start_of_line..start_of_line, newline));
 4832
 4833            rows_inserted += 1;
 4834            rows.push(row + rows_inserted);
 4835        }
 4836
 4837        self.transact(window, cx, |editor, window, cx| {
 4838            editor.edit(edits, cx);
 4839
 4840            editor.change_selections(Default::default(), window, cx, |s| {
 4841                let mut index = 0;
 4842                s.move_cursors_with(|map, _, _| {
 4843                    let row = rows[index];
 4844                    index += 1;
 4845
 4846                    let point = Point::new(row, 0);
 4847                    let boundary = map.next_line_boundary(point).1;
 4848                    let clipped = map.clip_point(boundary, Bias::Left);
 4849
 4850                    (clipped, SelectionGoal::None)
 4851                });
 4852            });
 4853
 4854            let mut indent_edits = Vec::new();
 4855            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4856            for row in rows {
 4857                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4858                for (row, indent) in indents {
 4859                    if indent.len == 0 {
 4860                        continue;
 4861                    }
 4862
 4863                    let text = match indent.kind {
 4864                        IndentKind::Space => " ".repeat(indent.len as usize),
 4865                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4866                    };
 4867                    let point = Point::new(row.0, 0);
 4868                    indent_edits.push((point..point, text));
 4869                }
 4870            }
 4871            editor.edit(indent_edits, cx);
 4872        });
 4873    }
 4874
 4875    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4876        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4877            original_indent_columns: Vec::new(),
 4878        });
 4879        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4880    }
 4881
 4882    fn insert_with_autoindent_mode(
 4883        &mut self,
 4884        text: &str,
 4885        autoindent_mode: Option<AutoindentMode>,
 4886        window: &mut Window,
 4887        cx: &mut Context<Self>,
 4888    ) {
 4889        if self.read_only(cx) {
 4890            return;
 4891        }
 4892
 4893        let text: Arc<str> = text.into();
 4894        self.transact(window, cx, |this, window, cx| {
 4895            let old_selections = this.selections.all_adjusted(cx);
 4896            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4897                let anchors = {
 4898                    let snapshot = buffer.read(cx);
 4899                    old_selections
 4900                        .iter()
 4901                        .map(|s| {
 4902                            let anchor = snapshot.anchor_after(s.head());
 4903                            s.map(|_| anchor)
 4904                        })
 4905                        .collect::<Vec<_>>()
 4906                };
 4907                buffer.edit(
 4908                    old_selections
 4909                        .iter()
 4910                        .map(|s| (s.start..s.end, text.clone())),
 4911                    autoindent_mode,
 4912                    cx,
 4913                );
 4914                anchors
 4915            });
 4916
 4917            this.change_selections(Default::default(), window, cx, |s| {
 4918                s.select_anchors(selection_anchors);
 4919            });
 4920
 4921            cx.notify();
 4922        });
 4923    }
 4924
 4925    fn trigger_completion_on_input(
 4926        &mut self,
 4927        text: &str,
 4928        trigger_in_words: bool,
 4929        window: &mut Window,
 4930        cx: &mut Context<Self>,
 4931    ) {
 4932        let completions_source = self
 4933            .context_menu
 4934            .borrow()
 4935            .as_ref()
 4936            .and_then(|menu| match menu {
 4937                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4938                CodeContextMenu::CodeActions(_) => None,
 4939            });
 4940
 4941        match completions_source {
 4942            Some(CompletionsMenuSource::Words { .. }) => {
 4943                self.open_or_update_completions_menu(
 4944                    Some(CompletionsMenuSource::Words {
 4945                        ignore_threshold: false,
 4946                    }),
 4947                    None,
 4948                    window,
 4949                    cx,
 4950                );
 4951            }
 4952            Some(CompletionsMenuSource::Normal)
 4953            | Some(CompletionsMenuSource::SnippetChoices)
 4954            | None
 4955                if self.is_completion_trigger(
 4956                    text,
 4957                    trigger_in_words,
 4958                    completions_source.is_some(),
 4959                    cx,
 4960                ) =>
 4961            {
 4962                self.show_completions(
 4963                    &ShowCompletions {
 4964                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4965                    },
 4966                    window,
 4967                    cx,
 4968                )
 4969            }
 4970            _ => {
 4971                self.hide_context_menu(window, cx);
 4972            }
 4973        }
 4974    }
 4975
 4976    fn is_completion_trigger(
 4977        &self,
 4978        text: &str,
 4979        trigger_in_words: bool,
 4980        menu_is_open: bool,
 4981        cx: &mut Context<Self>,
 4982    ) -> bool {
 4983        let position = self.selections.newest_anchor().head();
 4984        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4985            return false;
 4986        };
 4987
 4988        if let Some(completion_provider) = &self.completion_provider {
 4989            completion_provider.is_completion_trigger(
 4990                &buffer,
 4991                position.text_anchor,
 4992                text,
 4993                trigger_in_words,
 4994                menu_is_open,
 4995                cx,
 4996            )
 4997        } else {
 4998            false
 4999        }
 5000    }
 5001
 5002    /// If any empty selections is touching the start of its innermost containing autoclose
 5003    /// region, expand it to select the brackets.
 5004    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5005        let selections = self.selections.all::<usize>(cx);
 5006        let buffer = self.buffer.read(cx).read(cx);
 5007        let new_selections = self
 5008            .selections_with_autoclose_regions(selections, &buffer)
 5009            .map(|(mut selection, region)| {
 5010                if !selection.is_empty() {
 5011                    return selection;
 5012                }
 5013
 5014                if let Some(region) = region {
 5015                    let mut range = region.range.to_offset(&buffer);
 5016                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5017                        range.start -= region.pair.start.len();
 5018                        if buffer.contains_str_at(range.start, &region.pair.start)
 5019                            && buffer.contains_str_at(range.end, &region.pair.end)
 5020                        {
 5021                            range.end += region.pair.end.len();
 5022                            selection.start = range.start;
 5023                            selection.end = range.end;
 5024
 5025                            return selection;
 5026                        }
 5027                    }
 5028                }
 5029
 5030                let always_treat_brackets_as_autoclosed = buffer
 5031                    .language_settings_at(selection.start, cx)
 5032                    .always_treat_brackets_as_autoclosed;
 5033
 5034                if !always_treat_brackets_as_autoclosed {
 5035                    return selection;
 5036                }
 5037
 5038                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5039                    for (pair, enabled) in scope.brackets() {
 5040                        if !enabled || !pair.close {
 5041                            continue;
 5042                        }
 5043
 5044                        if buffer.contains_str_at(selection.start, &pair.end) {
 5045                            let pair_start_len = pair.start.len();
 5046                            if buffer.contains_str_at(
 5047                                selection.start.saturating_sub(pair_start_len),
 5048                                &pair.start,
 5049                            ) {
 5050                                selection.start -= pair_start_len;
 5051                                selection.end += pair.end.len();
 5052
 5053                                return selection;
 5054                            }
 5055                        }
 5056                    }
 5057                }
 5058
 5059                selection
 5060            })
 5061            .collect();
 5062
 5063        drop(buffer);
 5064        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5065            selections.select(new_selections)
 5066        });
 5067    }
 5068
 5069    /// Iterate the given selections, and for each one, find the smallest surrounding
 5070    /// autoclose region. This uses the ordering of the selections and the autoclose
 5071    /// regions to avoid repeated comparisons.
 5072    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5073        &'a self,
 5074        selections: impl IntoIterator<Item = Selection<D>>,
 5075        buffer: &'a MultiBufferSnapshot,
 5076    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5077        let mut i = 0;
 5078        let mut regions = self.autoclose_regions.as_slice();
 5079        selections.into_iter().map(move |selection| {
 5080            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5081
 5082            let mut enclosing = None;
 5083            while let Some(pair_state) = regions.get(i) {
 5084                if pair_state.range.end.to_offset(buffer) < range.start {
 5085                    regions = &regions[i + 1..];
 5086                    i = 0;
 5087                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5088                    break;
 5089                } else {
 5090                    if pair_state.selection_id == selection.id {
 5091                        enclosing = Some(pair_state);
 5092                    }
 5093                    i += 1;
 5094                }
 5095            }
 5096
 5097            (selection, enclosing)
 5098        })
 5099    }
 5100
 5101    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5102    fn invalidate_autoclose_regions(
 5103        &mut self,
 5104        mut selections: &[Selection<Anchor>],
 5105        buffer: &MultiBufferSnapshot,
 5106    ) {
 5107        self.autoclose_regions.retain(|state| {
 5108            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5109                return false;
 5110            }
 5111
 5112            let mut i = 0;
 5113            while let Some(selection) = selections.get(i) {
 5114                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5115                    selections = &selections[1..];
 5116                    continue;
 5117                }
 5118                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5119                    break;
 5120                }
 5121                if selection.id == state.selection_id {
 5122                    return true;
 5123                } else {
 5124                    i += 1;
 5125                }
 5126            }
 5127            false
 5128        });
 5129    }
 5130
 5131    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5132        let offset = position.to_offset(buffer);
 5133        let (word_range, kind) =
 5134            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5135        if offset > word_range.start && kind == Some(CharKind::Word) {
 5136            Some(
 5137                buffer
 5138                    .text_for_range(word_range.start..offset)
 5139                    .collect::<String>(),
 5140            )
 5141        } else {
 5142            None
 5143        }
 5144    }
 5145
 5146    pub fn toggle_inline_values(
 5147        &mut self,
 5148        _: &ToggleInlineValues,
 5149        _: &mut Window,
 5150        cx: &mut Context<Self>,
 5151    ) {
 5152        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5153
 5154        self.refresh_inline_values(cx);
 5155    }
 5156
 5157    pub fn toggle_inlay_hints(
 5158        &mut self,
 5159        _: &ToggleInlayHints,
 5160        _: &mut Window,
 5161        cx: &mut Context<Self>,
 5162    ) {
 5163        self.refresh_inlay_hints(
 5164            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5165            cx,
 5166        );
 5167    }
 5168
 5169    pub fn inlay_hints_enabled(&self) -> bool {
 5170        self.inlay_hint_cache.enabled
 5171    }
 5172
 5173    pub fn inline_values_enabled(&self) -> bool {
 5174        self.inline_value_cache.enabled
 5175    }
 5176
 5177    #[cfg(any(test, feature = "test-support"))]
 5178    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5179        self.display_map
 5180            .read(cx)
 5181            .current_inlays()
 5182            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5183            .cloned()
 5184            .collect()
 5185    }
 5186
 5187    #[cfg(any(test, feature = "test-support"))]
 5188    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5189        self.display_map
 5190            .read(cx)
 5191            .current_inlays()
 5192            .cloned()
 5193            .collect()
 5194    }
 5195
 5196    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5197        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5198            return;
 5199        }
 5200
 5201        let reason_description = reason.description();
 5202        let ignore_debounce = matches!(
 5203            reason,
 5204            InlayHintRefreshReason::SettingsChange(_)
 5205                | InlayHintRefreshReason::Toggle(_)
 5206                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5207                | InlayHintRefreshReason::ModifiersChanged(_)
 5208        );
 5209        let (invalidate_cache, required_languages) = match reason {
 5210            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5211                match self.inlay_hint_cache.modifiers_override(enabled) {
 5212                    Some(enabled) => {
 5213                        if enabled {
 5214                            (InvalidationStrategy::RefreshRequested, None)
 5215                        } else {
 5216                            self.splice_inlays(
 5217                                &self
 5218                                    .visible_inlay_hints(cx)
 5219                                    .iter()
 5220                                    .map(|inlay| inlay.id)
 5221                                    .collect::<Vec<InlayId>>(),
 5222                                Vec::new(),
 5223                                cx,
 5224                            );
 5225                            return;
 5226                        }
 5227                    }
 5228                    None => return,
 5229                }
 5230            }
 5231            InlayHintRefreshReason::Toggle(enabled) => {
 5232                if self.inlay_hint_cache.toggle(enabled) {
 5233                    if enabled {
 5234                        (InvalidationStrategy::RefreshRequested, None)
 5235                    } else {
 5236                        self.splice_inlays(
 5237                            &self
 5238                                .visible_inlay_hints(cx)
 5239                                .iter()
 5240                                .map(|inlay| inlay.id)
 5241                                .collect::<Vec<InlayId>>(),
 5242                            Vec::new(),
 5243                            cx,
 5244                        );
 5245                        return;
 5246                    }
 5247                } else {
 5248                    return;
 5249                }
 5250            }
 5251            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5252                match self.inlay_hint_cache.update_settings(
 5253                    &self.buffer,
 5254                    new_settings,
 5255                    self.visible_inlay_hints(cx),
 5256                    cx,
 5257                ) {
 5258                    ControlFlow::Break(Some(InlaySplice {
 5259                        to_remove,
 5260                        to_insert,
 5261                    })) => {
 5262                        self.splice_inlays(&to_remove, to_insert, cx);
 5263                        return;
 5264                    }
 5265                    ControlFlow::Break(None) => return,
 5266                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5267                }
 5268            }
 5269            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5270                if let Some(InlaySplice {
 5271                    to_remove,
 5272                    to_insert,
 5273                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5274                {
 5275                    self.splice_inlays(&to_remove, to_insert, cx);
 5276                }
 5277                self.display_map.update(cx, |display_map, _| {
 5278                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5279                });
 5280                return;
 5281            }
 5282            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5283            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5284                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5285            }
 5286            InlayHintRefreshReason::RefreshRequested => {
 5287                (InvalidationStrategy::RefreshRequested, None)
 5288            }
 5289        };
 5290
 5291        if let Some(InlaySplice {
 5292            to_remove,
 5293            to_insert,
 5294        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5295            reason_description,
 5296            self.visible_excerpts(required_languages.as_ref(), cx),
 5297            invalidate_cache,
 5298            ignore_debounce,
 5299            cx,
 5300        ) {
 5301            self.splice_inlays(&to_remove, to_insert, cx);
 5302        }
 5303    }
 5304
 5305    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5306        self.display_map
 5307            .read(cx)
 5308            .current_inlays()
 5309            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5310            .cloned()
 5311            .collect()
 5312    }
 5313
 5314    pub fn visible_excerpts(
 5315        &self,
 5316        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5317        cx: &mut Context<Editor>,
 5318    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5319        let Some(project) = self.project() else {
 5320            return HashMap::default();
 5321        };
 5322        let project = project.read(cx);
 5323        let multi_buffer = self.buffer().read(cx);
 5324        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5325        let multi_buffer_visible_start = self
 5326            .scroll_manager
 5327            .anchor()
 5328            .anchor
 5329            .to_point(&multi_buffer_snapshot);
 5330        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5331            multi_buffer_visible_start
 5332                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5333            Bias::Left,
 5334        );
 5335        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5336        multi_buffer_snapshot
 5337            .range_to_buffer_ranges(multi_buffer_visible_range)
 5338            .into_iter()
 5339            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5340            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5341                let buffer_file = project::File::from_dyn(buffer.file())?;
 5342                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5343                let worktree_entry = buffer_worktree
 5344                    .read(cx)
 5345                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5346                if worktree_entry.is_ignored {
 5347                    return None;
 5348                }
 5349
 5350                let language = buffer.language()?;
 5351                if let Some(restrict_to_languages) = restrict_to_languages
 5352                    && !restrict_to_languages.contains(language)
 5353                {
 5354                    return None;
 5355                }
 5356                Some((
 5357                    excerpt_id,
 5358                    (
 5359                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5360                        buffer.version().clone(),
 5361                        excerpt_visible_range,
 5362                    ),
 5363                ))
 5364            })
 5365            .collect()
 5366    }
 5367
 5368    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5369        TextLayoutDetails {
 5370            text_system: window.text_system().clone(),
 5371            editor_style: self.style.clone().unwrap(),
 5372            rem_size: window.rem_size(),
 5373            scroll_anchor: self.scroll_manager.anchor(),
 5374            visible_rows: self.visible_line_count(),
 5375            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5376        }
 5377    }
 5378
 5379    pub fn splice_inlays(
 5380        &self,
 5381        to_remove: &[InlayId],
 5382        to_insert: Vec<Inlay>,
 5383        cx: &mut Context<Self>,
 5384    ) {
 5385        self.display_map.update(cx, |display_map, cx| {
 5386            display_map.splice_inlays(to_remove, to_insert, cx)
 5387        });
 5388        cx.notify();
 5389    }
 5390
 5391    fn trigger_on_type_formatting(
 5392        &self,
 5393        input: String,
 5394        window: &mut Window,
 5395        cx: &mut Context<Self>,
 5396    ) -> Option<Task<Result<()>>> {
 5397        if input.len() != 1 {
 5398            return None;
 5399        }
 5400
 5401        let project = self.project()?;
 5402        let position = self.selections.newest_anchor().head();
 5403        let (buffer, buffer_position) = self
 5404            .buffer
 5405            .read(cx)
 5406            .text_anchor_for_position(position, cx)?;
 5407
 5408        let settings = language_settings::language_settings(
 5409            buffer
 5410                .read(cx)
 5411                .language_at(buffer_position)
 5412                .map(|l| l.name()),
 5413            buffer.read(cx).file(),
 5414            cx,
 5415        );
 5416        if !settings.use_on_type_format {
 5417            return None;
 5418        }
 5419
 5420        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5421        // hence we do LSP request & edit on host side only — add formats to host's history.
 5422        let push_to_lsp_host_history = true;
 5423        // If this is not the host, append its history with new edits.
 5424        let push_to_client_history = project.read(cx).is_via_collab();
 5425
 5426        let on_type_formatting = project.update(cx, |project, cx| {
 5427            project.on_type_format(
 5428                buffer.clone(),
 5429                buffer_position,
 5430                input,
 5431                push_to_lsp_host_history,
 5432                cx,
 5433            )
 5434        });
 5435        Some(cx.spawn_in(window, async move |editor, cx| {
 5436            if let Some(transaction) = on_type_formatting.await? {
 5437                if push_to_client_history {
 5438                    buffer
 5439                        .update(cx, |buffer, _| {
 5440                            buffer.push_transaction(transaction, Instant::now());
 5441                            buffer.finalize_last_transaction();
 5442                        })
 5443                        .ok();
 5444                }
 5445                editor.update(cx, |editor, cx| {
 5446                    editor.refresh_document_highlights(cx);
 5447                })?;
 5448            }
 5449            Ok(())
 5450        }))
 5451    }
 5452
 5453    pub fn show_word_completions(
 5454        &mut self,
 5455        _: &ShowWordCompletions,
 5456        window: &mut Window,
 5457        cx: &mut Context<Self>,
 5458    ) {
 5459        self.open_or_update_completions_menu(
 5460            Some(CompletionsMenuSource::Words {
 5461                ignore_threshold: true,
 5462            }),
 5463            None,
 5464            window,
 5465            cx,
 5466        );
 5467    }
 5468
 5469    pub fn show_completions(
 5470        &mut self,
 5471        options: &ShowCompletions,
 5472        window: &mut Window,
 5473        cx: &mut Context<Self>,
 5474    ) {
 5475        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5476    }
 5477
 5478    fn open_or_update_completions_menu(
 5479        &mut self,
 5480        requested_source: Option<CompletionsMenuSource>,
 5481        trigger: Option<&str>,
 5482        window: &mut Window,
 5483        cx: &mut Context<Self>,
 5484    ) {
 5485        if self.pending_rename.is_some() {
 5486            return;
 5487        }
 5488
 5489        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5490
 5491        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5492        // inserted and selected. To handle that case, the start of the selection is used so that
 5493        // the menu starts with all choices.
 5494        let position = self
 5495            .selections
 5496            .newest_anchor()
 5497            .start
 5498            .bias_right(&multibuffer_snapshot);
 5499        if position.diff_base_anchor.is_some() {
 5500            return;
 5501        }
 5502        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5503        let Some(buffer) = buffer_position
 5504            .buffer_id
 5505            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5506        else {
 5507            return;
 5508        };
 5509        let buffer_snapshot = buffer.read(cx).snapshot();
 5510
 5511        let query: Option<Arc<String>> =
 5512            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5513                .map(|query| query.into());
 5514
 5515        drop(multibuffer_snapshot);
 5516
 5517        // Hide the current completions menu when query is empty. Without this, cached
 5518        // completions from before the trigger char may be reused (#32774).
 5519        if query.is_none() {
 5520            let menu_is_open = matches!(
 5521                self.context_menu.borrow().as_ref(),
 5522                Some(CodeContextMenu::Completions(_))
 5523            );
 5524            if menu_is_open {
 5525                self.hide_context_menu(window, cx);
 5526            }
 5527        }
 5528
 5529        let mut ignore_word_threshold = false;
 5530        let provider = match requested_source {
 5531            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5532            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5533                ignore_word_threshold = ignore_threshold;
 5534                None
 5535            }
 5536            Some(CompletionsMenuSource::SnippetChoices) => {
 5537                log::error!("bug: SnippetChoices requested_source is not handled");
 5538                None
 5539            }
 5540        };
 5541
 5542        let sort_completions = provider
 5543            .as_ref()
 5544            .is_some_and(|provider| provider.sort_completions());
 5545
 5546        let filter_completions = provider
 5547            .as_ref()
 5548            .is_none_or(|provider| provider.filter_completions());
 5549
 5550        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5551            if filter_completions {
 5552                menu.filter(query.clone(), provider.clone(), window, cx);
 5553            }
 5554            // When `is_incomplete` is false, no need to re-query completions when the current query
 5555            // is a suffix of the initial query.
 5556            if !menu.is_incomplete {
 5557                // If the new query is a suffix of the old query (typing more characters) and
 5558                // the previous result was complete, the existing completions can be filtered.
 5559                //
 5560                // Note that this is always true for snippet completions.
 5561                let query_matches = match (&menu.initial_query, &query) {
 5562                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5563                    (None, _) => true,
 5564                    _ => false,
 5565                };
 5566                if query_matches {
 5567                    let position_matches = if menu.initial_position == position {
 5568                        true
 5569                    } else {
 5570                        let snapshot = self.buffer.read(cx).read(cx);
 5571                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5572                    };
 5573                    if position_matches {
 5574                        return;
 5575                    }
 5576                }
 5577            }
 5578        };
 5579
 5580        let trigger_kind = match trigger {
 5581            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5582                CompletionTriggerKind::TRIGGER_CHARACTER
 5583            }
 5584            _ => CompletionTriggerKind::INVOKED,
 5585        };
 5586        let completion_context = CompletionContext {
 5587            trigger_character: trigger.and_then(|trigger| {
 5588                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5589                    Some(String::from(trigger))
 5590                } else {
 5591                    None
 5592                }
 5593            }),
 5594            trigger_kind,
 5595        };
 5596
 5597        let Anchor {
 5598            excerpt_id: buffer_excerpt_id,
 5599            text_anchor: buffer_position,
 5600            ..
 5601        } = buffer_position;
 5602
 5603        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5604            buffer_snapshot.surrounding_word(buffer_position, None)
 5605        {
 5606            let word_to_exclude = buffer_snapshot
 5607                .text_for_range(word_range.clone())
 5608                .collect::<String>();
 5609            (
 5610                buffer_snapshot.anchor_before(word_range.start)
 5611                    ..buffer_snapshot.anchor_after(buffer_position),
 5612                Some(word_to_exclude),
 5613            )
 5614        } else {
 5615            (buffer_position..buffer_position, None)
 5616        };
 5617
 5618        let language = buffer_snapshot
 5619            .language_at(buffer_position)
 5620            .map(|language| language.name());
 5621
 5622        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5623            .completions
 5624            .clone();
 5625
 5626        let show_completion_documentation = buffer_snapshot
 5627            .settings_at(buffer_position, cx)
 5628            .show_completion_documentation;
 5629
 5630        // The document can be large, so stay in reasonable bounds when searching for words,
 5631        // otherwise completion pop-up might be slow to appear.
 5632        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5633        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5634        let min_word_search = buffer_snapshot.clip_point(
 5635            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5636            Bias::Left,
 5637        );
 5638        let max_word_search = buffer_snapshot.clip_point(
 5639            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5640            Bias::Right,
 5641        );
 5642        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5643            ..buffer_snapshot.point_to_offset(max_word_search);
 5644
 5645        let skip_digits = query
 5646            .as_ref()
 5647            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5648
 5649        let omit_word_completions = !self.word_completions_enabled
 5650            || (!ignore_word_threshold
 5651                && match &query {
 5652                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5653                    None => completion_settings.words_min_length != 0,
 5654                });
 5655
 5656        let (mut words, provider_responses) = match &provider {
 5657            Some(provider) => {
 5658                let provider_responses = provider.completions(
 5659                    buffer_excerpt_id,
 5660                    &buffer,
 5661                    buffer_position,
 5662                    completion_context,
 5663                    window,
 5664                    cx,
 5665                );
 5666
 5667                let words = match (omit_word_completions, completion_settings.words) {
 5668                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5669                        Task::ready(BTreeMap::default())
 5670                    }
 5671                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5672                        .background_spawn(async move {
 5673                            buffer_snapshot.words_in_range(WordsQuery {
 5674                                fuzzy_contents: None,
 5675                                range: word_search_range,
 5676                                skip_digits,
 5677                            })
 5678                        }),
 5679                };
 5680
 5681                (words, provider_responses)
 5682            }
 5683            None => {
 5684                let words = if omit_word_completions {
 5685                    Task::ready(BTreeMap::default())
 5686                } else {
 5687                    cx.background_spawn(async move {
 5688                        buffer_snapshot.words_in_range(WordsQuery {
 5689                            fuzzy_contents: None,
 5690                            range: word_search_range,
 5691                            skip_digits,
 5692                        })
 5693                    })
 5694                };
 5695                (words, Task::ready(Ok(Vec::new())))
 5696            }
 5697        };
 5698
 5699        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5700
 5701        let id = post_inc(&mut self.next_completion_id);
 5702        let task = cx.spawn_in(window, async move |editor, cx| {
 5703            let Ok(()) = editor.update(cx, |this, _| {
 5704                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5705            }) else {
 5706                return;
 5707            };
 5708
 5709            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5710            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5711            let mut completions = Vec::new();
 5712            let mut is_incomplete = false;
 5713            let mut display_options: Option<CompletionDisplayOptions> = None;
 5714            if let Some(provider_responses) = provider_responses.await.log_err()
 5715                && !provider_responses.is_empty()
 5716            {
 5717                for response in provider_responses {
 5718                    completions.extend(response.completions);
 5719                    is_incomplete = is_incomplete || response.is_incomplete;
 5720                    match display_options.as_mut() {
 5721                        None => {
 5722                            display_options = Some(response.display_options);
 5723                        }
 5724                        Some(options) => options.merge(&response.display_options),
 5725                    }
 5726                }
 5727                if completion_settings.words == WordsCompletionMode::Fallback {
 5728                    words = Task::ready(BTreeMap::default());
 5729                }
 5730            }
 5731            let display_options = display_options.unwrap_or_default();
 5732
 5733            let mut words = words.await;
 5734            if let Some(word_to_exclude) = &word_to_exclude {
 5735                words.remove(word_to_exclude);
 5736            }
 5737            for lsp_completion in &completions {
 5738                words.remove(&lsp_completion.new_text);
 5739            }
 5740            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5741                replace_range: word_replace_range.clone(),
 5742                new_text: word.clone(),
 5743                label: CodeLabel::plain(word, None),
 5744                icon_path: None,
 5745                documentation: None,
 5746                source: CompletionSource::BufferWord {
 5747                    word_range,
 5748                    resolved: false,
 5749                },
 5750                insert_text_mode: Some(InsertTextMode::AS_IS),
 5751                confirm: None,
 5752            }));
 5753
 5754            let menu = if completions.is_empty() {
 5755                None
 5756            } else {
 5757                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5758                    let languages = editor
 5759                        .workspace
 5760                        .as_ref()
 5761                        .and_then(|(workspace, _)| workspace.upgrade())
 5762                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5763                    let menu = CompletionsMenu::new(
 5764                        id,
 5765                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5766                        sort_completions,
 5767                        show_completion_documentation,
 5768                        position,
 5769                        query.clone(),
 5770                        is_incomplete,
 5771                        buffer.clone(),
 5772                        completions.into(),
 5773                        display_options,
 5774                        snippet_sort_order,
 5775                        languages,
 5776                        language,
 5777                        cx,
 5778                    );
 5779
 5780                    let query = if filter_completions { query } else { None };
 5781                    let matches_task = if let Some(query) = query {
 5782                        menu.do_async_filtering(query, cx)
 5783                    } else {
 5784                        Task::ready(menu.unfiltered_matches())
 5785                    };
 5786                    (menu, matches_task)
 5787                }) else {
 5788                    return;
 5789                };
 5790
 5791                let matches = matches_task.await;
 5792
 5793                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5794                    // Newer menu already set, so exit.
 5795                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5796                        editor.context_menu.borrow().as_ref()
 5797                        && prev_menu.id > id
 5798                    {
 5799                        return;
 5800                    };
 5801
 5802                    // Only valid to take prev_menu because it the new menu is immediately set
 5803                    // below, or the menu is hidden.
 5804                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5805                        editor.context_menu.borrow_mut().take()
 5806                    {
 5807                        let position_matches =
 5808                            if prev_menu.initial_position == menu.initial_position {
 5809                                true
 5810                            } else {
 5811                                let snapshot = editor.buffer.read(cx).read(cx);
 5812                                prev_menu.initial_position.to_offset(&snapshot)
 5813                                    == menu.initial_position.to_offset(&snapshot)
 5814                            };
 5815                        if position_matches {
 5816                            // Preserve markdown cache before `set_filter_results` because it will
 5817                            // try to populate the documentation cache.
 5818                            menu.preserve_markdown_cache(prev_menu);
 5819                        }
 5820                    };
 5821
 5822                    menu.set_filter_results(matches, provider, window, cx);
 5823                }) else {
 5824                    return;
 5825                };
 5826
 5827                menu.visible().then_some(menu)
 5828            };
 5829
 5830            editor
 5831                .update_in(cx, |editor, window, cx| {
 5832                    if editor.focus_handle.is_focused(window)
 5833                        && let Some(menu) = menu
 5834                    {
 5835                        *editor.context_menu.borrow_mut() =
 5836                            Some(CodeContextMenu::Completions(menu));
 5837
 5838                        crate::hover_popover::hide_hover(editor, cx);
 5839                        if editor.show_edit_predictions_in_menu() {
 5840                            editor.update_visible_edit_prediction(window, cx);
 5841                        } else {
 5842                            editor.discard_edit_prediction(false, cx);
 5843                        }
 5844
 5845                        cx.notify();
 5846                        return;
 5847                    }
 5848
 5849                    if editor.completion_tasks.len() <= 1 {
 5850                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5851                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5852                        // If it was already hidden and we don't show edit predictions in the menu,
 5853                        // we should also show the edit prediction when available.
 5854                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5855                            editor.update_visible_edit_prediction(window, cx);
 5856                        }
 5857                    }
 5858                })
 5859                .ok();
 5860        });
 5861
 5862        self.completion_tasks.push((id, task));
 5863    }
 5864
 5865    #[cfg(feature = "test-support")]
 5866    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5867        let menu = self.context_menu.borrow();
 5868        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5869            let completions = menu.completions.borrow();
 5870            Some(completions.to_vec())
 5871        } else {
 5872            None
 5873        }
 5874    }
 5875
 5876    pub fn with_completions_menu_matching_id<R>(
 5877        &self,
 5878        id: CompletionId,
 5879        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5880    ) -> R {
 5881        let mut context_menu = self.context_menu.borrow_mut();
 5882        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5883            return f(None);
 5884        };
 5885        if completions_menu.id != id {
 5886            return f(None);
 5887        }
 5888        f(Some(completions_menu))
 5889    }
 5890
 5891    pub fn confirm_completion(
 5892        &mut self,
 5893        action: &ConfirmCompletion,
 5894        window: &mut Window,
 5895        cx: &mut Context<Self>,
 5896    ) -> Option<Task<Result<()>>> {
 5897        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5898        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5899    }
 5900
 5901    pub fn confirm_completion_insert(
 5902        &mut self,
 5903        _: &ConfirmCompletionInsert,
 5904        window: &mut Window,
 5905        cx: &mut Context<Self>,
 5906    ) -> Option<Task<Result<()>>> {
 5907        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5908        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5909    }
 5910
 5911    pub fn confirm_completion_replace(
 5912        &mut self,
 5913        _: &ConfirmCompletionReplace,
 5914        window: &mut Window,
 5915        cx: &mut Context<Self>,
 5916    ) -> Option<Task<Result<()>>> {
 5917        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5918        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5919    }
 5920
 5921    pub fn compose_completion(
 5922        &mut self,
 5923        action: &ComposeCompletion,
 5924        window: &mut Window,
 5925        cx: &mut Context<Self>,
 5926    ) -> Option<Task<Result<()>>> {
 5927        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5928        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5929    }
 5930
 5931    fn do_completion(
 5932        &mut self,
 5933        item_ix: Option<usize>,
 5934        intent: CompletionIntent,
 5935        window: &mut Window,
 5936        cx: &mut Context<Editor>,
 5937    ) -> Option<Task<Result<()>>> {
 5938        use language::ToOffset as _;
 5939
 5940        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5941        else {
 5942            return None;
 5943        };
 5944
 5945        let candidate_id = {
 5946            let entries = completions_menu.entries.borrow();
 5947            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5948            if self.show_edit_predictions_in_menu() {
 5949                self.discard_edit_prediction(true, cx);
 5950            }
 5951            mat.candidate_id
 5952        };
 5953
 5954        let completion = completions_menu
 5955            .completions
 5956            .borrow()
 5957            .get(candidate_id)?
 5958            .clone();
 5959        cx.stop_propagation();
 5960
 5961        let buffer_handle = completions_menu.buffer.clone();
 5962
 5963        let CompletionEdit {
 5964            new_text,
 5965            snippet,
 5966            replace_range,
 5967        } = process_completion_for_edit(
 5968            &completion,
 5969            intent,
 5970            &buffer_handle,
 5971            &completions_menu.initial_position.text_anchor,
 5972            cx,
 5973        );
 5974
 5975        let buffer = buffer_handle.read(cx);
 5976        let snapshot = self.buffer.read(cx).snapshot(cx);
 5977        let newest_anchor = self.selections.newest_anchor();
 5978        let replace_range_multibuffer = {
 5979            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5980            let multibuffer_anchor = snapshot
 5981                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5982                .unwrap()
 5983                ..snapshot
 5984                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5985                    .unwrap();
 5986            multibuffer_anchor.start.to_offset(&snapshot)
 5987                ..multibuffer_anchor.end.to_offset(&snapshot)
 5988        };
 5989        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5990            return None;
 5991        }
 5992
 5993        let old_text = buffer
 5994            .text_for_range(replace_range.clone())
 5995            .collect::<String>();
 5996        let lookbehind = newest_anchor
 5997            .start
 5998            .text_anchor
 5999            .to_offset(buffer)
 6000            .saturating_sub(replace_range.start);
 6001        let lookahead = replace_range
 6002            .end
 6003            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6004        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6005        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6006
 6007        let selections = self.selections.all::<usize>(cx);
 6008        let mut ranges = Vec::new();
 6009        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6010
 6011        for selection in &selections {
 6012            let range = if selection.id == newest_anchor.id {
 6013                replace_range_multibuffer.clone()
 6014            } else {
 6015                let mut range = selection.range();
 6016
 6017                // if prefix is present, don't duplicate it
 6018                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6019                    range.start = range.start.saturating_sub(lookbehind);
 6020
 6021                    // if suffix is also present, mimic the newest cursor and replace it
 6022                    if selection.id != newest_anchor.id
 6023                        && snapshot.contains_str_at(range.end, suffix)
 6024                    {
 6025                        range.end += lookahead;
 6026                    }
 6027                }
 6028                range
 6029            };
 6030
 6031            ranges.push(range.clone());
 6032
 6033            if !self.linked_edit_ranges.is_empty() {
 6034                let start_anchor = snapshot.anchor_before(range.start);
 6035                let end_anchor = snapshot.anchor_after(range.end);
 6036                if let Some(ranges) = self
 6037                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6038                {
 6039                    for (buffer, edits) in ranges {
 6040                        linked_edits
 6041                            .entry(buffer.clone())
 6042                            .or_default()
 6043                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6044                    }
 6045                }
 6046            }
 6047        }
 6048
 6049        let common_prefix_len = old_text
 6050            .chars()
 6051            .zip(new_text.chars())
 6052            .take_while(|(a, b)| a == b)
 6053            .map(|(a, _)| a.len_utf8())
 6054            .sum::<usize>();
 6055
 6056        cx.emit(EditorEvent::InputHandled {
 6057            utf16_range_to_replace: None,
 6058            text: new_text[common_prefix_len..].into(),
 6059        });
 6060
 6061        self.transact(window, cx, |editor, window, cx| {
 6062            if let Some(mut snippet) = snippet {
 6063                snippet.text = new_text.to_string();
 6064                editor
 6065                    .insert_snippet(&ranges, snippet, window, cx)
 6066                    .log_err();
 6067            } else {
 6068                editor.buffer.update(cx, |multi_buffer, cx| {
 6069                    let auto_indent = match completion.insert_text_mode {
 6070                        Some(InsertTextMode::AS_IS) => None,
 6071                        _ => editor.autoindent_mode.clone(),
 6072                    };
 6073                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6074                    multi_buffer.edit(edits, auto_indent, cx);
 6075                });
 6076            }
 6077            for (buffer, edits) in linked_edits {
 6078                buffer.update(cx, |buffer, cx| {
 6079                    let snapshot = buffer.snapshot();
 6080                    let edits = edits
 6081                        .into_iter()
 6082                        .map(|(range, text)| {
 6083                            use text::ToPoint as TP;
 6084                            let end_point = TP::to_point(&range.end, &snapshot);
 6085                            let start_point = TP::to_point(&range.start, &snapshot);
 6086                            (start_point..end_point, text)
 6087                        })
 6088                        .sorted_by_key(|(range, _)| range.start);
 6089                    buffer.edit(edits, None, cx);
 6090                })
 6091            }
 6092
 6093            editor.refresh_edit_prediction(true, false, window, cx);
 6094        });
 6095        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6096
 6097        let show_new_completions_on_confirm = completion
 6098            .confirm
 6099            .as_ref()
 6100            .is_some_and(|confirm| confirm(intent, window, cx));
 6101        if show_new_completions_on_confirm {
 6102            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6103        }
 6104
 6105        let provider = self.completion_provider.as_ref()?;
 6106        drop(completion);
 6107        let apply_edits = provider.apply_additional_edits_for_completion(
 6108            buffer_handle,
 6109            completions_menu.completions.clone(),
 6110            candidate_id,
 6111            true,
 6112            cx,
 6113        );
 6114
 6115        let editor_settings = EditorSettings::get_global(cx);
 6116        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6117            // After the code completion is finished, users often want to know what signatures are needed.
 6118            // so we should automatically call signature_help
 6119            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6120        }
 6121
 6122        Some(cx.foreground_executor().spawn(async move {
 6123            apply_edits.await?;
 6124            Ok(())
 6125        }))
 6126    }
 6127
 6128    pub fn toggle_code_actions(
 6129        &mut self,
 6130        action: &ToggleCodeActions,
 6131        window: &mut Window,
 6132        cx: &mut Context<Self>,
 6133    ) {
 6134        let quick_launch = action.quick_launch;
 6135        let mut context_menu = self.context_menu.borrow_mut();
 6136        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6137            if code_actions.deployed_from == action.deployed_from {
 6138                // Toggle if we're selecting the same one
 6139                *context_menu = None;
 6140                cx.notify();
 6141                return;
 6142            } else {
 6143                // Otherwise, clear it and start a new one
 6144                *context_menu = None;
 6145                cx.notify();
 6146            }
 6147        }
 6148        drop(context_menu);
 6149        let snapshot = self.snapshot(window, cx);
 6150        let deployed_from = action.deployed_from.clone();
 6151        let action = action.clone();
 6152        self.completion_tasks.clear();
 6153        self.discard_edit_prediction(false, cx);
 6154
 6155        let multibuffer_point = match &action.deployed_from {
 6156            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6157                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6158            }
 6159            _ => self.selections.newest::<Point>(cx).head(),
 6160        };
 6161        let Some((buffer, buffer_row)) = snapshot
 6162            .buffer_snapshot
 6163            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6164            .and_then(|(buffer_snapshot, range)| {
 6165                self.buffer()
 6166                    .read(cx)
 6167                    .buffer(buffer_snapshot.remote_id())
 6168                    .map(|buffer| (buffer, range.start.row))
 6169            })
 6170        else {
 6171            return;
 6172        };
 6173        let buffer_id = buffer.read(cx).remote_id();
 6174        let tasks = self
 6175            .tasks
 6176            .get(&(buffer_id, buffer_row))
 6177            .map(|t| Arc::new(t.to_owned()));
 6178
 6179        if !self.focus_handle.is_focused(window) {
 6180            return;
 6181        }
 6182        let project = self.project.clone();
 6183
 6184        let code_actions_task = match deployed_from {
 6185            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6186            _ => self.code_actions(buffer_row, window, cx),
 6187        };
 6188
 6189        let runnable_task = match deployed_from {
 6190            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6191            _ => {
 6192                let mut task_context_task = Task::ready(None);
 6193                if let Some(tasks) = &tasks
 6194                    && let Some(project) = project
 6195                {
 6196                    task_context_task =
 6197                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6198                }
 6199
 6200                cx.spawn_in(window, {
 6201                    let buffer = buffer.clone();
 6202                    async move |editor, cx| {
 6203                        let task_context = task_context_task.await;
 6204
 6205                        let resolved_tasks =
 6206                            tasks
 6207                                .zip(task_context.clone())
 6208                                .map(|(tasks, task_context)| ResolvedTasks {
 6209                                    templates: tasks.resolve(&task_context).collect(),
 6210                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6211                                        multibuffer_point.row,
 6212                                        tasks.column,
 6213                                    )),
 6214                                });
 6215                        let debug_scenarios = editor
 6216                            .update(cx, |editor, cx| {
 6217                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6218                            })?
 6219                            .await;
 6220                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6221                    }
 6222                })
 6223            }
 6224        };
 6225
 6226        cx.spawn_in(window, async move |editor, cx| {
 6227            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6228            let code_actions = code_actions_task.await;
 6229            let spawn_straight_away = quick_launch
 6230                && resolved_tasks
 6231                    .as_ref()
 6232                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6233                && code_actions
 6234                    .as_ref()
 6235                    .is_none_or(|actions| actions.is_empty())
 6236                && debug_scenarios.is_empty();
 6237
 6238            editor.update_in(cx, |editor, window, cx| {
 6239                crate::hover_popover::hide_hover(editor, cx);
 6240                let actions = CodeActionContents::new(
 6241                    resolved_tasks,
 6242                    code_actions,
 6243                    debug_scenarios,
 6244                    task_context.unwrap_or_default(),
 6245                );
 6246
 6247                // Don't show the menu if there are no actions available
 6248                if actions.is_empty() {
 6249                    cx.notify();
 6250                    return Task::ready(Ok(()));
 6251                }
 6252
 6253                *editor.context_menu.borrow_mut() =
 6254                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6255                        buffer,
 6256                        actions,
 6257                        selected_item: Default::default(),
 6258                        scroll_handle: UniformListScrollHandle::default(),
 6259                        deployed_from,
 6260                    }));
 6261                cx.notify();
 6262                if spawn_straight_away
 6263                    && let Some(task) = editor.confirm_code_action(
 6264                        &ConfirmCodeAction { item_ix: Some(0) },
 6265                        window,
 6266                        cx,
 6267                    )
 6268                {
 6269                    return task;
 6270                }
 6271
 6272                Task::ready(Ok(()))
 6273            })
 6274        })
 6275        .detach_and_log_err(cx);
 6276    }
 6277
 6278    fn debug_scenarios(
 6279        &mut self,
 6280        resolved_tasks: &Option<ResolvedTasks>,
 6281        buffer: &Entity<Buffer>,
 6282        cx: &mut App,
 6283    ) -> Task<Vec<task::DebugScenario>> {
 6284        maybe!({
 6285            let project = self.project()?;
 6286            let dap_store = project.read(cx).dap_store();
 6287            let mut scenarios = vec![];
 6288            let resolved_tasks = resolved_tasks.as_ref()?;
 6289            let buffer = buffer.read(cx);
 6290            let language = buffer.language()?;
 6291            let file = buffer.file();
 6292            let debug_adapter = language_settings(language.name().into(), file, cx)
 6293                .debuggers
 6294                .first()
 6295                .map(SharedString::from)
 6296                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6297
 6298            dap_store.update(cx, |dap_store, cx| {
 6299                for (_, task) in &resolved_tasks.templates {
 6300                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6301                        task.original_task().clone(),
 6302                        debug_adapter.clone().into(),
 6303                        task.display_label().to_owned().into(),
 6304                        cx,
 6305                    );
 6306                    scenarios.push(maybe_scenario);
 6307                }
 6308            });
 6309            Some(cx.background_spawn(async move {
 6310                futures::future::join_all(scenarios)
 6311                    .await
 6312                    .into_iter()
 6313                    .flatten()
 6314                    .collect::<Vec<_>>()
 6315            }))
 6316        })
 6317        .unwrap_or_else(|| Task::ready(vec![]))
 6318    }
 6319
 6320    fn code_actions(
 6321        &mut self,
 6322        buffer_row: u32,
 6323        window: &mut Window,
 6324        cx: &mut Context<Self>,
 6325    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6326        let mut task = self.code_actions_task.take();
 6327        cx.spawn_in(window, async move |editor, cx| {
 6328            while let Some(prev_task) = task {
 6329                prev_task.await.log_err();
 6330                task = editor
 6331                    .update(cx, |this, _| this.code_actions_task.take())
 6332                    .ok()?;
 6333            }
 6334
 6335            editor
 6336                .update(cx, |editor, cx| {
 6337                    editor
 6338                        .available_code_actions
 6339                        .clone()
 6340                        .and_then(|(location, code_actions)| {
 6341                            let snapshot = location.buffer.read(cx).snapshot();
 6342                            let point_range = location.range.to_point(&snapshot);
 6343                            let point_range = point_range.start.row..=point_range.end.row;
 6344                            if point_range.contains(&buffer_row) {
 6345                                Some(code_actions)
 6346                            } else {
 6347                                None
 6348                            }
 6349                        })
 6350                })
 6351                .ok()
 6352                .flatten()
 6353        })
 6354    }
 6355
 6356    pub fn confirm_code_action(
 6357        &mut self,
 6358        action: &ConfirmCodeAction,
 6359        window: &mut Window,
 6360        cx: &mut Context<Self>,
 6361    ) -> Option<Task<Result<()>>> {
 6362        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6363
 6364        let actions_menu =
 6365            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6366                menu
 6367            } else {
 6368                return None;
 6369            };
 6370
 6371        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6372        let action = actions_menu.actions.get(action_ix)?;
 6373        let title = action.label();
 6374        let buffer = actions_menu.buffer;
 6375        let workspace = self.workspace()?;
 6376
 6377        match action {
 6378            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6379                workspace.update(cx, |workspace, cx| {
 6380                    workspace.schedule_resolved_task(
 6381                        task_source_kind,
 6382                        resolved_task,
 6383                        false,
 6384                        window,
 6385                        cx,
 6386                    );
 6387
 6388                    Some(Task::ready(Ok(())))
 6389                })
 6390            }
 6391            CodeActionsItem::CodeAction {
 6392                excerpt_id,
 6393                action,
 6394                provider,
 6395            } => {
 6396                let apply_code_action =
 6397                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6398                let workspace = workspace.downgrade();
 6399                Some(cx.spawn_in(window, async move |editor, cx| {
 6400                    let project_transaction = apply_code_action.await?;
 6401                    Self::open_project_transaction(
 6402                        &editor,
 6403                        workspace,
 6404                        project_transaction,
 6405                        title,
 6406                        cx,
 6407                    )
 6408                    .await
 6409                }))
 6410            }
 6411            CodeActionsItem::DebugScenario(scenario) => {
 6412                let context = actions_menu.actions.context;
 6413
 6414                workspace.update(cx, |workspace, cx| {
 6415                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6416                    workspace.start_debug_session(
 6417                        scenario,
 6418                        context,
 6419                        Some(buffer),
 6420                        None,
 6421                        window,
 6422                        cx,
 6423                    );
 6424                });
 6425                Some(Task::ready(Ok(())))
 6426            }
 6427        }
 6428    }
 6429
 6430    pub async fn open_project_transaction(
 6431        editor: &WeakEntity<Editor>,
 6432        workspace: WeakEntity<Workspace>,
 6433        transaction: ProjectTransaction,
 6434        title: String,
 6435        cx: &mut AsyncWindowContext,
 6436    ) -> Result<()> {
 6437        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6438        cx.update(|_, cx| {
 6439            entries.sort_unstable_by_key(|(buffer, _)| {
 6440                buffer.read(cx).file().map(|f| f.path().clone())
 6441            });
 6442        })?;
 6443        if entries.is_empty() {
 6444            return Ok(());
 6445        }
 6446
 6447        // If the project transaction's edits are all contained within this editor, then
 6448        // avoid opening a new editor to display them.
 6449
 6450        if let [(buffer, transaction)] = &*entries {
 6451            let excerpt = editor.update(cx, |editor, cx| {
 6452                editor
 6453                    .buffer()
 6454                    .read(cx)
 6455                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6456            })?;
 6457            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6458                && excerpted_buffer == *buffer
 6459            {
 6460                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6461                    let excerpt_range = excerpt_range.to_offset(buffer);
 6462                    buffer
 6463                        .edited_ranges_for_transaction::<usize>(transaction)
 6464                        .all(|range| {
 6465                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6466                        })
 6467                })?;
 6468
 6469                if all_edits_within_excerpt {
 6470                    return Ok(());
 6471                }
 6472            }
 6473        }
 6474
 6475        let mut ranges_to_highlight = Vec::new();
 6476        let excerpt_buffer = cx.new(|cx| {
 6477            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6478            for (buffer_handle, transaction) in &entries {
 6479                let edited_ranges = buffer_handle
 6480                    .read(cx)
 6481                    .edited_ranges_for_transaction::<Point>(transaction)
 6482                    .collect::<Vec<_>>();
 6483                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6484                    PathKey::for_buffer(buffer_handle, cx),
 6485                    buffer_handle.clone(),
 6486                    edited_ranges,
 6487                    multibuffer_context_lines(cx),
 6488                    cx,
 6489                );
 6490
 6491                ranges_to_highlight.extend(ranges);
 6492            }
 6493            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6494            multibuffer
 6495        })?;
 6496
 6497        workspace.update_in(cx, |workspace, window, cx| {
 6498            let project = workspace.project().clone();
 6499            let editor =
 6500                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6501            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6502            editor.update(cx, |editor, cx| {
 6503                editor.highlight_background::<Self>(
 6504                    &ranges_to_highlight,
 6505                    |theme| theme.colors().editor_highlighted_line_background,
 6506                    cx,
 6507                );
 6508            });
 6509        })?;
 6510
 6511        Ok(())
 6512    }
 6513
 6514    pub fn clear_code_action_providers(&mut self) {
 6515        self.code_action_providers.clear();
 6516        self.available_code_actions.take();
 6517    }
 6518
 6519    pub fn add_code_action_provider(
 6520        &mut self,
 6521        provider: Rc<dyn CodeActionProvider>,
 6522        window: &mut Window,
 6523        cx: &mut Context<Self>,
 6524    ) {
 6525        if self
 6526            .code_action_providers
 6527            .iter()
 6528            .any(|existing_provider| existing_provider.id() == provider.id())
 6529        {
 6530            return;
 6531        }
 6532
 6533        self.code_action_providers.push(provider);
 6534        self.refresh_code_actions(window, cx);
 6535    }
 6536
 6537    pub fn remove_code_action_provider(
 6538        &mut self,
 6539        id: Arc<str>,
 6540        window: &mut Window,
 6541        cx: &mut Context<Self>,
 6542    ) {
 6543        self.code_action_providers
 6544            .retain(|provider| provider.id() != id);
 6545        self.refresh_code_actions(window, cx);
 6546    }
 6547
 6548    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6549        !self.code_action_providers.is_empty()
 6550            && EditorSettings::get_global(cx).toolbar.code_actions
 6551    }
 6552
 6553    pub fn has_available_code_actions(&self) -> bool {
 6554        self.available_code_actions
 6555            .as_ref()
 6556            .is_some_and(|(_, actions)| !actions.is_empty())
 6557    }
 6558
 6559    fn render_inline_code_actions(
 6560        &self,
 6561        icon_size: ui::IconSize,
 6562        display_row: DisplayRow,
 6563        is_active: bool,
 6564        cx: &mut Context<Self>,
 6565    ) -> AnyElement {
 6566        let show_tooltip = !self.context_menu_visible();
 6567        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6568            .icon_size(icon_size)
 6569            .shape(ui::IconButtonShape::Square)
 6570            .icon_color(ui::Color::Hidden)
 6571            .toggle_state(is_active)
 6572            .when(show_tooltip, |this| {
 6573                this.tooltip({
 6574                    let focus_handle = self.focus_handle.clone();
 6575                    move |window, cx| {
 6576                        Tooltip::for_action_in(
 6577                            "Toggle Code Actions",
 6578                            &ToggleCodeActions {
 6579                                deployed_from: None,
 6580                                quick_launch: false,
 6581                            },
 6582                            &focus_handle,
 6583                            window,
 6584                            cx,
 6585                        )
 6586                    }
 6587                })
 6588            })
 6589            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6590                window.focus(&editor.focus_handle(cx));
 6591                editor.toggle_code_actions(
 6592                    &crate::actions::ToggleCodeActions {
 6593                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6594                            display_row,
 6595                        )),
 6596                        quick_launch: false,
 6597                    },
 6598                    window,
 6599                    cx,
 6600                );
 6601            }))
 6602            .into_any_element()
 6603    }
 6604
 6605    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6606        &self.context_menu
 6607    }
 6608
 6609    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6610        let newest_selection = self.selections.newest_anchor().clone();
 6611        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6612        let buffer = self.buffer.read(cx);
 6613        if newest_selection.head().diff_base_anchor.is_some() {
 6614            return None;
 6615        }
 6616        let (start_buffer, start) =
 6617            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6618        let (end_buffer, end) =
 6619            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6620        if start_buffer != end_buffer {
 6621            return None;
 6622        }
 6623
 6624        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6625            cx.background_executor()
 6626                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6627                .await;
 6628
 6629            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6630                let providers = this.code_action_providers.clone();
 6631                let tasks = this
 6632                    .code_action_providers
 6633                    .iter()
 6634                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6635                    .collect::<Vec<_>>();
 6636                (providers, tasks)
 6637            })?;
 6638
 6639            let mut actions = Vec::new();
 6640            for (provider, provider_actions) in
 6641                providers.into_iter().zip(future::join_all(tasks).await)
 6642            {
 6643                if let Some(provider_actions) = provider_actions.log_err() {
 6644                    actions.extend(provider_actions.into_iter().map(|action| {
 6645                        AvailableCodeAction {
 6646                            excerpt_id: newest_selection.start.excerpt_id,
 6647                            action,
 6648                            provider: provider.clone(),
 6649                        }
 6650                    }));
 6651                }
 6652            }
 6653
 6654            this.update(cx, |this, cx| {
 6655                this.available_code_actions = if actions.is_empty() {
 6656                    None
 6657                } else {
 6658                    Some((
 6659                        Location {
 6660                            buffer: start_buffer,
 6661                            range: start..end,
 6662                        },
 6663                        actions.into(),
 6664                    ))
 6665                };
 6666                cx.notify();
 6667            })
 6668        }));
 6669        None
 6670    }
 6671
 6672    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6673        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6674            self.show_git_blame_inline = false;
 6675
 6676            self.show_git_blame_inline_delay_task =
 6677                Some(cx.spawn_in(window, async move |this, cx| {
 6678                    cx.background_executor().timer(delay).await;
 6679
 6680                    this.update(cx, |this, cx| {
 6681                        this.show_git_blame_inline = true;
 6682                        cx.notify();
 6683                    })
 6684                    .log_err();
 6685                }));
 6686        }
 6687    }
 6688
 6689    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6690        let snapshot = self.snapshot(window, cx);
 6691        let cursor = self.selections.newest::<Point>(cx).head();
 6692        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6693        else {
 6694            return;
 6695        };
 6696
 6697        let Some(blame) = self.blame.as_ref() else {
 6698            return;
 6699        };
 6700
 6701        let row_info = RowInfo {
 6702            buffer_id: Some(buffer.remote_id()),
 6703            buffer_row: Some(point.row),
 6704            ..Default::default()
 6705        };
 6706        let Some((buffer, blame_entry)) = blame
 6707            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6708            .flatten()
 6709        else {
 6710            return;
 6711        };
 6712
 6713        let anchor = self.selections.newest_anchor().head();
 6714        let position = self.to_pixel_point(anchor, &snapshot, window);
 6715        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6716            self.show_blame_popover(
 6717                buffer,
 6718                &blame_entry,
 6719                position + last_bounds.origin,
 6720                true,
 6721                cx,
 6722            );
 6723        };
 6724    }
 6725
 6726    fn show_blame_popover(
 6727        &mut self,
 6728        buffer: BufferId,
 6729        blame_entry: &BlameEntry,
 6730        position: gpui::Point<Pixels>,
 6731        ignore_timeout: bool,
 6732        cx: &mut Context<Self>,
 6733    ) {
 6734        if let Some(state) = &mut self.inline_blame_popover {
 6735            state.hide_task.take();
 6736        } else {
 6737            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6738            let blame_entry = blame_entry.clone();
 6739            let show_task = cx.spawn(async move |editor, cx| {
 6740                if !ignore_timeout {
 6741                    cx.background_executor()
 6742                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6743                        .await;
 6744                }
 6745                editor
 6746                    .update(cx, |editor, cx| {
 6747                        editor.inline_blame_popover_show_task.take();
 6748                        let Some(blame) = editor.blame.as_ref() else {
 6749                            return;
 6750                        };
 6751                        let blame = blame.read(cx);
 6752                        let details = blame.details_for_entry(buffer, &blame_entry);
 6753                        let markdown = cx.new(|cx| {
 6754                            Markdown::new(
 6755                                details
 6756                                    .as_ref()
 6757                                    .map(|message| message.message.clone())
 6758                                    .unwrap_or_default(),
 6759                                None,
 6760                                None,
 6761                                cx,
 6762                            )
 6763                        });
 6764                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6765                            position,
 6766                            hide_task: None,
 6767                            popover_bounds: None,
 6768                            popover_state: InlineBlamePopoverState {
 6769                                scroll_handle: ScrollHandle::new(),
 6770                                commit_message: details,
 6771                                markdown,
 6772                            },
 6773                            keyboard_grace: ignore_timeout,
 6774                        });
 6775                        cx.notify();
 6776                    })
 6777                    .ok();
 6778            });
 6779            self.inline_blame_popover_show_task = Some(show_task);
 6780        }
 6781    }
 6782
 6783    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6784        self.inline_blame_popover_show_task.take();
 6785        if let Some(state) = &mut self.inline_blame_popover {
 6786            let hide_task = cx.spawn(async move |editor, cx| {
 6787                cx.background_executor()
 6788                    .timer(std::time::Duration::from_millis(100))
 6789                    .await;
 6790                editor
 6791                    .update(cx, |editor, cx| {
 6792                        editor.inline_blame_popover.take();
 6793                        cx.notify();
 6794                    })
 6795                    .ok();
 6796            });
 6797            state.hide_task = Some(hide_task);
 6798        }
 6799    }
 6800
 6801    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6802        if self.pending_rename.is_some() {
 6803            return None;
 6804        }
 6805
 6806        let provider = self.semantics_provider.clone()?;
 6807        let buffer = self.buffer.read(cx);
 6808        let newest_selection = self.selections.newest_anchor().clone();
 6809        let cursor_position = newest_selection.head();
 6810        let (cursor_buffer, cursor_buffer_position) =
 6811            buffer.text_anchor_for_position(cursor_position, cx)?;
 6812        let (tail_buffer, tail_buffer_position) =
 6813            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6814        if cursor_buffer != tail_buffer {
 6815            return None;
 6816        }
 6817
 6818        let snapshot = cursor_buffer.read(cx).snapshot();
 6819        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6820        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6821        if start_word_range != end_word_range {
 6822            self.document_highlights_task.take();
 6823            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6824            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6825            return None;
 6826        }
 6827
 6828        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6829        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6830            cx.background_executor()
 6831                .timer(Duration::from_millis(debounce))
 6832                .await;
 6833
 6834            let highlights = if let Some(highlights) = cx
 6835                .update(|cx| {
 6836                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6837                })
 6838                .ok()
 6839                .flatten()
 6840            {
 6841                highlights.await.log_err()
 6842            } else {
 6843                None
 6844            };
 6845
 6846            if let Some(highlights) = highlights {
 6847                this.update(cx, |this, cx| {
 6848                    if this.pending_rename.is_some() {
 6849                        return;
 6850                    }
 6851
 6852                    let buffer = this.buffer.read(cx);
 6853                    if buffer
 6854                        .text_anchor_for_position(cursor_position, cx)
 6855                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6856                    {
 6857                        return;
 6858                    }
 6859
 6860                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6861                    let mut write_ranges = Vec::new();
 6862                    let mut read_ranges = Vec::new();
 6863                    for highlight in highlights {
 6864                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6865                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6866                        {
 6867                            let start = highlight
 6868                                .range
 6869                                .start
 6870                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6871                            let end = highlight
 6872                                .range
 6873                                .end
 6874                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6875                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6876                                continue;
 6877                            }
 6878
 6879                            let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
 6880                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6881                                write_ranges.push(range);
 6882                            } else {
 6883                                read_ranges.push(range);
 6884                            }
 6885                        }
 6886                    }
 6887
 6888                    this.highlight_background::<DocumentHighlightRead>(
 6889                        &read_ranges,
 6890                        |theme| theme.colors().editor_document_highlight_read_background,
 6891                        cx,
 6892                    );
 6893                    this.highlight_background::<DocumentHighlightWrite>(
 6894                        &write_ranges,
 6895                        |theme| theme.colors().editor_document_highlight_write_background,
 6896                        cx,
 6897                    );
 6898                    cx.notify();
 6899                })
 6900                .log_err();
 6901            }
 6902        }));
 6903        None
 6904    }
 6905
 6906    fn prepare_highlight_query_from_selection(
 6907        &mut self,
 6908        cx: &mut Context<Editor>,
 6909    ) -> Option<(String, Range<Anchor>)> {
 6910        if matches!(self.mode, EditorMode::SingleLine) {
 6911            return None;
 6912        }
 6913        if !EditorSettings::get_global(cx).selection_highlight {
 6914            return None;
 6915        }
 6916        if self.selections.count() != 1 || self.selections.line_mode() {
 6917            return None;
 6918        }
 6919        let selection = self.selections.newest::<Point>(cx);
 6920        if selection.is_empty() || selection.start.row != selection.end.row {
 6921            return None;
 6922        }
 6923        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6924        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6925        let query = multi_buffer_snapshot
 6926            .text_for_range(selection_anchor_range.clone())
 6927            .collect::<String>();
 6928        if query.trim().is_empty() {
 6929            return None;
 6930        }
 6931        Some((query, selection_anchor_range))
 6932    }
 6933
 6934    fn update_selection_occurrence_highlights(
 6935        &mut self,
 6936        query_text: String,
 6937        query_range: Range<Anchor>,
 6938        multi_buffer_range_to_query: Range<Point>,
 6939        use_debounce: bool,
 6940        window: &mut Window,
 6941        cx: &mut Context<Editor>,
 6942    ) -> Task<()> {
 6943        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6944        cx.spawn_in(window, async move |editor, cx| {
 6945            if use_debounce {
 6946                cx.background_executor()
 6947                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6948                    .await;
 6949            }
 6950            let match_task = cx.background_spawn(async move {
 6951                let buffer_ranges = multi_buffer_snapshot
 6952                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6953                    .into_iter()
 6954                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6955                let mut match_ranges = Vec::new();
 6956                let Ok(regex) = project::search::SearchQuery::text(
 6957                    query_text.clone(),
 6958                    false,
 6959                    false,
 6960                    false,
 6961                    Default::default(),
 6962                    Default::default(),
 6963                    false,
 6964                    None,
 6965                ) else {
 6966                    return Vec::default();
 6967                };
 6968                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6969                    match_ranges.extend(
 6970                        regex
 6971                            .search(buffer_snapshot, Some(search_range.clone()))
 6972                            .await
 6973                            .into_iter()
 6974                            .filter_map(|match_range| {
 6975                                let match_start = buffer_snapshot
 6976                                    .anchor_after(search_range.start + match_range.start);
 6977                                let match_end = buffer_snapshot
 6978                                    .anchor_before(search_range.start + match_range.end);
 6979                                let match_anchor_range = Anchor::range_in_buffer(
 6980                                    excerpt_id,
 6981                                    buffer_snapshot.remote_id(),
 6982                                    match_start..match_end,
 6983                                );
 6984                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6985                            }),
 6986                    );
 6987                }
 6988                match_ranges
 6989            });
 6990            let match_ranges = match_task.await;
 6991            editor
 6992                .update_in(cx, |editor, _, cx| {
 6993                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6994                    if !match_ranges.is_empty() {
 6995                        editor.highlight_background::<SelectedTextHighlight>(
 6996                            &match_ranges,
 6997                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6998                            cx,
 6999                        )
 7000                    }
 7001                })
 7002                .log_err();
 7003        })
 7004    }
 7005
 7006    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7007        struct NewlineFold;
 7008        let type_id = std::any::TypeId::of::<NewlineFold>();
 7009        if !self.mode.is_single_line() {
 7010            return;
 7011        }
 7012        let snapshot = self.snapshot(window, cx);
 7013        if snapshot.buffer_snapshot.max_point().row == 0 {
 7014            return;
 7015        }
 7016        let task = cx.background_spawn(async move {
 7017            let new_newlines = snapshot
 7018                .buffer_chars_at(0)
 7019                .filter_map(|(c, i)| {
 7020                    if c == '\n' {
 7021                        Some(
 7022                            snapshot.buffer_snapshot.anchor_after(i)
 7023                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7024                        )
 7025                    } else {
 7026                        None
 7027                    }
 7028                })
 7029                .collect::<Vec<_>>();
 7030            let existing_newlines = snapshot
 7031                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7032                .filter_map(|fold| {
 7033                    if fold.placeholder.type_tag == Some(type_id) {
 7034                        Some(fold.range.start..fold.range.end)
 7035                    } else {
 7036                        None
 7037                    }
 7038                })
 7039                .collect::<Vec<_>>();
 7040
 7041            (new_newlines, existing_newlines)
 7042        });
 7043        self.folding_newlines = cx.spawn(async move |this, cx| {
 7044            let (new_newlines, existing_newlines) = task.await;
 7045            if new_newlines == existing_newlines {
 7046                return;
 7047            }
 7048            let placeholder = FoldPlaceholder {
 7049                render: Arc::new(move |_, _, cx| {
 7050                    div()
 7051                        .bg(cx.theme().status().hint_background)
 7052                        .border_b_1()
 7053                        .size_full()
 7054                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7055                        .border_color(cx.theme().status().hint)
 7056                        .child("\\n")
 7057                        .into_any()
 7058                }),
 7059                constrain_width: false,
 7060                merge_adjacent: false,
 7061                type_tag: Some(type_id),
 7062            };
 7063            let creases = new_newlines
 7064                .into_iter()
 7065                .map(|range| Crease::simple(range, placeholder.clone()))
 7066                .collect();
 7067            this.update(cx, |this, cx| {
 7068                this.display_map.update(cx, |display_map, cx| {
 7069                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7070                    display_map.fold(creases, cx);
 7071                });
 7072            })
 7073            .ok();
 7074        });
 7075    }
 7076
 7077    fn refresh_selected_text_highlights(
 7078        &mut self,
 7079        on_buffer_edit: bool,
 7080        window: &mut Window,
 7081        cx: &mut Context<Editor>,
 7082    ) {
 7083        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7084        else {
 7085            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7086            self.quick_selection_highlight_task.take();
 7087            self.debounced_selection_highlight_task.take();
 7088            return;
 7089        };
 7090        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7091        if on_buffer_edit
 7092            || self
 7093                .quick_selection_highlight_task
 7094                .as_ref()
 7095                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7096        {
 7097            let multi_buffer_visible_start = self
 7098                .scroll_manager
 7099                .anchor()
 7100                .anchor
 7101                .to_point(&multi_buffer_snapshot);
 7102            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7103                multi_buffer_visible_start
 7104                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7105                Bias::Left,
 7106            );
 7107            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7108            self.quick_selection_highlight_task = Some((
 7109                query_range.clone(),
 7110                self.update_selection_occurrence_highlights(
 7111                    query_text.clone(),
 7112                    query_range.clone(),
 7113                    multi_buffer_visible_range,
 7114                    false,
 7115                    window,
 7116                    cx,
 7117                ),
 7118            ));
 7119        }
 7120        if on_buffer_edit
 7121            || self
 7122                .debounced_selection_highlight_task
 7123                .as_ref()
 7124                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7125        {
 7126            let multi_buffer_start = multi_buffer_snapshot
 7127                .anchor_before(0)
 7128                .to_point(&multi_buffer_snapshot);
 7129            let multi_buffer_end = multi_buffer_snapshot
 7130                .anchor_after(multi_buffer_snapshot.len())
 7131                .to_point(&multi_buffer_snapshot);
 7132            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7133            self.debounced_selection_highlight_task = Some((
 7134                query_range.clone(),
 7135                self.update_selection_occurrence_highlights(
 7136                    query_text,
 7137                    query_range,
 7138                    multi_buffer_full_range,
 7139                    true,
 7140                    window,
 7141                    cx,
 7142                ),
 7143            ));
 7144        }
 7145    }
 7146
 7147    pub fn refresh_edit_prediction(
 7148        &mut self,
 7149        debounce: bool,
 7150        user_requested: bool,
 7151        window: &mut Window,
 7152        cx: &mut Context<Self>,
 7153    ) -> Option<()> {
 7154        if DisableAiSettings::get_global(cx).disable_ai {
 7155            return None;
 7156        }
 7157
 7158        let provider = self.edit_prediction_provider()?;
 7159        let cursor = self.selections.newest_anchor().head();
 7160        let (buffer, cursor_buffer_position) =
 7161            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7162
 7163        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7164            self.discard_edit_prediction(false, cx);
 7165            return None;
 7166        }
 7167
 7168        self.update_visible_edit_prediction(window, cx);
 7169
 7170        if !user_requested
 7171            && (!self.should_show_edit_predictions()
 7172                || !self.is_focused(window)
 7173                || buffer.read(cx).is_empty())
 7174        {
 7175            self.discard_edit_prediction(false, cx);
 7176            return None;
 7177        }
 7178
 7179        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7180        Some(())
 7181    }
 7182
 7183    fn show_edit_predictions_in_menu(&self) -> bool {
 7184        match self.edit_prediction_settings {
 7185            EditPredictionSettings::Disabled => false,
 7186            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7187        }
 7188    }
 7189
 7190    pub fn edit_predictions_enabled(&self) -> bool {
 7191        match self.edit_prediction_settings {
 7192            EditPredictionSettings::Disabled => false,
 7193            EditPredictionSettings::Enabled { .. } => true,
 7194        }
 7195    }
 7196
 7197    fn edit_prediction_requires_modifier(&self) -> bool {
 7198        match self.edit_prediction_settings {
 7199            EditPredictionSettings::Disabled => false,
 7200            EditPredictionSettings::Enabled {
 7201                preview_requires_modifier,
 7202                ..
 7203            } => preview_requires_modifier,
 7204        }
 7205    }
 7206
 7207    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7208        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7209            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7210            self.discard_edit_prediction(false, cx);
 7211        } else {
 7212            let selection = self.selections.newest_anchor();
 7213            let cursor = selection.head();
 7214
 7215            if let Some((buffer, cursor_buffer_position)) =
 7216                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7217            {
 7218                self.edit_prediction_settings =
 7219                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7220            }
 7221        }
 7222    }
 7223
 7224    fn edit_prediction_settings_at_position(
 7225        &self,
 7226        buffer: &Entity<Buffer>,
 7227        buffer_position: language::Anchor,
 7228        cx: &App,
 7229    ) -> EditPredictionSettings {
 7230        if !self.mode.is_full()
 7231            || !self.show_edit_predictions_override.unwrap_or(true)
 7232            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7233        {
 7234            return EditPredictionSettings::Disabled;
 7235        }
 7236
 7237        let buffer = buffer.read(cx);
 7238
 7239        let file = buffer.file();
 7240
 7241        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7242            return EditPredictionSettings::Disabled;
 7243        };
 7244
 7245        let by_provider = matches!(
 7246            self.menu_edit_predictions_policy,
 7247            MenuEditPredictionsPolicy::ByProvider
 7248        );
 7249
 7250        let show_in_menu = by_provider
 7251            && self
 7252                .edit_prediction_provider
 7253                .as_ref()
 7254                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7255
 7256        let preview_requires_modifier =
 7257            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7258
 7259        EditPredictionSettings::Enabled {
 7260            show_in_menu,
 7261            preview_requires_modifier,
 7262        }
 7263    }
 7264
 7265    fn should_show_edit_predictions(&self) -> bool {
 7266        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7267    }
 7268
 7269    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7270        matches!(
 7271            self.edit_prediction_preview,
 7272            EditPredictionPreview::Active { .. }
 7273        )
 7274    }
 7275
 7276    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7277        let cursor = self.selections.newest_anchor().head();
 7278        if let Some((buffer, cursor_position)) =
 7279            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7280        {
 7281            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7282        } else {
 7283            false
 7284        }
 7285    }
 7286
 7287    pub fn supports_minimap(&self, cx: &App) -> bool {
 7288        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7289    }
 7290
 7291    fn edit_predictions_enabled_in_buffer(
 7292        &self,
 7293        buffer: &Entity<Buffer>,
 7294        buffer_position: language::Anchor,
 7295        cx: &App,
 7296    ) -> bool {
 7297        maybe!({
 7298            if self.read_only(cx) {
 7299                return Some(false);
 7300            }
 7301            let provider = self.edit_prediction_provider()?;
 7302            if !provider.is_enabled(buffer, buffer_position, cx) {
 7303                return Some(false);
 7304            }
 7305            let buffer = buffer.read(cx);
 7306            let Some(file) = buffer.file() else {
 7307                return Some(true);
 7308            };
 7309            let settings = all_language_settings(Some(file), cx);
 7310            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7311        })
 7312        .unwrap_or(false)
 7313    }
 7314
 7315    fn cycle_edit_prediction(
 7316        &mut self,
 7317        direction: Direction,
 7318        window: &mut Window,
 7319        cx: &mut Context<Self>,
 7320    ) -> Option<()> {
 7321        let provider = self.edit_prediction_provider()?;
 7322        let cursor = self.selections.newest_anchor().head();
 7323        let (buffer, cursor_buffer_position) =
 7324            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7325        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7326            return None;
 7327        }
 7328
 7329        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7330        self.update_visible_edit_prediction(window, cx);
 7331
 7332        Some(())
 7333    }
 7334
 7335    pub fn show_edit_prediction(
 7336        &mut self,
 7337        _: &ShowEditPrediction,
 7338        window: &mut Window,
 7339        cx: &mut Context<Self>,
 7340    ) {
 7341        if !self.has_active_edit_prediction() {
 7342            self.refresh_edit_prediction(false, true, window, cx);
 7343            return;
 7344        }
 7345
 7346        self.update_visible_edit_prediction(window, cx);
 7347    }
 7348
 7349    pub fn display_cursor_names(
 7350        &mut self,
 7351        _: &DisplayCursorNames,
 7352        window: &mut Window,
 7353        cx: &mut Context<Self>,
 7354    ) {
 7355        self.show_cursor_names(window, cx);
 7356    }
 7357
 7358    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7359        self.show_cursor_names = true;
 7360        cx.notify();
 7361        cx.spawn_in(window, async move |this, cx| {
 7362            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7363            this.update(cx, |this, cx| {
 7364                this.show_cursor_names = false;
 7365                cx.notify()
 7366            })
 7367            .ok()
 7368        })
 7369        .detach();
 7370    }
 7371
 7372    pub fn next_edit_prediction(
 7373        &mut self,
 7374        _: &NextEditPrediction,
 7375        window: &mut Window,
 7376        cx: &mut Context<Self>,
 7377    ) {
 7378        if self.has_active_edit_prediction() {
 7379            self.cycle_edit_prediction(Direction::Next, window, cx);
 7380        } else {
 7381            let is_copilot_disabled = self
 7382                .refresh_edit_prediction(false, true, window, cx)
 7383                .is_none();
 7384            if is_copilot_disabled {
 7385                cx.propagate();
 7386            }
 7387        }
 7388    }
 7389
 7390    pub fn previous_edit_prediction(
 7391        &mut self,
 7392        _: &PreviousEditPrediction,
 7393        window: &mut Window,
 7394        cx: &mut Context<Self>,
 7395    ) {
 7396        if self.has_active_edit_prediction() {
 7397            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7398        } else {
 7399            let is_copilot_disabled = self
 7400                .refresh_edit_prediction(false, true, window, cx)
 7401                .is_none();
 7402            if is_copilot_disabled {
 7403                cx.propagate();
 7404            }
 7405        }
 7406    }
 7407
 7408    pub fn accept_edit_prediction(
 7409        &mut self,
 7410        _: &AcceptEditPrediction,
 7411        window: &mut Window,
 7412        cx: &mut Context<Self>,
 7413    ) {
 7414        if self.show_edit_predictions_in_menu() {
 7415            self.hide_context_menu(window, cx);
 7416        }
 7417
 7418        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7419            return;
 7420        };
 7421
 7422        match &active_edit_prediction.completion {
 7423            EditPrediction::MoveWithin { target, .. } => {
 7424                let target = *target;
 7425
 7426                if let Some(position_map) = &self.last_position_map {
 7427                    if position_map
 7428                        .visible_row_range
 7429                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7430                        || !self.edit_prediction_requires_modifier()
 7431                    {
 7432                        self.unfold_ranges(&[target..target], true, false, cx);
 7433                        // Note that this is also done in vim's handler of the Tab action.
 7434                        self.change_selections(
 7435                            SelectionEffects::scroll(Autoscroll::newest()),
 7436                            window,
 7437                            cx,
 7438                            |selections| {
 7439                                selections.select_anchor_ranges([target..target]);
 7440                            },
 7441                        );
 7442                        self.clear_row_highlights::<EditPredictionPreview>();
 7443
 7444                        self.edit_prediction_preview
 7445                            .set_previous_scroll_position(None);
 7446                    } else {
 7447                        self.edit_prediction_preview
 7448                            .set_previous_scroll_position(Some(
 7449                                position_map.snapshot.scroll_anchor,
 7450                            ));
 7451
 7452                        self.highlight_rows::<EditPredictionPreview>(
 7453                            target..target,
 7454                            cx.theme().colors().editor_highlighted_line_background,
 7455                            RowHighlightOptions {
 7456                                autoscroll: true,
 7457                                ..Default::default()
 7458                            },
 7459                            cx,
 7460                        );
 7461                        self.request_autoscroll(Autoscroll::fit(), cx);
 7462                    }
 7463                }
 7464            }
 7465            EditPrediction::MoveOutside { snapshot, target } => {
 7466                if let Some(workspace) = self.workspace() {
 7467                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7468                        .detach_and_log_err(cx);
 7469                }
 7470            }
 7471            EditPrediction::Edit { edits, .. } => {
 7472                self.report_edit_prediction_event(
 7473                    active_edit_prediction.completion_id.clone(),
 7474                    true,
 7475                    cx,
 7476                );
 7477
 7478                if let Some(provider) = self.edit_prediction_provider() {
 7479                    provider.accept(cx);
 7480                }
 7481
 7482                // Store the transaction ID and selections before applying the edit
 7483                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7484
 7485                let snapshot = self.buffer.read(cx).snapshot(cx);
 7486                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7487
 7488                self.buffer.update(cx, |buffer, cx| {
 7489                    buffer.edit(edits.iter().cloned(), None, cx)
 7490                });
 7491
 7492                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7493                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7494                });
 7495
 7496                let selections = self.selections.disjoint_anchors_arc();
 7497                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7498                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7499                    if has_new_transaction {
 7500                        self.selection_history
 7501                            .insert_transaction(transaction_id_now, selections);
 7502                    }
 7503                }
 7504
 7505                self.update_visible_edit_prediction(window, cx);
 7506                if self.active_edit_prediction.is_none() {
 7507                    self.refresh_edit_prediction(true, true, window, cx);
 7508                }
 7509
 7510                cx.notify();
 7511            }
 7512        }
 7513
 7514        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7515    }
 7516
 7517    pub fn accept_partial_edit_prediction(
 7518        &mut self,
 7519        _: &AcceptPartialEditPrediction,
 7520        window: &mut Window,
 7521        cx: &mut Context<Self>,
 7522    ) {
 7523        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7524            return;
 7525        };
 7526        if self.selections.count() != 1 {
 7527            return;
 7528        }
 7529
 7530        match &active_edit_prediction.completion {
 7531            EditPrediction::MoveWithin { target, .. } => {
 7532                let target = *target;
 7533                self.change_selections(
 7534                    SelectionEffects::scroll(Autoscroll::newest()),
 7535                    window,
 7536                    cx,
 7537                    |selections| {
 7538                        selections.select_anchor_ranges([target..target]);
 7539                    },
 7540                );
 7541            }
 7542            EditPrediction::MoveOutside { snapshot, target } => {
 7543                if let Some(workspace) = self.workspace() {
 7544                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7545                        .detach_and_log_err(cx);
 7546                }
 7547            }
 7548            EditPrediction::Edit { edits, .. } => {
 7549                self.report_edit_prediction_event(
 7550                    active_edit_prediction.completion_id.clone(),
 7551                    true,
 7552                    cx,
 7553                );
 7554
 7555                // Find an insertion that starts at the cursor position.
 7556                let snapshot = self.buffer.read(cx).snapshot(cx);
 7557                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7558                let insertion = edits.iter().find_map(|(range, text)| {
 7559                    let range = range.to_offset(&snapshot);
 7560                    if range.is_empty() && range.start == cursor_offset {
 7561                        Some(text)
 7562                    } else {
 7563                        None
 7564                    }
 7565                });
 7566
 7567                if let Some(text) = insertion {
 7568                    let mut partial_completion = text
 7569                        .chars()
 7570                        .by_ref()
 7571                        .take_while(|c| c.is_alphabetic())
 7572                        .collect::<String>();
 7573                    if partial_completion.is_empty() {
 7574                        partial_completion = text
 7575                            .chars()
 7576                            .by_ref()
 7577                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7578                            .collect::<String>();
 7579                    }
 7580
 7581                    cx.emit(EditorEvent::InputHandled {
 7582                        utf16_range_to_replace: None,
 7583                        text: partial_completion.clone().into(),
 7584                    });
 7585
 7586                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7587
 7588                    self.refresh_edit_prediction(true, true, window, cx);
 7589                    cx.notify();
 7590                } else {
 7591                    self.accept_edit_prediction(&Default::default(), window, cx);
 7592                }
 7593            }
 7594        }
 7595    }
 7596
 7597    fn discard_edit_prediction(
 7598        &mut self,
 7599        should_report_edit_prediction_event: bool,
 7600        cx: &mut Context<Self>,
 7601    ) -> bool {
 7602        if should_report_edit_prediction_event {
 7603            let completion_id = self
 7604                .active_edit_prediction
 7605                .as_ref()
 7606                .and_then(|active_completion| active_completion.completion_id.clone());
 7607
 7608            self.report_edit_prediction_event(completion_id, false, cx);
 7609        }
 7610
 7611        if let Some(provider) = self.edit_prediction_provider() {
 7612            provider.discard(cx);
 7613        }
 7614
 7615        self.take_active_edit_prediction(cx)
 7616    }
 7617
 7618    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7619        let Some(provider) = self.edit_prediction_provider() else {
 7620            return;
 7621        };
 7622
 7623        let Some((_, buffer, _)) = self
 7624            .buffer
 7625            .read(cx)
 7626            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7627        else {
 7628            return;
 7629        };
 7630
 7631        let extension = buffer
 7632            .read(cx)
 7633            .file()
 7634            .and_then(|file| Some(file.path().extension()?.to_string()));
 7635
 7636        let event_type = match accepted {
 7637            true => "Edit Prediction Accepted",
 7638            false => "Edit Prediction Discarded",
 7639        };
 7640        telemetry::event!(
 7641            event_type,
 7642            provider = provider.name(),
 7643            prediction_id = id,
 7644            suggestion_accepted = accepted,
 7645            file_extension = extension,
 7646        );
 7647    }
 7648
 7649    fn open_editor_at_anchor(
 7650        snapshot: &language::BufferSnapshot,
 7651        target: language::Anchor,
 7652        workspace: &Entity<Workspace>,
 7653        window: &mut Window,
 7654        cx: &mut App,
 7655    ) -> Task<Result<()>> {
 7656        workspace.update(cx, |workspace, cx| {
 7657            let path = snapshot.file().map(|file| file.full_path(cx));
 7658            let Some(path) =
 7659                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7660            else {
 7661                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7662            };
 7663            let target = text::ToPoint::to_point(&target, snapshot);
 7664            let item = workspace.open_path(path, None, true, window, cx);
 7665            window.spawn(cx, async move |cx| {
 7666                let Some(editor) = item.await?.downcast::<Editor>() else {
 7667                    return Ok(());
 7668                };
 7669                editor
 7670                    .update_in(cx, |editor, window, cx| {
 7671                        editor.go_to_singleton_buffer_point(target, window, cx);
 7672                    })
 7673                    .ok();
 7674                anyhow::Ok(())
 7675            })
 7676        })
 7677    }
 7678
 7679    pub fn has_active_edit_prediction(&self) -> bool {
 7680        self.active_edit_prediction.is_some()
 7681    }
 7682
 7683    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7684        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7685            return false;
 7686        };
 7687
 7688        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7689        self.clear_highlights::<EditPredictionHighlight>(cx);
 7690        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7691        true
 7692    }
 7693
 7694    /// Returns true when we're displaying the edit prediction popover below the cursor
 7695    /// like we are not previewing and the LSP autocomplete menu is visible
 7696    /// or we are in `when_holding_modifier` mode.
 7697    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7698        if self.edit_prediction_preview_is_active()
 7699            || !self.show_edit_predictions_in_menu()
 7700            || !self.edit_predictions_enabled()
 7701        {
 7702            return false;
 7703        }
 7704
 7705        if self.has_visible_completions_menu() {
 7706            return true;
 7707        }
 7708
 7709        has_completion && self.edit_prediction_requires_modifier()
 7710    }
 7711
 7712    fn handle_modifiers_changed(
 7713        &mut self,
 7714        modifiers: Modifiers,
 7715        position_map: &PositionMap,
 7716        window: &mut Window,
 7717        cx: &mut Context<Self>,
 7718    ) {
 7719        if self.show_edit_predictions_in_menu() {
 7720            self.update_edit_prediction_preview(&modifiers, window, cx);
 7721        }
 7722
 7723        self.update_selection_mode(&modifiers, position_map, window, cx);
 7724
 7725        let mouse_position = window.mouse_position();
 7726        if !position_map.text_hitbox.is_hovered(window) {
 7727            return;
 7728        }
 7729
 7730        self.update_hovered_link(
 7731            position_map.point_for_position(mouse_position),
 7732            &position_map.snapshot,
 7733            modifiers,
 7734            window,
 7735            cx,
 7736        )
 7737    }
 7738
 7739    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7740        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7741        if invert {
 7742            match multi_cursor_setting {
 7743                MultiCursorModifier::Alt => modifiers.alt,
 7744                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7745            }
 7746        } else {
 7747            match multi_cursor_setting {
 7748                MultiCursorModifier::Alt => modifiers.secondary(),
 7749                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7750            }
 7751        }
 7752    }
 7753
 7754    fn columnar_selection_mode(
 7755        modifiers: &Modifiers,
 7756        cx: &mut Context<Self>,
 7757    ) -> Option<ColumnarMode> {
 7758        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7759            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7760                Some(ColumnarMode::FromMouse)
 7761            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7762                Some(ColumnarMode::FromSelection)
 7763            } else {
 7764                None
 7765            }
 7766        } else {
 7767            None
 7768        }
 7769    }
 7770
 7771    fn update_selection_mode(
 7772        &mut self,
 7773        modifiers: &Modifiers,
 7774        position_map: &PositionMap,
 7775        window: &mut Window,
 7776        cx: &mut Context<Self>,
 7777    ) {
 7778        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7779            return;
 7780        };
 7781        if self.selections.pending_anchor().is_none() {
 7782            return;
 7783        }
 7784
 7785        let mouse_position = window.mouse_position();
 7786        let point_for_position = position_map.point_for_position(mouse_position);
 7787        let position = point_for_position.previous_valid;
 7788
 7789        self.select(
 7790            SelectPhase::BeginColumnar {
 7791                position,
 7792                reset: false,
 7793                mode,
 7794                goal_column: point_for_position.exact_unclipped.column(),
 7795            },
 7796            window,
 7797            cx,
 7798        );
 7799    }
 7800
 7801    fn update_edit_prediction_preview(
 7802        &mut self,
 7803        modifiers: &Modifiers,
 7804        window: &mut Window,
 7805        cx: &mut Context<Self>,
 7806    ) {
 7807        let mut modifiers_held = false;
 7808        if let Some(accept_keystroke) = self
 7809            .accept_edit_prediction_keybind(false, window, cx)
 7810            .keystroke()
 7811        {
 7812            modifiers_held = modifiers_held
 7813                || (accept_keystroke.modifiers() == modifiers
 7814                    && accept_keystroke.modifiers().modified());
 7815        };
 7816        if let Some(accept_partial_keystroke) = self
 7817            .accept_edit_prediction_keybind(true, window, cx)
 7818            .keystroke()
 7819        {
 7820            modifiers_held = modifiers_held
 7821                || (accept_partial_keystroke.modifiers() == modifiers
 7822                    && accept_partial_keystroke.modifiers().modified());
 7823        }
 7824
 7825        if modifiers_held {
 7826            if matches!(
 7827                self.edit_prediction_preview,
 7828                EditPredictionPreview::Inactive { .. }
 7829            ) {
 7830                self.edit_prediction_preview = EditPredictionPreview::Active {
 7831                    previous_scroll_position: None,
 7832                    since: Instant::now(),
 7833                };
 7834
 7835                self.update_visible_edit_prediction(window, cx);
 7836                cx.notify();
 7837            }
 7838        } else if let EditPredictionPreview::Active {
 7839            previous_scroll_position,
 7840            since,
 7841        } = self.edit_prediction_preview
 7842        {
 7843            if let (Some(previous_scroll_position), Some(position_map)) =
 7844                (previous_scroll_position, self.last_position_map.as_ref())
 7845            {
 7846                self.set_scroll_position(
 7847                    previous_scroll_position
 7848                        .scroll_position(&position_map.snapshot.display_snapshot),
 7849                    window,
 7850                    cx,
 7851                );
 7852            }
 7853
 7854            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7855                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7856            };
 7857            self.clear_row_highlights::<EditPredictionPreview>();
 7858            self.update_visible_edit_prediction(window, cx);
 7859            cx.notify();
 7860        }
 7861    }
 7862
 7863    fn update_visible_edit_prediction(
 7864        &mut self,
 7865        _window: &mut Window,
 7866        cx: &mut Context<Self>,
 7867    ) -> Option<()> {
 7868        if DisableAiSettings::get_global(cx).disable_ai {
 7869            return None;
 7870        }
 7871
 7872        if self.ime_transaction.is_some() {
 7873            self.discard_edit_prediction(false, cx);
 7874            return None;
 7875        }
 7876
 7877        let selection = self.selections.newest_anchor();
 7878        let cursor = selection.head();
 7879        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7880        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7881        let excerpt_id = cursor.excerpt_id;
 7882
 7883        let show_in_menu = self.show_edit_predictions_in_menu();
 7884        let completions_menu_has_precedence = !show_in_menu
 7885            && (self.context_menu.borrow().is_some()
 7886                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7887
 7888        if completions_menu_has_precedence
 7889            || !offset_selection.is_empty()
 7890            || self
 7891                .active_edit_prediction
 7892                .as_ref()
 7893                .is_some_and(|completion| {
 7894                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7895                        return false;
 7896                    };
 7897                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7898                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7899                    !invalidation_range.contains(&offset_selection.head())
 7900                })
 7901        {
 7902            self.discard_edit_prediction(false, cx);
 7903            return None;
 7904        }
 7905
 7906        self.take_active_edit_prediction(cx);
 7907        let Some(provider) = self.edit_prediction_provider() else {
 7908            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7909            return None;
 7910        };
 7911
 7912        let (buffer, cursor_buffer_position) =
 7913            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7914
 7915        self.edit_prediction_settings =
 7916            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7917
 7918        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7919
 7920        if self.edit_prediction_indent_conflict {
 7921            let cursor_point = cursor.to_point(&multibuffer);
 7922
 7923            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7924
 7925            if let Some((_, indent)) = indents.iter().next()
 7926                && indent.len == cursor_point.column
 7927            {
 7928                self.edit_prediction_indent_conflict = false;
 7929            }
 7930        }
 7931
 7932        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7933
 7934        let (completion_id, edits, edit_preview) = match edit_prediction {
 7935            edit_prediction::EditPrediction::Local {
 7936                id,
 7937                edits,
 7938                edit_preview,
 7939            } => (id, edits, edit_preview),
 7940            edit_prediction::EditPrediction::Jump {
 7941                id,
 7942                snapshot,
 7943                target,
 7944            } => {
 7945                self.stale_edit_prediction_in_menu = None;
 7946                self.active_edit_prediction = Some(EditPredictionState {
 7947                    inlay_ids: vec![],
 7948                    completion: EditPrediction::MoveOutside { snapshot, target },
 7949                    completion_id: id,
 7950                    invalidation_range: None,
 7951                });
 7952                cx.notify();
 7953                return Some(());
 7954            }
 7955        };
 7956
 7957        let edits = edits
 7958            .into_iter()
 7959            .flat_map(|(range, new_text)| {
 7960                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7961                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7962                Some((start..end, new_text))
 7963            })
 7964            .collect::<Vec<_>>();
 7965        if edits.is_empty() {
 7966            return None;
 7967        }
 7968
 7969        let first_edit_start = edits.first().unwrap().0.start;
 7970        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7971        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7972
 7973        let last_edit_end = edits.last().unwrap().0.end;
 7974        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7975        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7976
 7977        let cursor_row = cursor.to_point(&multibuffer).row;
 7978
 7979        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7980
 7981        let mut inlay_ids = Vec::new();
 7982        let invalidation_row_range;
 7983        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7984            Some(cursor_row..edit_end_row)
 7985        } else if cursor_row > edit_end_row {
 7986            Some(edit_start_row..cursor_row)
 7987        } else {
 7988            None
 7989        };
 7990        let supports_jump = self
 7991            .edit_prediction_provider
 7992            .as_ref()
 7993            .map(|provider| provider.provider.supports_jump_to_edit())
 7994            .unwrap_or(true);
 7995
 7996        let is_move = supports_jump
 7997            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7998        let completion = if is_move {
 7999            invalidation_row_range =
 8000                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8001            let target = first_edit_start;
 8002            EditPrediction::MoveWithin { target, snapshot }
 8003        } else {
 8004            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8005                && !self.edit_predictions_hidden_for_vim_mode;
 8006
 8007            if show_completions_in_buffer {
 8008                if edits
 8009                    .iter()
 8010                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8011                {
 8012                    let mut inlays = Vec::new();
 8013                    for (range, new_text) in &edits {
 8014                        let inlay = Inlay::edit_prediction(
 8015                            post_inc(&mut self.next_inlay_id),
 8016                            range.start,
 8017                            new_text.as_str(),
 8018                        );
 8019                        inlay_ids.push(inlay.id);
 8020                        inlays.push(inlay);
 8021                    }
 8022
 8023                    self.splice_inlays(&[], inlays, cx);
 8024                } else {
 8025                    let background_color = cx.theme().status().deleted_background;
 8026                    self.highlight_text::<EditPredictionHighlight>(
 8027                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8028                        HighlightStyle {
 8029                            background_color: Some(background_color),
 8030                            ..Default::default()
 8031                        },
 8032                        cx,
 8033                    );
 8034                }
 8035            }
 8036
 8037            invalidation_row_range = edit_start_row..edit_end_row;
 8038
 8039            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8040                if provider.show_tab_accept_marker() {
 8041                    EditDisplayMode::TabAccept
 8042                } else {
 8043                    EditDisplayMode::Inline
 8044                }
 8045            } else {
 8046                EditDisplayMode::DiffPopover
 8047            };
 8048
 8049            EditPrediction::Edit {
 8050                edits,
 8051                edit_preview,
 8052                display_mode,
 8053                snapshot,
 8054            }
 8055        };
 8056
 8057        let invalidation_range = multibuffer
 8058            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8059            ..multibuffer.anchor_after(Point::new(
 8060                invalidation_row_range.end,
 8061                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8062            ));
 8063
 8064        self.stale_edit_prediction_in_menu = None;
 8065        self.active_edit_prediction = Some(EditPredictionState {
 8066            inlay_ids,
 8067            completion,
 8068            completion_id,
 8069            invalidation_range: Some(invalidation_range),
 8070        });
 8071
 8072        cx.notify();
 8073
 8074        Some(())
 8075    }
 8076
 8077    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8078        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8079    }
 8080
 8081    fn clear_tasks(&mut self) {
 8082        self.tasks.clear()
 8083    }
 8084
 8085    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8086        if self.tasks.insert(key, value).is_some() {
 8087            // This case should hopefully be rare, but just in case...
 8088            log::error!(
 8089                "multiple different run targets found on a single line, only the last target will be rendered"
 8090            )
 8091        }
 8092    }
 8093
 8094    /// Get all display points of breakpoints that will be rendered within editor
 8095    ///
 8096    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8097    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8098    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8099    fn active_breakpoints(
 8100        &self,
 8101        range: Range<DisplayRow>,
 8102        window: &mut Window,
 8103        cx: &mut Context<Self>,
 8104    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8105        let mut breakpoint_display_points = HashMap::default();
 8106
 8107        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8108            return breakpoint_display_points;
 8109        };
 8110
 8111        let snapshot = self.snapshot(window, cx);
 8112
 8113        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8114        let Some(project) = self.project() else {
 8115            return breakpoint_display_points;
 8116        };
 8117
 8118        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8119            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8120
 8121        for (buffer_snapshot, range, excerpt_id) in
 8122            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8123        {
 8124            let Some(buffer) = project
 8125                .read(cx)
 8126                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8127            else {
 8128                continue;
 8129            };
 8130            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8131                &buffer,
 8132                Some(
 8133                    buffer_snapshot.anchor_before(range.start)
 8134                        ..buffer_snapshot.anchor_after(range.end),
 8135                ),
 8136                buffer_snapshot,
 8137                cx,
 8138            );
 8139            for (breakpoint, state) in breakpoints {
 8140                let multi_buffer_anchor =
 8141                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8142                let position = multi_buffer_anchor
 8143                    .to_point(multi_buffer_snapshot)
 8144                    .to_display_point(&snapshot);
 8145
 8146                breakpoint_display_points.insert(
 8147                    position.row(),
 8148                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8149                );
 8150            }
 8151        }
 8152
 8153        breakpoint_display_points
 8154    }
 8155
 8156    fn breakpoint_context_menu(
 8157        &self,
 8158        anchor: Anchor,
 8159        window: &mut Window,
 8160        cx: &mut Context<Self>,
 8161    ) -> Entity<ui::ContextMenu> {
 8162        let weak_editor = cx.weak_entity();
 8163        let focus_handle = self.focus_handle(cx);
 8164
 8165        let row = self
 8166            .buffer
 8167            .read(cx)
 8168            .snapshot(cx)
 8169            .summary_for_anchor::<Point>(&anchor)
 8170            .row;
 8171
 8172        let breakpoint = self
 8173            .breakpoint_at_row(row, window, cx)
 8174            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8175
 8176        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8177            "Edit Log Breakpoint"
 8178        } else {
 8179            "Set Log Breakpoint"
 8180        };
 8181
 8182        let condition_breakpoint_msg = if breakpoint
 8183            .as_ref()
 8184            .is_some_and(|bp| bp.1.condition.is_some())
 8185        {
 8186            "Edit Condition Breakpoint"
 8187        } else {
 8188            "Set Condition Breakpoint"
 8189        };
 8190
 8191        let hit_condition_breakpoint_msg = if breakpoint
 8192            .as_ref()
 8193            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8194        {
 8195            "Edit Hit Condition Breakpoint"
 8196        } else {
 8197            "Set Hit Condition Breakpoint"
 8198        };
 8199
 8200        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8201            "Unset Breakpoint"
 8202        } else {
 8203            "Set Breakpoint"
 8204        };
 8205
 8206        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8207
 8208        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8209            BreakpointState::Enabled => Some("Disable"),
 8210            BreakpointState::Disabled => Some("Enable"),
 8211        });
 8212
 8213        let (anchor, breakpoint) =
 8214            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8215
 8216        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8217            menu.on_blur_subscription(Subscription::new(|| {}))
 8218                .context(focus_handle)
 8219                .when(run_to_cursor, |this| {
 8220                    let weak_editor = weak_editor.clone();
 8221                    this.entry("Run to cursor", None, move |window, cx| {
 8222                        weak_editor
 8223                            .update(cx, |editor, cx| {
 8224                                editor.change_selections(
 8225                                    SelectionEffects::no_scroll(),
 8226                                    window,
 8227                                    cx,
 8228                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8229                                );
 8230                            })
 8231                            .ok();
 8232
 8233                        window.dispatch_action(Box::new(RunToCursor), cx);
 8234                    })
 8235                    .separator()
 8236                })
 8237                .when_some(toggle_state_msg, |this, msg| {
 8238                    this.entry(msg, None, {
 8239                        let weak_editor = weak_editor.clone();
 8240                        let breakpoint = breakpoint.clone();
 8241                        move |_window, cx| {
 8242                            weak_editor
 8243                                .update(cx, |this, cx| {
 8244                                    this.edit_breakpoint_at_anchor(
 8245                                        anchor,
 8246                                        breakpoint.as_ref().clone(),
 8247                                        BreakpointEditAction::InvertState,
 8248                                        cx,
 8249                                    );
 8250                                })
 8251                                .log_err();
 8252                        }
 8253                    })
 8254                })
 8255                .entry(set_breakpoint_msg, None, {
 8256                    let weak_editor = weak_editor.clone();
 8257                    let breakpoint = breakpoint.clone();
 8258                    move |_window, cx| {
 8259                        weak_editor
 8260                            .update(cx, |this, cx| {
 8261                                this.edit_breakpoint_at_anchor(
 8262                                    anchor,
 8263                                    breakpoint.as_ref().clone(),
 8264                                    BreakpointEditAction::Toggle,
 8265                                    cx,
 8266                                );
 8267                            })
 8268                            .log_err();
 8269                    }
 8270                })
 8271                .entry(log_breakpoint_msg, None, {
 8272                    let breakpoint = breakpoint.clone();
 8273                    let weak_editor = weak_editor.clone();
 8274                    move |window, cx| {
 8275                        weak_editor
 8276                            .update(cx, |this, cx| {
 8277                                this.add_edit_breakpoint_block(
 8278                                    anchor,
 8279                                    breakpoint.as_ref(),
 8280                                    BreakpointPromptEditAction::Log,
 8281                                    window,
 8282                                    cx,
 8283                                );
 8284                            })
 8285                            .log_err();
 8286                    }
 8287                })
 8288                .entry(condition_breakpoint_msg, None, {
 8289                    let breakpoint = breakpoint.clone();
 8290                    let weak_editor = weak_editor.clone();
 8291                    move |window, cx| {
 8292                        weak_editor
 8293                            .update(cx, |this, cx| {
 8294                                this.add_edit_breakpoint_block(
 8295                                    anchor,
 8296                                    breakpoint.as_ref(),
 8297                                    BreakpointPromptEditAction::Condition,
 8298                                    window,
 8299                                    cx,
 8300                                );
 8301                            })
 8302                            .log_err();
 8303                    }
 8304                })
 8305                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8306                    weak_editor
 8307                        .update(cx, |this, cx| {
 8308                            this.add_edit_breakpoint_block(
 8309                                anchor,
 8310                                breakpoint.as_ref(),
 8311                                BreakpointPromptEditAction::HitCondition,
 8312                                window,
 8313                                cx,
 8314                            );
 8315                        })
 8316                        .log_err();
 8317                })
 8318        })
 8319    }
 8320
 8321    fn render_breakpoint(
 8322        &self,
 8323        position: Anchor,
 8324        row: DisplayRow,
 8325        breakpoint: &Breakpoint,
 8326        state: Option<BreakpointSessionState>,
 8327        cx: &mut Context<Self>,
 8328    ) -> IconButton {
 8329        let is_rejected = state.is_some_and(|s| !s.verified);
 8330        // Is it a breakpoint that shows up when hovering over gutter?
 8331        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8332            (false, false),
 8333            |PhantomBreakpointIndicator {
 8334                 is_active,
 8335                 display_row,
 8336                 collides_with_existing_breakpoint,
 8337             }| {
 8338                (
 8339                    is_active && display_row == row,
 8340                    collides_with_existing_breakpoint,
 8341                )
 8342            },
 8343        );
 8344
 8345        let (color, icon) = {
 8346            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8347                (false, false) => ui::IconName::DebugBreakpoint,
 8348                (true, false) => ui::IconName::DebugLogBreakpoint,
 8349                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8350                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8351            };
 8352
 8353            let color = if is_phantom {
 8354                Color::Hint
 8355            } else if is_rejected {
 8356                Color::Disabled
 8357            } else {
 8358                Color::Debugger
 8359            };
 8360
 8361            (color, icon)
 8362        };
 8363
 8364        let breakpoint = Arc::from(breakpoint.clone());
 8365
 8366        let alt_as_text = gpui::Keystroke {
 8367            modifiers: Modifiers::secondary_key(),
 8368            ..Default::default()
 8369        };
 8370        let primary_action_text = if breakpoint.is_disabled() {
 8371            "Enable breakpoint"
 8372        } else if is_phantom && !collides_with_existing {
 8373            "Set breakpoint"
 8374        } else {
 8375            "Unset breakpoint"
 8376        };
 8377        let focus_handle = self.focus_handle.clone();
 8378
 8379        let meta = if is_rejected {
 8380            SharedString::from("No executable code is associated with this line.")
 8381        } else if collides_with_existing && !breakpoint.is_disabled() {
 8382            SharedString::from(format!(
 8383                "{alt_as_text}-click to disable,\nright-click for more options."
 8384            ))
 8385        } else {
 8386            SharedString::from("Right-click for more options.")
 8387        };
 8388        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8389            .icon_size(IconSize::XSmall)
 8390            .size(ui::ButtonSize::None)
 8391            .when(is_rejected, |this| {
 8392                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8393            })
 8394            .icon_color(color)
 8395            .style(ButtonStyle::Transparent)
 8396            .on_click(cx.listener({
 8397                move |editor, event: &ClickEvent, window, cx| {
 8398                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8399                        BreakpointEditAction::InvertState
 8400                    } else {
 8401                        BreakpointEditAction::Toggle
 8402                    };
 8403
 8404                    window.focus(&editor.focus_handle(cx));
 8405                    editor.edit_breakpoint_at_anchor(
 8406                        position,
 8407                        breakpoint.as_ref().clone(),
 8408                        edit_action,
 8409                        cx,
 8410                    );
 8411                }
 8412            }))
 8413            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8414                editor.set_breakpoint_context_menu(
 8415                    row,
 8416                    Some(position),
 8417                    event.position(),
 8418                    window,
 8419                    cx,
 8420                );
 8421            }))
 8422            .tooltip(move |window, cx| {
 8423                Tooltip::with_meta_in(
 8424                    primary_action_text,
 8425                    Some(&ToggleBreakpoint),
 8426                    meta.clone(),
 8427                    &focus_handle,
 8428                    window,
 8429                    cx,
 8430                )
 8431            })
 8432    }
 8433
 8434    fn build_tasks_context(
 8435        project: &Entity<Project>,
 8436        buffer: &Entity<Buffer>,
 8437        buffer_row: u32,
 8438        tasks: &Arc<RunnableTasks>,
 8439        cx: &mut Context<Self>,
 8440    ) -> Task<Option<task::TaskContext>> {
 8441        let position = Point::new(buffer_row, tasks.column);
 8442        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8443        let location = Location {
 8444            buffer: buffer.clone(),
 8445            range: range_start..range_start,
 8446        };
 8447        // Fill in the environmental variables from the tree-sitter captures
 8448        let mut captured_task_variables = TaskVariables::default();
 8449        for (capture_name, value) in tasks.extra_variables.clone() {
 8450            captured_task_variables.insert(
 8451                task::VariableName::Custom(capture_name.into()),
 8452                value.clone(),
 8453            );
 8454        }
 8455        project.update(cx, |project, cx| {
 8456            project.task_store().update(cx, |task_store, cx| {
 8457                task_store.task_context_for_location(captured_task_variables, location, cx)
 8458            })
 8459        })
 8460    }
 8461
 8462    pub fn spawn_nearest_task(
 8463        &mut self,
 8464        action: &SpawnNearestTask,
 8465        window: &mut Window,
 8466        cx: &mut Context<Self>,
 8467    ) {
 8468        let Some((workspace, _)) = self.workspace.clone() else {
 8469            return;
 8470        };
 8471        let Some(project) = self.project.clone() else {
 8472            return;
 8473        };
 8474
 8475        // Try to find a closest, enclosing node using tree-sitter that has a task
 8476        let Some((buffer, buffer_row, tasks)) = self
 8477            .find_enclosing_node_task(cx)
 8478            // Or find the task that's closest in row-distance.
 8479            .or_else(|| self.find_closest_task(cx))
 8480        else {
 8481            return;
 8482        };
 8483
 8484        let reveal_strategy = action.reveal;
 8485        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8486        cx.spawn_in(window, async move |_, cx| {
 8487            let context = task_context.await?;
 8488            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8489
 8490            let resolved = &mut resolved_task.resolved;
 8491            resolved.reveal = reveal_strategy;
 8492
 8493            workspace
 8494                .update_in(cx, |workspace, window, cx| {
 8495                    workspace.schedule_resolved_task(
 8496                        task_source_kind,
 8497                        resolved_task,
 8498                        false,
 8499                        window,
 8500                        cx,
 8501                    );
 8502                })
 8503                .ok()
 8504        })
 8505        .detach();
 8506    }
 8507
 8508    fn find_closest_task(
 8509        &mut self,
 8510        cx: &mut Context<Self>,
 8511    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8512        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8513
 8514        let ((buffer_id, row), tasks) = self
 8515            .tasks
 8516            .iter()
 8517            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8518
 8519        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8520        let tasks = Arc::new(tasks.to_owned());
 8521        Some((buffer, *row, tasks))
 8522    }
 8523
 8524    fn find_enclosing_node_task(
 8525        &mut self,
 8526        cx: &mut Context<Self>,
 8527    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8528        let snapshot = self.buffer.read(cx).snapshot(cx);
 8529        let offset = self.selections.newest::<usize>(cx).head();
 8530        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8531        let buffer_id = excerpt.buffer().remote_id();
 8532
 8533        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8534        let mut cursor = layer.node().walk();
 8535
 8536        while cursor.goto_first_child_for_byte(offset).is_some() {
 8537            if cursor.node().end_byte() == offset {
 8538                cursor.goto_next_sibling();
 8539            }
 8540        }
 8541
 8542        // Ascend to the smallest ancestor that contains the range and has a task.
 8543        loop {
 8544            let node = cursor.node();
 8545            let node_range = node.byte_range();
 8546            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8547
 8548            // Check if this node contains our offset
 8549            if node_range.start <= offset && node_range.end >= offset {
 8550                // If it contains offset, check for task
 8551                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8552                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8553                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8554                }
 8555            }
 8556
 8557            if !cursor.goto_parent() {
 8558                break;
 8559            }
 8560        }
 8561        None
 8562    }
 8563
 8564    fn render_run_indicator(
 8565        &self,
 8566        _style: &EditorStyle,
 8567        is_active: bool,
 8568        row: DisplayRow,
 8569        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8570        cx: &mut Context<Self>,
 8571    ) -> IconButton {
 8572        let color = Color::Muted;
 8573        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8574
 8575        IconButton::new(
 8576            ("run_indicator", row.0 as usize),
 8577            ui::IconName::PlayOutlined,
 8578        )
 8579        .shape(ui::IconButtonShape::Square)
 8580        .icon_size(IconSize::XSmall)
 8581        .icon_color(color)
 8582        .toggle_state(is_active)
 8583        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8584            let quick_launch = match e {
 8585                ClickEvent::Keyboard(_) => true,
 8586                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8587            };
 8588
 8589            window.focus(&editor.focus_handle(cx));
 8590            editor.toggle_code_actions(
 8591                &ToggleCodeActions {
 8592                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8593                    quick_launch,
 8594                },
 8595                window,
 8596                cx,
 8597            );
 8598        }))
 8599        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8600            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8601        }))
 8602    }
 8603
 8604    pub fn context_menu_visible(&self) -> bool {
 8605        !self.edit_prediction_preview_is_active()
 8606            && self
 8607                .context_menu
 8608                .borrow()
 8609                .as_ref()
 8610                .is_some_and(|menu| menu.visible())
 8611    }
 8612
 8613    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8614        self.context_menu
 8615            .borrow()
 8616            .as_ref()
 8617            .map(|menu| menu.origin())
 8618    }
 8619
 8620    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8621        self.context_menu_options = Some(options);
 8622    }
 8623
 8624    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8625    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8626
 8627    fn render_edit_prediction_popover(
 8628        &mut self,
 8629        text_bounds: &Bounds<Pixels>,
 8630        content_origin: gpui::Point<Pixels>,
 8631        right_margin: Pixels,
 8632        editor_snapshot: &EditorSnapshot,
 8633        visible_row_range: Range<DisplayRow>,
 8634        scroll_top: f32,
 8635        scroll_bottom: f32,
 8636        line_layouts: &[LineWithInvisibles],
 8637        line_height: Pixels,
 8638        scroll_pixel_position: gpui::Point<Pixels>,
 8639        newest_selection_head: Option<DisplayPoint>,
 8640        editor_width: Pixels,
 8641        style: &EditorStyle,
 8642        window: &mut Window,
 8643        cx: &mut App,
 8644    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8645        if self.mode().is_minimap() {
 8646            return None;
 8647        }
 8648        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8649
 8650        if self.edit_prediction_visible_in_cursor_popover(true) {
 8651            return None;
 8652        }
 8653
 8654        match &active_edit_prediction.completion {
 8655            EditPrediction::MoveWithin { target, .. } => {
 8656                let target_display_point = target.to_display_point(editor_snapshot);
 8657
 8658                if self.edit_prediction_requires_modifier() {
 8659                    if !self.edit_prediction_preview_is_active() {
 8660                        return None;
 8661                    }
 8662
 8663                    self.render_edit_prediction_modifier_jump_popover(
 8664                        text_bounds,
 8665                        content_origin,
 8666                        visible_row_range,
 8667                        line_layouts,
 8668                        line_height,
 8669                        scroll_pixel_position,
 8670                        newest_selection_head,
 8671                        target_display_point,
 8672                        window,
 8673                        cx,
 8674                    )
 8675                } else {
 8676                    self.render_edit_prediction_eager_jump_popover(
 8677                        text_bounds,
 8678                        content_origin,
 8679                        editor_snapshot,
 8680                        visible_row_range,
 8681                        scroll_top,
 8682                        scroll_bottom,
 8683                        line_height,
 8684                        scroll_pixel_position,
 8685                        target_display_point,
 8686                        editor_width,
 8687                        window,
 8688                        cx,
 8689                    )
 8690                }
 8691            }
 8692            EditPrediction::Edit {
 8693                display_mode: EditDisplayMode::Inline,
 8694                ..
 8695            } => None,
 8696            EditPrediction::Edit {
 8697                display_mode: EditDisplayMode::TabAccept,
 8698                edits,
 8699                ..
 8700            } => {
 8701                let range = &edits.first()?.0;
 8702                let target_display_point = range.end.to_display_point(editor_snapshot);
 8703
 8704                self.render_edit_prediction_end_of_line_popover(
 8705                    "Accept",
 8706                    editor_snapshot,
 8707                    visible_row_range,
 8708                    target_display_point,
 8709                    line_height,
 8710                    scroll_pixel_position,
 8711                    content_origin,
 8712                    editor_width,
 8713                    window,
 8714                    cx,
 8715                )
 8716            }
 8717            EditPrediction::Edit {
 8718                edits,
 8719                edit_preview,
 8720                display_mode: EditDisplayMode::DiffPopover,
 8721                snapshot,
 8722            } => self.render_edit_prediction_diff_popover(
 8723                text_bounds,
 8724                content_origin,
 8725                right_margin,
 8726                editor_snapshot,
 8727                visible_row_range,
 8728                line_layouts,
 8729                line_height,
 8730                scroll_pixel_position,
 8731                newest_selection_head,
 8732                editor_width,
 8733                style,
 8734                edits,
 8735                edit_preview,
 8736                snapshot,
 8737                window,
 8738                cx,
 8739            ),
 8740            EditPrediction::MoveOutside { snapshot, .. } => {
 8741                let file_name = snapshot
 8742                    .file()
 8743                    .map(|file| file.file_name(cx))
 8744                    .unwrap_or("untitled");
 8745                let mut element = self
 8746                    .render_edit_prediction_line_popover(
 8747                        format!("Jump to {file_name}"),
 8748                        Some(IconName::ZedPredict),
 8749                        window,
 8750                        cx,
 8751                    )
 8752                    .into_any();
 8753
 8754                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8755                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8756                let origin_y = text_bounds.size.height - size.height - px(30.);
 8757                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8758                element.prepaint_at(origin, window, cx);
 8759
 8760                Some((element, origin))
 8761            }
 8762        }
 8763    }
 8764
 8765    fn render_edit_prediction_modifier_jump_popover(
 8766        &mut self,
 8767        text_bounds: &Bounds<Pixels>,
 8768        content_origin: gpui::Point<Pixels>,
 8769        visible_row_range: Range<DisplayRow>,
 8770        line_layouts: &[LineWithInvisibles],
 8771        line_height: Pixels,
 8772        scroll_pixel_position: gpui::Point<Pixels>,
 8773        newest_selection_head: Option<DisplayPoint>,
 8774        target_display_point: DisplayPoint,
 8775        window: &mut Window,
 8776        cx: &mut App,
 8777    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8778        let scrolled_content_origin =
 8779            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8780
 8781        const SCROLL_PADDING_Y: Pixels = px(12.);
 8782
 8783        if target_display_point.row() < visible_row_range.start {
 8784            return self.render_edit_prediction_scroll_popover(
 8785                |_| SCROLL_PADDING_Y,
 8786                IconName::ArrowUp,
 8787                visible_row_range,
 8788                line_layouts,
 8789                newest_selection_head,
 8790                scrolled_content_origin,
 8791                window,
 8792                cx,
 8793            );
 8794        } else if target_display_point.row() >= visible_row_range.end {
 8795            return self.render_edit_prediction_scroll_popover(
 8796                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8797                IconName::ArrowDown,
 8798                visible_row_range,
 8799                line_layouts,
 8800                newest_selection_head,
 8801                scrolled_content_origin,
 8802                window,
 8803                cx,
 8804            );
 8805        }
 8806
 8807        const POLE_WIDTH: Pixels = px(2.);
 8808
 8809        let line_layout =
 8810            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8811        let target_column = target_display_point.column() as usize;
 8812
 8813        let target_x = line_layout.x_for_index(target_column);
 8814        let target_y =
 8815            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8816
 8817        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8818
 8819        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8820        border_color.l += 0.001;
 8821
 8822        let mut element = v_flex()
 8823            .items_end()
 8824            .when(flag_on_right, |el| el.items_start())
 8825            .child(if flag_on_right {
 8826                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8827                    .rounded_bl(px(0.))
 8828                    .rounded_tl(px(0.))
 8829                    .border_l_2()
 8830                    .border_color(border_color)
 8831            } else {
 8832                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8833                    .rounded_br(px(0.))
 8834                    .rounded_tr(px(0.))
 8835                    .border_r_2()
 8836                    .border_color(border_color)
 8837            })
 8838            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8839            .into_any();
 8840
 8841        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8842
 8843        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8844            - point(
 8845                if flag_on_right {
 8846                    POLE_WIDTH
 8847                } else {
 8848                    size.width - POLE_WIDTH
 8849                },
 8850                size.height - line_height,
 8851            );
 8852
 8853        origin.x = origin.x.max(content_origin.x);
 8854
 8855        element.prepaint_at(origin, window, cx);
 8856
 8857        Some((element, origin))
 8858    }
 8859
 8860    fn render_edit_prediction_scroll_popover(
 8861        &mut self,
 8862        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8863        scroll_icon: IconName,
 8864        visible_row_range: Range<DisplayRow>,
 8865        line_layouts: &[LineWithInvisibles],
 8866        newest_selection_head: Option<DisplayPoint>,
 8867        scrolled_content_origin: gpui::Point<Pixels>,
 8868        window: &mut Window,
 8869        cx: &mut App,
 8870    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8871        let mut element = self
 8872            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8873            .into_any();
 8874
 8875        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8876
 8877        let cursor = newest_selection_head?;
 8878        let cursor_row_layout =
 8879            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8880        let cursor_column = cursor.column() as usize;
 8881
 8882        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8883
 8884        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8885
 8886        element.prepaint_at(origin, window, cx);
 8887        Some((element, origin))
 8888    }
 8889
 8890    fn render_edit_prediction_eager_jump_popover(
 8891        &mut self,
 8892        text_bounds: &Bounds<Pixels>,
 8893        content_origin: gpui::Point<Pixels>,
 8894        editor_snapshot: &EditorSnapshot,
 8895        visible_row_range: Range<DisplayRow>,
 8896        scroll_top: f32,
 8897        scroll_bottom: f32,
 8898        line_height: Pixels,
 8899        scroll_pixel_position: gpui::Point<Pixels>,
 8900        target_display_point: DisplayPoint,
 8901        editor_width: Pixels,
 8902        window: &mut Window,
 8903        cx: &mut App,
 8904    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8905        if target_display_point.row().as_f32() < scroll_top {
 8906            let mut element = self
 8907                .render_edit_prediction_line_popover(
 8908                    "Jump to Edit",
 8909                    Some(IconName::ArrowUp),
 8910                    window,
 8911                    cx,
 8912                )
 8913                .into_any();
 8914
 8915            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8916            let offset = point(
 8917                (text_bounds.size.width - size.width) / 2.,
 8918                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8919            );
 8920
 8921            let origin = text_bounds.origin + offset;
 8922            element.prepaint_at(origin, window, cx);
 8923            Some((element, origin))
 8924        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8925            let mut element = self
 8926                .render_edit_prediction_line_popover(
 8927                    "Jump to Edit",
 8928                    Some(IconName::ArrowDown),
 8929                    window,
 8930                    cx,
 8931                )
 8932                .into_any();
 8933
 8934            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8935            let offset = point(
 8936                (text_bounds.size.width - size.width) / 2.,
 8937                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8938            );
 8939
 8940            let origin = text_bounds.origin + offset;
 8941            element.prepaint_at(origin, window, cx);
 8942            Some((element, origin))
 8943        } else {
 8944            self.render_edit_prediction_end_of_line_popover(
 8945                "Jump to Edit",
 8946                editor_snapshot,
 8947                visible_row_range,
 8948                target_display_point,
 8949                line_height,
 8950                scroll_pixel_position,
 8951                content_origin,
 8952                editor_width,
 8953                window,
 8954                cx,
 8955            )
 8956        }
 8957    }
 8958
 8959    fn render_edit_prediction_end_of_line_popover(
 8960        self: &mut Editor,
 8961        label: &'static str,
 8962        editor_snapshot: &EditorSnapshot,
 8963        visible_row_range: Range<DisplayRow>,
 8964        target_display_point: DisplayPoint,
 8965        line_height: Pixels,
 8966        scroll_pixel_position: gpui::Point<Pixels>,
 8967        content_origin: gpui::Point<Pixels>,
 8968        editor_width: Pixels,
 8969        window: &mut Window,
 8970        cx: &mut App,
 8971    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8972        let target_line_end = DisplayPoint::new(
 8973            target_display_point.row(),
 8974            editor_snapshot.line_len(target_display_point.row()),
 8975        );
 8976
 8977        let mut element = self
 8978            .render_edit_prediction_line_popover(label, None, window, cx)
 8979            .into_any();
 8980
 8981        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8982
 8983        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8984
 8985        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8986        let mut origin = start_point
 8987            + line_origin
 8988            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8989        origin.x = origin.x.max(content_origin.x);
 8990
 8991        let max_x = content_origin.x + editor_width - size.width;
 8992
 8993        if origin.x > max_x {
 8994            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8995
 8996            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8997                origin.y += offset;
 8998                IconName::ArrowUp
 8999            } else {
 9000                origin.y -= offset;
 9001                IconName::ArrowDown
 9002            };
 9003
 9004            element = self
 9005                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9006                .into_any();
 9007
 9008            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9009
 9010            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9011        }
 9012
 9013        element.prepaint_at(origin, window, cx);
 9014        Some((element, origin))
 9015    }
 9016
 9017    fn render_edit_prediction_diff_popover(
 9018        self: &Editor,
 9019        text_bounds: &Bounds<Pixels>,
 9020        content_origin: gpui::Point<Pixels>,
 9021        right_margin: Pixels,
 9022        editor_snapshot: &EditorSnapshot,
 9023        visible_row_range: Range<DisplayRow>,
 9024        line_layouts: &[LineWithInvisibles],
 9025        line_height: Pixels,
 9026        scroll_pixel_position: gpui::Point<Pixels>,
 9027        newest_selection_head: Option<DisplayPoint>,
 9028        editor_width: Pixels,
 9029        style: &EditorStyle,
 9030        edits: &Vec<(Range<Anchor>, String)>,
 9031        edit_preview: &Option<language::EditPreview>,
 9032        snapshot: &language::BufferSnapshot,
 9033        window: &mut Window,
 9034        cx: &mut App,
 9035    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9036        let edit_start = edits
 9037            .first()
 9038            .unwrap()
 9039            .0
 9040            .start
 9041            .to_display_point(editor_snapshot);
 9042        let edit_end = edits
 9043            .last()
 9044            .unwrap()
 9045            .0
 9046            .end
 9047            .to_display_point(editor_snapshot);
 9048
 9049        let is_visible = visible_row_range.contains(&edit_start.row())
 9050            || visible_row_range.contains(&edit_end.row());
 9051        if !is_visible {
 9052            return None;
 9053        }
 9054
 9055        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9056            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9057        } else {
 9058            // Fallback for providers without edit_preview
 9059            crate::edit_prediction_fallback_text(edits, cx)
 9060        };
 9061
 9062        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9063        let line_count = highlighted_edits.text.lines().count();
 9064
 9065        const BORDER_WIDTH: Pixels = px(1.);
 9066
 9067        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9068        let has_keybind = keybind.is_some();
 9069
 9070        let mut element = h_flex()
 9071            .items_start()
 9072            .child(
 9073                h_flex()
 9074                    .bg(cx.theme().colors().editor_background)
 9075                    .border(BORDER_WIDTH)
 9076                    .shadow_xs()
 9077                    .border_color(cx.theme().colors().border)
 9078                    .rounded_l_lg()
 9079                    .when(line_count > 1, |el| el.rounded_br_lg())
 9080                    .pr_1()
 9081                    .child(styled_text),
 9082            )
 9083            .child(
 9084                h_flex()
 9085                    .h(line_height + BORDER_WIDTH * 2.)
 9086                    .px_1p5()
 9087                    .gap_1()
 9088                    // Workaround: For some reason, there's a gap if we don't do this
 9089                    .ml(-BORDER_WIDTH)
 9090                    .shadow(vec![gpui::BoxShadow {
 9091                        color: gpui::black().opacity(0.05),
 9092                        offset: point(px(1.), px(1.)),
 9093                        blur_radius: px(2.),
 9094                        spread_radius: px(0.),
 9095                    }])
 9096                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9097                    .border(BORDER_WIDTH)
 9098                    .border_color(cx.theme().colors().border)
 9099                    .rounded_r_lg()
 9100                    .id("edit_prediction_diff_popover_keybind")
 9101                    .when(!has_keybind, |el| {
 9102                        let status_colors = cx.theme().status();
 9103
 9104                        el.bg(status_colors.error_background)
 9105                            .border_color(status_colors.error.opacity(0.6))
 9106                            .child(Icon::new(IconName::Info).color(Color::Error))
 9107                            .cursor_default()
 9108                            .hoverable_tooltip(move |_window, cx| {
 9109                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9110                            })
 9111                    })
 9112                    .children(keybind),
 9113            )
 9114            .into_any();
 9115
 9116        let longest_row =
 9117            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9118        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9119            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9120        } else {
 9121            layout_line(
 9122                longest_row,
 9123                editor_snapshot,
 9124                style,
 9125                editor_width,
 9126                |_| false,
 9127                window,
 9128                cx,
 9129            )
 9130            .width
 9131        };
 9132
 9133        let viewport_bounds =
 9134            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9135                right: -right_margin,
 9136                ..Default::default()
 9137            });
 9138
 9139        let x_after_longest =
 9140            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9141                - scroll_pixel_position.x;
 9142
 9143        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9144
 9145        // Fully visible if it can be displayed within the window (allow overlapping other
 9146        // panes). However, this is only allowed if the popover starts within text_bounds.
 9147        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9148            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9149
 9150        let mut origin = if can_position_to_the_right {
 9151            point(
 9152                x_after_longest,
 9153                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9154                    - scroll_pixel_position.y,
 9155            )
 9156        } else {
 9157            let cursor_row = newest_selection_head.map(|head| head.row());
 9158            let above_edit = edit_start
 9159                .row()
 9160                .0
 9161                .checked_sub(line_count as u32)
 9162                .map(DisplayRow);
 9163            let below_edit = Some(edit_end.row() + 1);
 9164            let above_cursor =
 9165                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9166            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9167
 9168            // Place the edit popover adjacent to the edit if there is a location
 9169            // available that is onscreen and does not obscure the cursor. Otherwise,
 9170            // place it adjacent to the cursor.
 9171            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9172                .into_iter()
 9173                .flatten()
 9174                .find(|&start_row| {
 9175                    let end_row = start_row + line_count as u32;
 9176                    visible_row_range.contains(&start_row)
 9177                        && visible_row_range.contains(&end_row)
 9178                        && cursor_row
 9179                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9180                })?;
 9181
 9182            content_origin
 9183                + point(
 9184                    -scroll_pixel_position.x,
 9185                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9186                )
 9187        };
 9188
 9189        origin.x -= BORDER_WIDTH;
 9190
 9191        window.defer_draw(element, origin, 1);
 9192
 9193        // Do not return an element, since it will already be drawn due to defer_draw.
 9194        None
 9195    }
 9196
 9197    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9198        px(30.)
 9199    }
 9200
 9201    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9202        if self.read_only(cx) {
 9203            cx.theme().players().read_only()
 9204        } else {
 9205            self.style.as_ref().unwrap().local_player
 9206        }
 9207    }
 9208
 9209    fn render_edit_prediction_accept_keybind(
 9210        &self,
 9211        window: &mut Window,
 9212        cx: &App,
 9213    ) -> Option<AnyElement> {
 9214        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9215        let accept_keystroke = accept_binding.keystroke()?;
 9216
 9217        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9218
 9219        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9220            Color::Accent
 9221        } else {
 9222            Color::Muted
 9223        };
 9224
 9225        h_flex()
 9226            .px_0p5()
 9227            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9228            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9229            .text_size(TextSize::XSmall.rems(cx))
 9230            .child(h_flex().children(ui::render_modifiers(
 9231                accept_keystroke.modifiers(),
 9232                PlatformStyle::platform(),
 9233                Some(modifiers_color),
 9234                Some(IconSize::XSmall.rems().into()),
 9235                true,
 9236            )))
 9237            .when(is_platform_style_mac, |parent| {
 9238                parent.child(accept_keystroke.key().to_string())
 9239            })
 9240            .when(!is_platform_style_mac, |parent| {
 9241                parent.child(
 9242                    Key::new(
 9243                        util::capitalize(accept_keystroke.key()),
 9244                        Some(Color::Default),
 9245                    )
 9246                    .size(Some(IconSize::XSmall.rems().into())),
 9247                )
 9248            })
 9249            .into_any()
 9250            .into()
 9251    }
 9252
 9253    fn render_edit_prediction_line_popover(
 9254        &self,
 9255        label: impl Into<SharedString>,
 9256        icon: Option<IconName>,
 9257        window: &mut Window,
 9258        cx: &App,
 9259    ) -> Stateful<Div> {
 9260        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9261
 9262        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9263        let has_keybind = keybind.is_some();
 9264
 9265        h_flex()
 9266            .id("ep-line-popover")
 9267            .py_0p5()
 9268            .pl_1()
 9269            .pr(padding_right)
 9270            .gap_1()
 9271            .rounded_md()
 9272            .border_1()
 9273            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9274            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9275            .shadow_xs()
 9276            .when(!has_keybind, |el| {
 9277                let status_colors = cx.theme().status();
 9278
 9279                el.bg(status_colors.error_background)
 9280                    .border_color(status_colors.error.opacity(0.6))
 9281                    .pl_2()
 9282                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9283                    .cursor_default()
 9284                    .hoverable_tooltip(move |_window, cx| {
 9285                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9286                    })
 9287            })
 9288            .children(keybind)
 9289            .child(
 9290                Label::new(label)
 9291                    .size(LabelSize::Small)
 9292                    .when(!has_keybind, |el| {
 9293                        el.color(cx.theme().status().error.into()).strikethrough()
 9294                    }),
 9295            )
 9296            .when(!has_keybind, |el| {
 9297                el.child(
 9298                    h_flex().ml_1().child(
 9299                        Icon::new(IconName::Info)
 9300                            .size(IconSize::Small)
 9301                            .color(cx.theme().status().error.into()),
 9302                    ),
 9303                )
 9304            })
 9305            .when_some(icon, |element, icon| {
 9306                element.child(
 9307                    div()
 9308                        .mt(px(1.5))
 9309                        .child(Icon::new(icon).size(IconSize::Small)),
 9310                )
 9311            })
 9312    }
 9313
 9314    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9315        let accent_color = cx.theme().colors().text_accent;
 9316        let editor_bg_color = cx.theme().colors().editor_background;
 9317        editor_bg_color.blend(accent_color.opacity(0.1))
 9318    }
 9319
 9320    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9321        let accent_color = cx.theme().colors().text_accent;
 9322        let editor_bg_color = cx.theme().colors().editor_background;
 9323        editor_bg_color.blend(accent_color.opacity(0.6))
 9324    }
 9325    fn get_prediction_provider_icon_name(
 9326        provider: &Option<RegisteredEditPredictionProvider>,
 9327    ) -> IconName {
 9328        match provider {
 9329            Some(provider) => match provider.provider.name() {
 9330                "copilot" => IconName::Copilot,
 9331                "supermaven" => IconName::Supermaven,
 9332                _ => IconName::ZedPredict,
 9333            },
 9334            None => IconName::ZedPredict,
 9335        }
 9336    }
 9337
 9338    fn render_edit_prediction_cursor_popover(
 9339        &self,
 9340        min_width: Pixels,
 9341        max_width: Pixels,
 9342        cursor_point: Point,
 9343        style: &EditorStyle,
 9344        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9345        _window: &Window,
 9346        cx: &mut Context<Editor>,
 9347    ) -> Option<AnyElement> {
 9348        let provider = self.edit_prediction_provider.as_ref()?;
 9349        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9350
 9351        let is_refreshing = provider.provider.is_refreshing(cx);
 9352
 9353        fn pending_completion_container(icon: IconName) -> Div {
 9354            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9355        }
 9356
 9357        let completion = match &self.active_edit_prediction {
 9358            Some(prediction) => {
 9359                if !self.has_visible_completions_menu() {
 9360                    const RADIUS: Pixels = px(6.);
 9361                    const BORDER_WIDTH: Pixels = px(1.);
 9362
 9363                    return Some(
 9364                        h_flex()
 9365                            .elevation_2(cx)
 9366                            .border(BORDER_WIDTH)
 9367                            .border_color(cx.theme().colors().border)
 9368                            .when(accept_keystroke.is_none(), |el| {
 9369                                el.border_color(cx.theme().status().error)
 9370                            })
 9371                            .rounded(RADIUS)
 9372                            .rounded_tl(px(0.))
 9373                            .overflow_hidden()
 9374                            .child(div().px_1p5().child(match &prediction.completion {
 9375                                EditPrediction::MoveWithin { target, snapshot } => {
 9376                                    use text::ToPoint as _;
 9377                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9378                                    {
 9379                                        Icon::new(IconName::ZedPredictDown)
 9380                                    } else {
 9381                                        Icon::new(IconName::ZedPredictUp)
 9382                                    }
 9383                                }
 9384                                EditPrediction::MoveOutside { .. } => {
 9385                                    // TODO [zeta2] custom icon for external jump?
 9386                                    Icon::new(provider_icon)
 9387                                }
 9388                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9389                            }))
 9390                            .child(
 9391                                h_flex()
 9392                                    .gap_1()
 9393                                    .py_1()
 9394                                    .px_2()
 9395                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9396                                    .border_l_1()
 9397                                    .border_color(cx.theme().colors().border)
 9398                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9399                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9400                                        el.child(
 9401                                            Label::new("Hold")
 9402                                                .size(LabelSize::Small)
 9403                                                .when(accept_keystroke.is_none(), |el| {
 9404                                                    el.strikethrough()
 9405                                                })
 9406                                                .line_height_style(LineHeightStyle::UiLabel),
 9407                                        )
 9408                                    })
 9409                                    .id("edit_prediction_cursor_popover_keybind")
 9410                                    .when(accept_keystroke.is_none(), |el| {
 9411                                        let status_colors = cx.theme().status();
 9412
 9413                                        el.bg(status_colors.error_background)
 9414                                            .border_color(status_colors.error.opacity(0.6))
 9415                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9416                                            .cursor_default()
 9417                                            .hoverable_tooltip(move |_window, cx| {
 9418                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9419                                                    .into()
 9420                                            })
 9421                                    })
 9422                                    .when_some(
 9423                                        accept_keystroke.as_ref(),
 9424                                        |el, accept_keystroke| {
 9425                                            el.child(h_flex().children(ui::render_modifiers(
 9426                                                accept_keystroke.modifiers(),
 9427                                                PlatformStyle::platform(),
 9428                                                Some(Color::Default),
 9429                                                Some(IconSize::XSmall.rems().into()),
 9430                                                false,
 9431                                            )))
 9432                                        },
 9433                                    ),
 9434                            )
 9435                            .into_any(),
 9436                    );
 9437                }
 9438
 9439                self.render_edit_prediction_cursor_popover_preview(
 9440                    prediction,
 9441                    cursor_point,
 9442                    style,
 9443                    cx,
 9444                )?
 9445            }
 9446
 9447            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9448                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9449                    stale_completion,
 9450                    cursor_point,
 9451                    style,
 9452                    cx,
 9453                )?,
 9454
 9455                None => pending_completion_container(provider_icon)
 9456                    .child(Label::new("...").size(LabelSize::Small)),
 9457            },
 9458
 9459            None => pending_completion_container(provider_icon)
 9460                .child(Label::new("...").size(LabelSize::Small)),
 9461        };
 9462
 9463        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9464            completion
 9465                .with_animation(
 9466                    "loading-completion",
 9467                    Animation::new(Duration::from_secs(2))
 9468                        .repeat()
 9469                        .with_easing(pulsating_between(0.4, 0.8)),
 9470                    |label, delta| label.opacity(delta),
 9471                )
 9472                .into_any_element()
 9473        } else {
 9474            completion.into_any_element()
 9475        };
 9476
 9477        let has_completion = self.active_edit_prediction.is_some();
 9478
 9479        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9480        Some(
 9481            h_flex()
 9482                .min_w(min_width)
 9483                .max_w(max_width)
 9484                .flex_1()
 9485                .elevation_2(cx)
 9486                .border_color(cx.theme().colors().border)
 9487                .child(
 9488                    div()
 9489                        .flex_1()
 9490                        .py_1()
 9491                        .px_2()
 9492                        .overflow_hidden()
 9493                        .child(completion),
 9494                )
 9495                .when_some(accept_keystroke, |el, accept_keystroke| {
 9496                    if !accept_keystroke.modifiers().modified() {
 9497                        return el;
 9498                    }
 9499
 9500                    el.child(
 9501                        h_flex()
 9502                            .h_full()
 9503                            .border_l_1()
 9504                            .rounded_r_lg()
 9505                            .border_color(cx.theme().colors().border)
 9506                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9507                            .gap_1()
 9508                            .py_1()
 9509                            .px_2()
 9510                            .child(
 9511                                h_flex()
 9512                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9513                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9514                                    .child(h_flex().children(ui::render_modifiers(
 9515                                        accept_keystroke.modifiers(),
 9516                                        PlatformStyle::platform(),
 9517                                        Some(if !has_completion {
 9518                                            Color::Muted
 9519                                        } else {
 9520                                            Color::Default
 9521                                        }),
 9522                                        None,
 9523                                        false,
 9524                                    ))),
 9525                            )
 9526                            .child(Label::new("Preview").into_any_element())
 9527                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9528                    )
 9529                })
 9530                .into_any(),
 9531        )
 9532    }
 9533
 9534    fn render_edit_prediction_cursor_popover_preview(
 9535        &self,
 9536        completion: &EditPredictionState,
 9537        cursor_point: Point,
 9538        style: &EditorStyle,
 9539        cx: &mut Context<Editor>,
 9540    ) -> Option<Div> {
 9541        use text::ToPoint as _;
 9542
 9543        fn render_relative_row_jump(
 9544            prefix: impl Into<String>,
 9545            current_row: u32,
 9546            target_row: u32,
 9547        ) -> Div {
 9548            let (row_diff, arrow) = if target_row < current_row {
 9549                (current_row - target_row, IconName::ArrowUp)
 9550            } else {
 9551                (target_row - current_row, IconName::ArrowDown)
 9552            };
 9553
 9554            h_flex()
 9555                .child(
 9556                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9557                        .color(Color::Muted)
 9558                        .size(LabelSize::Small),
 9559                )
 9560                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9561        }
 9562
 9563        let supports_jump = self
 9564            .edit_prediction_provider
 9565            .as_ref()
 9566            .map(|provider| provider.provider.supports_jump_to_edit())
 9567            .unwrap_or(true);
 9568
 9569        match &completion.completion {
 9570            EditPrediction::MoveWithin {
 9571                target, snapshot, ..
 9572            } => {
 9573                if !supports_jump {
 9574                    return None;
 9575                }
 9576
 9577                Some(
 9578                    h_flex()
 9579                        .px_2()
 9580                        .gap_2()
 9581                        .flex_1()
 9582                        .child(
 9583                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9584                                Icon::new(IconName::ZedPredictDown)
 9585                            } else {
 9586                                Icon::new(IconName::ZedPredictUp)
 9587                            },
 9588                        )
 9589                        .child(Label::new("Jump to Edit")),
 9590                )
 9591            }
 9592            EditPrediction::MoveOutside { snapshot, .. } => {
 9593                let file_name = snapshot
 9594                    .file()
 9595                    .map(|file| file.file_name(cx))
 9596                    .unwrap_or("untitled");
 9597                Some(
 9598                    h_flex()
 9599                        .px_2()
 9600                        .gap_2()
 9601                        .flex_1()
 9602                        .child(Icon::new(IconName::ZedPredict))
 9603                        .child(Label::new(format!("Jump to {file_name}"))),
 9604                )
 9605            }
 9606            EditPrediction::Edit {
 9607                edits,
 9608                edit_preview,
 9609                snapshot,
 9610                display_mode: _,
 9611            } => {
 9612                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9613
 9614                let (highlighted_edits, has_more_lines) =
 9615                    if let Some(edit_preview) = edit_preview.as_ref() {
 9616                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9617                            .first_line_preview()
 9618                    } else {
 9619                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9620                    };
 9621
 9622                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9623                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9624
 9625                let preview = h_flex()
 9626                    .gap_1()
 9627                    .min_w_16()
 9628                    .child(styled_text)
 9629                    .when(has_more_lines, |parent| parent.child(""));
 9630
 9631                let left = if supports_jump && first_edit_row != cursor_point.row {
 9632                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9633                        .into_any_element()
 9634                } else {
 9635                    let icon_name =
 9636                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9637                    Icon::new(icon_name).into_any_element()
 9638                };
 9639
 9640                Some(
 9641                    h_flex()
 9642                        .h_full()
 9643                        .flex_1()
 9644                        .gap_2()
 9645                        .pr_1()
 9646                        .overflow_x_hidden()
 9647                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9648                        .child(left)
 9649                        .child(preview),
 9650                )
 9651            }
 9652        }
 9653    }
 9654
 9655    pub fn render_context_menu(
 9656        &self,
 9657        style: &EditorStyle,
 9658        max_height_in_lines: u32,
 9659        window: &mut Window,
 9660        cx: &mut Context<Editor>,
 9661    ) -> Option<AnyElement> {
 9662        let menu = self.context_menu.borrow();
 9663        let menu = menu.as_ref()?;
 9664        if !menu.visible() {
 9665            return None;
 9666        };
 9667        Some(menu.render(style, max_height_in_lines, window, cx))
 9668    }
 9669
 9670    fn render_context_menu_aside(
 9671        &mut self,
 9672        max_size: Size<Pixels>,
 9673        window: &mut Window,
 9674        cx: &mut Context<Editor>,
 9675    ) -> Option<AnyElement> {
 9676        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9677            if menu.visible() {
 9678                menu.render_aside(max_size, window, cx)
 9679            } else {
 9680                None
 9681            }
 9682        })
 9683    }
 9684
 9685    fn hide_context_menu(
 9686        &mut self,
 9687        window: &mut Window,
 9688        cx: &mut Context<Self>,
 9689    ) -> Option<CodeContextMenu> {
 9690        cx.notify();
 9691        self.completion_tasks.clear();
 9692        let context_menu = self.context_menu.borrow_mut().take();
 9693        self.stale_edit_prediction_in_menu.take();
 9694        self.update_visible_edit_prediction(window, cx);
 9695        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9696            && let Some(completion_provider) = &self.completion_provider
 9697        {
 9698            completion_provider.selection_changed(None, window, cx);
 9699        }
 9700        context_menu
 9701    }
 9702
 9703    fn show_snippet_choices(
 9704        &mut self,
 9705        choices: &Vec<String>,
 9706        selection: Range<Anchor>,
 9707        cx: &mut Context<Self>,
 9708    ) {
 9709        let Some((_, buffer, _)) = self
 9710            .buffer()
 9711            .read(cx)
 9712            .excerpt_containing(selection.start, cx)
 9713        else {
 9714            return;
 9715        };
 9716        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9717        else {
 9718            return;
 9719        };
 9720        if buffer != end_buffer {
 9721            log::error!("expected anchor range to have matching buffer IDs");
 9722            return;
 9723        }
 9724
 9725        let id = post_inc(&mut self.next_completion_id);
 9726        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9727        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9728            CompletionsMenu::new_snippet_choices(
 9729                id,
 9730                true,
 9731                choices,
 9732                selection,
 9733                buffer,
 9734                snippet_sort_order,
 9735            ),
 9736        ));
 9737    }
 9738
 9739    pub fn insert_snippet(
 9740        &mut self,
 9741        insertion_ranges: &[Range<usize>],
 9742        snippet: Snippet,
 9743        window: &mut Window,
 9744        cx: &mut Context<Self>,
 9745    ) -> Result<()> {
 9746        struct Tabstop<T> {
 9747            is_end_tabstop: bool,
 9748            ranges: Vec<Range<T>>,
 9749            choices: Option<Vec<String>>,
 9750        }
 9751
 9752        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9753            let snippet_text: Arc<str> = snippet.text.clone().into();
 9754            let edits = insertion_ranges
 9755                .iter()
 9756                .cloned()
 9757                .map(|range| (range, snippet_text.clone()));
 9758            let autoindent_mode = AutoindentMode::Block {
 9759                original_indent_columns: Vec::new(),
 9760            };
 9761            buffer.edit(edits, Some(autoindent_mode), cx);
 9762
 9763            let snapshot = &*buffer.read(cx);
 9764            let snippet = &snippet;
 9765            snippet
 9766                .tabstops
 9767                .iter()
 9768                .map(|tabstop| {
 9769                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9770                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9771                    });
 9772                    let mut tabstop_ranges = tabstop
 9773                        .ranges
 9774                        .iter()
 9775                        .flat_map(|tabstop_range| {
 9776                            let mut delta = 0_isize;
 9777                            insertion_ranges.iter().map(move |insertion_range| {
 9778                                let insertion_start = insertion_range.start as isize + delta;
 9779                                delta +=
 9780                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9781
 9782                                let start = ((insertion_start + tabstop_range.start) as usize)
 9783                                    .min(snapshot.len());
 9784                                let end = ((insertion_start + tabstop_range.end) as usize)
 9785                                    .min(snapshot.len());
 9786                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9787                            })
 9788                        })
 9789                        .collect::<Vec<_>>();
 9790                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9791
 9792                    Tabstop {
 9793                        is_end_tabstop,
 9794                        ranges: tabstop_ranges,
 9795                        choices: tabstop.choices.clone(),
 9796                    }
 9797                })
 9798                .collect::<Vec<_>>()
 9799        });
 9800        if let Some(tabstop) = tabstops.first() {
 9801            self.change_selections(Default::default(), window, cx, |s| {
 9802                // Reverse order so that the first range is the newest created selection.
 9803                // Completions will use it and autoscroll will prioritize it.
 9804                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9805            });
 9806
 9807            if let Some(choices) = &tabstop.choices
 9808                && let Some(selection) = tabstop.ranges.first()
 9809            {
 9810                self.show_snippet_choices(choices, selection.clone(), cx)
 9811            }
 9812
 9813            // If we're already at the last tabstop and it's at the end of the snippet,
 9814            // we're done, we don't need to keep the state around.
 9815            if !tabstop.is_end_tabstop {
 9816                let choices = tabstops
 9817                    .iter()
 9818                    .map(|tabstop| tabstop.choices.clone())
 9819                    .collect();
 9820
 9821                let ranges = tabstops
 9822                    .into_iter()
 9823                    .map(|tabstop| tabstop.ranges)
 9824                    .collect::<Vec<_>>();
 9825
 9826                self.snippet_stack.push(SnippetState {
 9827                    active_index: 0,
 9828                    ranges,
 9829                    choices,
 9830                });
 9831            }
 9832
 9833            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9834            if self.autoclose_regions.is_empty() {
 9835                let snapshot = self.buffer.read(cx).snapshot(cx);
 9836                let mut all_selections = self.selections.all::<Point>(cx);
 9837                for selection in &mut all_selections {
 9838                    let selection_head = selection.head();
 9839                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9840                        continue;
 9841                    };
 9842
 9843                    let mut bracket_pair = None;
 9844                    let max_lookup_length = scope
 9845                        .brackets()
 9846                        .map(|(pair, _)| {
 9847                            pair.start
 9848                                .as_str()
 9849                                .chars()
 9850                                .count()
 9851                                .max(pair.end.as_str().chars().count())
 9852                        })
 9853                        .max();
 9854                    if let Some(max_lookup_length) = max_lookup_length {
 9855                        let next_text = snapshot
 9856                            .chars_at(selection_head)
 9857                            .take(max_lookup_length)
 9858                            .collect::<String>();
 9859                        let prev_text = snapshot
 9860                            .reversed_chars_at(selection_head)
 9861                            .take(max_lookup_length)
 9862                            .collect::<String>();
 9863
 9864                        for (pair, enabled) in scope.brackets() {
 9865                            if enabled
 9866                                && pair.close
 9867                                && prev_text.starts_with(pair.start.as_str())
 9868                                && next_text.starts_with(pair.end.as_str())
 9869                            {
 9870                                bracket_pair = Some(pair.clone());
 9871                                break;
 9872                            }
 9873                        }
 9874                    }
 9875
 9876                    if let Some(pair) = bracket_pair {
 9877                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9878                        let autoclose_enabled =
 9879                            self.use_autoclose && snapshot_settings.use_autoclose;
 9880                        if autoclose_enabled {
 9881                            let start = snapshot.anchor_after(selection_head);
 9882                            let end = snapshot.anchor_after(selection_head);
 9883                            self.autoclose_regions.push(AutocloseRegion {
 9884                                selection_id: selection.id,
 9885                                range: start..end,
 9886                                pair,
 9887                            });
 9888                        }
 9889                    }
 9890                }
 9891            }
 9892        }
 9893        Ok(())
 9894    }
 9895
 9896    pub fn move_to_next_snippet_tabstop(
 9897        &mut self,
 9898        window: &mut Window,
 9899        cx: &mut Context<Self>,
 9900    ) -> bool {
 9901        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9902    }
 9903
 9904    pub fn move_to_prev_snippet_tabstop(
 9905        &mut self,
 9906        window: &mut Window,
 9907        cx: &mut Context<Self>,
 9908    ) -> bool {
 9909        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9910    }
 9911
 9912    pub fn move_to_snippet_tabstop(
 9913        &mut self,
 9914        bias: Bias,
 9915        window: &mut Window,
 9916        cx: &mut Context<Self>,
 9917    ) -> bool {
 9918        if let Some(mut snippet) = self.snippet_stack.pop() {
 9919            match bias {
 9920                Bias::Left => {
 9921                    if snippet.active_index > 0 {
 9922                        snippet.active_index -= 1;
 9923                    } else {
 9924                        self.snippet_stack.push(snippet);
 9925                        return false;
 9926                    }
 9927                }
 9928                Bias::Right => {
 9929                    if snippet.active_index + 1 < snippet.ranges.len() {
 9930                        snippet.active_index += 1;
 9931                    } else {
 9932                        self.snippet_stack.push(snippet);
 9933                        return false;
 9934                    }
 9935                }
 9936            }
 9937            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9938                self.change_selections(Default::default(), window, cx, |s| {
 9939                    // Reverse order so that the first range is the newest created selection.
 9940                    // Completions will use it and autoscroll will prioritize it.
 9941                    s.select_ranges(current_ranges.iter().rev().cloned())
 9942                });
 9943
 9944                if let Some(choices) = &snippet.choices[snippet.active_index]
 9945                    && let Some(selection) = current_ranges.first()
 9946                {
 9947                    self.show_snippet_choices(choices, selection.clone(), cx);
 9948                }
 9949
 9950                // If snippet state is not at the last tabstop, push it back on the stack
 9951                if snippet.active_index + 1 < snippet.ranges.len() {
 9952                    self.snippet_stack.push(snippet);
 9953                }
 9954                return true;
 9955            }
 9956        }
 9957
 9958        false
 9959    }
 9960
 9961    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9962        self.transact(window, cx, |this, window, cx| {
 9963            this.select_all(&SelectAll, window, cx);
 9964            this.insert("", window, cx);
 9965        });
 9966    }
 9967
 9968    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9969        if self.read_only(cx) {
 9970            return;
 9971        }
 9972        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9973        self.transact(window, cx, |this, window, cx| {
 9974            this.select_autoclose_pair(window, cx);
 9975            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9976            if !this.linked_edit_ranges.is_empty() {
 9977                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9978                let snapshot = this.buffer.read(cx).snapshot(cx);
 9979
 9980                for selection in selections.iter() {
 9981                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9982                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9983                    if selection_start.buffer_id != selection_end.buffer_id {
 9984                        continue;
 9985                    }
 9986                    if let Some(ranges) =
 9987                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9988                    {
 9989                        for (buffer, entries) in ranges {
 9990                            linked_ranges.entry(buffer).or_default().extend(entries);
 9991                        }
 9992                    }
 9993                }
 9994            }
 9995
 9996            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9997            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9998            for selection in &mut selections {
 9999                if selection.is_empty() {
10000                    let old_head = selection.head();
10001                    let mut new_head =
10002                        movement::left(&display_map, old_head.to_display_point(&display_map))
10003                            .to_point(&display_map);
10004                    if let Some((buffer, line_buffer_range)) = display_map
10005                        .buffer_snapshot
10006                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10007                    {
10008                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10009                        let indent_len = match indent_size.kind {
10010                            IndentKind::Space => {
10011                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10012                            }
10013                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10014                        };
10015                        if old_head.column <= indent_size.len && old_head.column > 0 {
10016                            let indent_len = indent_len.get();
10017                            new_head = cmp::min(
10018                                new_head,
10019                                MultiBufferPoint::new(
10020                                    old_head.row,
10021                                    ((old_head.column - 1) / indent_len) * indent_len,
10022                                ),
10023                            );
10024                        }
10025                    }
10026
10027                    selection.set_head(new_head, SelectionGoal::None);
10028                }
10029            }
10030
10031            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10032            this.insert("", window, cx);
10033            let empty_str: Arc<str> = Arc::from("");
10034            for (buffer, edits) in linked_ranges {
10035                let snapshot = buffer.read(cx).snapshot();
10036                use text::ToPoint as TP;
10037
10038                let edits = edits
10039                    .into_iter()
10040                    .map(|range| {
10041                        let end_point = TP::to_point(&range.end, &snapshot);
10042                        let mut start_point = TP::to_point(&range.start, &snapshot);
10043
10044                        if end_point == start_point {
10045                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10046                                .saturating_sub(1);
10047                            start_point =
10048                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10049                        };
10050
10051                        (start_point..end_point, empty_str.clone())
10052                    })
10053                    .sorted_by_key(|(range, _)| range.start)
10054                    .collect::<Vec<_>>();
10055                buffer.update(cx, |this, cx| {
10056                    this.edit(edits, None, cx);
10057                })
10058            }
10059            this.refresh_edit_prediction(true, false, window, cx);
10060            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
10061        });
10062    }
10063
10064    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10065        if self.read_only(cx) {
10066            return;
10067        }
10068        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10069        self.transact(window, cx, |this, window, cx| {
10070            this.change_selections(Default::default(), window, cx, |s| {
10071                s.move_with(|map, selection| {
10072                    if selection.is_empty() {
10073                        let cursor = movement::right(map, selection.head());
10074                        selection.end = cursor;
10075                        selection.reversed = true;
10076                        selection.goal = SelectionGoal::None;
10077                    }
10078                })
10079            });
10080            this.insert("", window, cx);
10081            this.refresh_edit_prediction(true, false, window, cx);
10082        });
10083    }
10084
10085    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10086        if self.mode.is_single_line() {
10087            cx.propagate();
10088            return;
10089        }
10090
10091        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10092        if self.move_to_prev_snippet_tabstop(window, cx) {
10093            return;
10094        }
10095        self.outdent(&Outdent, window, cx);
10096    }
10097
10098    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10099        if self.mode.is_single_line() {
10100            cx.propagate();
10101            return;
10102        }
10103
10104        if self.move_to_next_snippet_tabstop(window, cx) {
10105            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10106            return;
10107        }
10108        if self.read_only(cx) {
10109            return;
10110        }
10111        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10112        let mut selections = self.selections.all_adjusted(cx);
10113        let buffer = self.buffer.read(cx);
10114        let snapshot = buffer.snapshot(cx);
10115        let rows_iter = selections.iter().map(|s| s.head().row);
10116        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10117
10118        let has_some_cursor_in_whitespace = selections
10119            .iter()
10120            .filter(|selection| selection.is_empty())
10121            .any(|selection| {
10122                let cursor = selection.head();
10123                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10124                cursor.column < current_indent.len
10125            });
10126
10127        let mut edits = Vec::new();
10128        let mut prev_edited_row = 0;
10129        let mut row_delta = 0;
10130        for selection in &mut selections {
10131            if selection.start.row != prev_edited_row {
10132                row_delta = 0;
10133            }
10134            prev_edited_row = selection.end.row;
10135
10136            // If the selection is non-empty, then increase the indentation of the selected lines.
10137            if !selection.is_empty() {
10138                row_delta =
10139                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10140                continue;
10141            }
10142
10143            let cursor = selection.head();
10144            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10145            if let Some(suggested_indent) =
10146                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10147            {
10148                // Don't do anything if already at suggested indent
10149                // and there is any other cursor which is not
10150                if has_some_cursor_in_whitespace
10151                    && cursor.column == current_indent.len
10152                    && current_indent.len == suggested_indent.len
10153                {
10154                    continue;
10155                }
10156
10157                // Adjust line and move cursor to suggested indent
10158                // if cursor is not at suggested indent
10159                if cursor.column < suggested_indent.len
10160                    && cursor.column <= current_indent.len
10161                    && current_indent.len <= suggested_indent.len
10162                {
10163                    selection.start = Point::new(cursor.row, suggested_indent.len);
10164                    selection.end = selection.start;
10165                    if row_delta == 0 {
10166                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10167                            cursor.row,
10168                            current_indent,
10169                            suggested_indent,
10170                        ));
10171                        row_delta = suggested_indent.len - current_indent.len;
10172                    }
10173                    continue;
10174                }
10175
10176                // If current indent is more than suggested indent
10177                // only move cursor to current indent and skip indent
10178                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10179                    selection.start = Point::new(cursor.row, current_indent.len);
10180                    selection.end = selection.start;
10181                    continue;
10182                }
10183            }
10184
10185            // Otherwise, insert a hard or soft tab.
10186            let settings = buffer.language_settings_at(cursor, cx);
10187            let tab_size = if settings.hard_tabs {
10188                IndentSize::tab()
10189            } else {
10190                let tab_size = settings.tab_size.get();
10191                let indent_remainder = snapshot
10192                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10193                    .flat_map(str::chars)
10194                    .fold(row_delta % tab_size, |counter: u32, c| {
10195                        if c == '\t' {
10196                            0
10197                        } else {
10198                            (counter + 1) % tab_size
10199                        }
10200                    });
10201
10202                let chars_to_next_tab_stop = tab_size - indent_remainder;
10203                IndentSize::spaces(chars_to_next_tab_stop)
10204            };
10205            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10206            selection.end = selection.start;
10207            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10208            row_delta += tab_size.len;
10209        }
10210
10211        self.transact(window, cx, |this, window, cx| {
10212            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10213            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10214            this.refresh_edit_prediction(true, false, window, cx);
10215        });
10216    }
10217
10218    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10219        if self.read_only(cx) {
10220            return;
10221        }
10222        if self.mode.is_single_line() {
10223            cx.propagate();
10224            return;
10225        }
10226
10227        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10228        let mut selections = self.selections.all::<Point>(cx);
10229        let mut prev_edited_row = 0;
10230        let mut row_delta = 0;
10231        let mut edits = Vec::new();
10232        let buffer = self.buffer.read(cx);
10233        let snapshot = buffer.snapshot(cx);
10234        for selection in &mut selections {
10235            if selection.start.row != prev_edited_row {
10236                row_delta = 0;
10237            }
10238            prev_edited_row = selection.end.row;
10239
10240            row_delta =
10241                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10242        }
10243
10244        self.transact(window, cx, |this, window, cx| {
10245            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10246            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10247        });
10248    }
10249
10250    fn indent_selection(
10251        buffer: &MultiBuffer,
10252        snapshot: &MultiBufferSnapshot,
10253        selection: &mut Selection<Point>,
10254        edits: &mut Vec<(Range<Point>, String)>,
10255        delta_for_start_row: u32,
10256        cx: &App,
10257    ) -> u32 {
10258        let settings = buffer.language_settings_at(selection.start, cx);
10259        let tab_size = settings.tab_size.get();
10260        let indent_kind = if settings.hard_tabs {
10261            IndentKind::Tab
10262        } else {
10263            IndentKind::Space
10264        };
10265        let mut start_row = selection.start.row;
10266        let mut end_row = selection.end.row + 1;
10267
10268        // If a selection ends at the beginning of a line, don't indent
10269        // that last line.
10270        if selection.end.column == 0 && selection.end.row > selection.start.row {
10271            end_row -= 1;
10272        }
10273
10274        // Avoid re-indenting a row that has already been indented by a
10275        // previous selection, but still update this selection's column
10276        // to reflect that indentation.
10277        if delta_for_start_row > 0 {
10278            start_row += 1;
10279            selection.start.column += delta_for_start_row;
10280            if selection.end.row == selection.start.row {
10281                selection.end.column += delta_for_start_row;
10282            }
10283        }
10284
10285        let mut delta_for_end_row = 0;
10286        let has_multiple_rows = start_row + 1 != end_row;
10287        for row in start_row..end_row {
10288            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10289            let indent_delta = match (current_indent.kind, indent_kind) {
10290                (IndentKind::Space, IndentKind::Space) => {
10291                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10292                    IndentSize::spaces(columns_to_next_tab_stop)
10293                }
10294                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10295                (_, IndentKind::Tab) => IndentSize::tab(),
10296            };
10297
10298            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10299                0
10300            } else {
10301                selection.start.column
10302            };
10303            let row_start = Point::new(row, start);
10304            edits.push((
10305                row_start..row_start,
10306                indent_delta.chars().collect::<String>(),
10307            ));
10308
10309            // Update this selection's endpoints to reflect the indentation.
10310            if row == selection.start.row {
10311                selection.start.column += indent_delta.len;
10312            }
10313            if row == selection.end.row {
10314                selection.end.column += indent_delta.len;
10315                delta_for_end_row = indent_delta.len;
10316            }
10317        }
10318
10319        if selection.start.row == selection.end.row {
10320            delta_for_start_row + delta_for_end_row
10321        } else {
10322            delta_for_end_row
10323        }
10324    }
10325
10326    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10327        if self.read_only(cx) {
10328            return;
10329        }
10330        if self.mode.is_single_line() {
10331            cx.propagate();
10332            return;
10333        }
10334
10335        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10336        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10337        let selections = self.selections.all::<Point>(cx);
10338        let mut deletion_ranges = Vec::new();
10339        let mut last_outdent = None;
10340        {
10341            let buffer = self.buffer.read(cx);
10342            let snapshot = buffer.snapshot(cx);
10343            for selection in &selections {
10344                let settings = buffer.language_settings_at(selection.start, cx);
10345                let tab_size = settings.tab_size.get();
10346                let mut rows = selection.spanned_rows(false, &display_map);
10347
10348                // Avoid re-outdenting a row that has already been outdented by a
10349                // previous selection.
10350                if let Some(last_row) = last_outdent
10351                    && last_row == rows.start
10352                {
10353                    rows.start = rows.start.next_row();
10354                }
10355                let has_multiple_rows = rows.len() > 1;
10356                for row in rows.iter_rows() {
10357                    let indent_size = snapshot.indent_size_for_line(row);
10358                    if indent_size.len > 0 {
10359                        let deletion_len = match indent_size.kind {
10360                            IndentKind::Space => {
10361                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10362                                if columns_to_prev_tab_stop == 0 {
10363                                    tab_size
10364                                } else {
10365                                    columns_to_prev_tab_stop
10366                                }
10367                            }
10368                            IndentKind::Tab => 1,
10369                        };
10370                        let start = if has_multiple_rows
10371                            || deletion_len > selection.start.column
10372                            || indent_size.len < selection.start.column
10373                        {
10374                            0
10375                        } else {
10376                            selection.start.column - deletion_len
10377                        };
10378                        deletion_ranges.push(
10379                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10380                        );
10381                        last_outdent = Some(row);
10382                    }
10383                }
10384            }
10385        }
10386
10387        self.transact(window, cx, |this, window, cx| {
10388            this.buffer.update(cx, |buffer, cx| {
10389                let empty_str: Arc<str> = Arc::default();
10390                buffer.edit(
10391                    deletion_ranges
10392                        .into_iter()
10393                        .map(|range| (range, empty_str.clone())),
10394                    None,
10395                    cx,
10396                );
10397            });
10398            let selections = this.selections.all::<usize>(cx);
10399            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10400        });
10401    }
10402
10403    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10404        if self.read_only(cx) {
10405            return;
10406        }
10407        if self.mode.is_single_line() {
10408            cx.propagate();
10409            return;
10410        }
10411
10412        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10413        let selections = self
10414            .selections
10415            .all::<usize>(cx)
10416            .into_iter()
10417            .map(|s| s.range());
10418
10419        self.transact(window, cx, |this, window, cx| {
10420            this.buffer.update(cx, |buffer, cx| {
10421                buffer.autoindent_ranges(selections, cx);
10422            });
10423            let selections = this.selections.all::<usize>(cx);
10424            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10425        });
10426    }
10427
10428    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10429        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10430        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10431        let selections = self.selections.all::<Point>(cx);
10432
10433        let mut new_cursors = Vec::new();
10434        let mut edit_ranges = Vec::new();
10435        let mut selections = selections.iter().peekable();
10436        while let Some(selection) = selections.next() {
10437            let mut rows = selection.spanned_rows(false, &display_map);
10438
10439            // Accumulate contiguous regions of rows that we want to delete.
10440            while let Some(next_selection) = selections.peek() {
10441                let next_rows = next_selection.spanned_rows(false, &display_map);
10442                if next_rows.start <= rows.end {
10443                    rows.end = next_rows.end;
10444                    selections.next().unwrap();
10445                } else {
10446                    break;
10447                }
10448            }
10449
10450            let buffer = &display_map.buffer_snapshot;
10451            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10452            let edit_end = if buffer.max_point().row >= rows.end.0 {
10453                // If there's a line after the range, delete the \n from the end of the row range
10454                ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer)
10455            } else {
10456                // If there isn't a line after the range, delete the \n from the line before the
10457                // start of the row range
10458                edit_start = edit_start.saturating_sub(1);
10459                buffer.len()
10460            };
10461
10462            let (cursor, goal) = movement::down_by_rows(
10463                &display_map,
10464                selection.head().to_display_point(&display_map),
10465                rows.len() as u32,
10466                selection.goal,
10467                false,
10468                &self.text_layout_details(window),
10469            );
10470
10471            new_cursors.push((
10472                selection.id,
10473                buffer.anchor_after(cursor.to_point(&display_map)),
10474                goal,
10475            ));
10476            edit_ranges.push(edit_start..edit_end);
10477        }
10478
10479        self.transact(window, cx, |this, window, cx| {
10480            let buffer = this.buffer.update(cx, |buffer, cx| {
10481                let empty_str: Arc<str> = Arc::default();
10482                buffer.edit(
10483                    edit_ranges
10484                        .into_iter()
10485                        .map(|range| (range, empty_str.clone())),
10486                    None,
10487                    cx,
10488                );
10489                buffer.snapshot(cx)
10490            });
10491            let new_selections = new_cursors
10492                .into_iter()
10493                .map(|(id, cursor, goal)| {
10494                    let cursor = cursor.to_point(&buffer);
10495                    Selection {
10496                        id,
10497                        start: cursor,
10498                        end: cursor,
10499                        reversed: false,
10500                        goal,
10501                    }
10502                })
10503                .collect();
10504
10505            this.change_selections(Default::default(), window, cx, |s| {
10506                s.select(new_selections);
10507            });
10508        });
10509    }
10510
10511    pub fn join_lines_impl(
10512        &mut self,
10513        insert_whitespace: bool,
10514        window: &mut Window,
10515        cx: &mut Context<Self>,
10516    ) {
10517        if self.read_only(cx) {
10518            return;
10519        }
10520        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10521        for selection in self.selections.all::<Point>(cx) {
10522            let start = MultiBufferRow(selection.start.row);
10523            // Treat single line selections as if they include the next line. Otherwise this action
10524            // would do nothing for single line selections individual cursors.
10525            let end = if selection.start.row == selection.end.row {
10526                MultiBufferRow(selection.start.row + 1)
10527            } else {
10528                MultiBufferRow(selection.end.row)
10529            };
10530
10531            if let Some(last_row_range) = row_ranges.last_mut()
10532                && start <= last_row_range.end
10533            {
10534                last_row_range.end = end;
10535                continue;
10536            }
10537            row_ranges.push(start..end);
10538        }
10539
10540        let snapshot = self.buffer.read(cx).snapshot(cx);
10541        let mut cursor_positions = Vec::new();
10542        for row_range in &row_ranges {
10543            let anchor = snapshot.anchor_before(Point::new(
10544                row_range.end.previous_row().0,
10545                snapshot.line_len(row_range.end.previous_row()),
10546            ));
10547            cursor_positions.push(anchor..anchor);
10548        }
10549
10550        self.transact(window, cx, |this, window, cx| {
10551            for row_range in row_ranges.into_iter().rev() {
10552                for row in row_range.iter_rows().rev() {
10553                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10554                    let next_line_row = row.next_row();
10555                    let indent = snapshot.indent_size_for_line(next_line_row);
10556                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10557
10558                    let replace =
10559                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10560                            " "
10561                        } else {
10562                            ""
10563                        };
10564
10565                    this.buffer.update(cx, |buffer, cx| {
10566                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10567                    });
10568                }
10569            }
10570
10571            this.change_selections(Default::default(), window, cx, |s| {
10572                s.select_anchor_ranges(cursor_positions)
10573            });
10574        });
10575    }
10576
10577    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10578        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10579        self.join_lines_impl(true, window, cx);
10580    }
10581
10582    pub fn sort_lines_case_sensitive(
10583        &mut self,
10584        _: &SortLinesCaseSensitive,
10585        window: &mut Window,
10586        cx: &mut Context<Self>,
10587    ) {
10588        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10589    }
10590
10591    pub fn sort_lines_by_length(
10592        &mut self,
10593        _: &SortLinesByLength,
10594        window: &mut Window,
10595        cx: &mut Context<Self>,
10596    ) {
10597        self.manipulate_immutable_lines(window, cx, |lines| {
10598            lines.sort_by_key(|&line| line.chars().count())
10599        })
10600    }
10601
10602    pub fn sort_lines_case_insensitive(
10603        &mut self,
10604        _: &SortLinesCaseInsensitive,
10605        window: &mut Window,
10606        cx: &mut Context<Self>,
10607    ) {
10608        self.manipulate_immutable_lines(window, cx, |lines| {
10609            lines.sort_by_key(|line| line.to_lowercase())
10610        })
10611    }
10612
10613    pub fn unique_lines_case_insensitive(
10614        &mut self,
10615        _: &UniqueLinesCaseInsensitive,
10616        window: &mut Window,
10617        cx: &mut Context<Self>,
10618    ) {
10619        self.manipulate_immutable_lines(window, cx, |lines| {
10620            let mut seen = HashSet::default();
10621            lines.retain(|line| seen.insert(line.to_lowercase()));
10622        })
10623    }
10624
10625    pub fn unique_lines_case_sensitive(
10626        &mut self,
10627        _: &UniqueLinesCaseSensitive,
10628        window: &mut Window,
10629        cx: &mut Context<Self>,
10630    ) {
10631        self.manipulate_immutable_lines(window, cx, |lines| {
10632            let mut seen = HashSet::default();
10633            lines.retain(|line| seen.insert(*line));
10634        })
10635    }
10636
10637    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10638        let snapshot = self.buffer.read(cx).snapshot(cx);
10639        for selection in self.selections.disjoint_anchors_arc().iter() {
10640            if snapshot
10641                .language_at(selection.start)
10642                .and_then(|lang| lang.config().wrap_characters.as_ref())
10643                .is_some()
10644            {
10645                return true;
10646            }
10647        }
10648        false
10649    }
10650
10651    fn wrap_selections_in_tag(
10652        &mut self,
10653        _: &WrapSelectionsInTag,
10654        window: &mut Window,
10655        cx: &mut Context<Self>,
10656    ) {
10657        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10658
10659        let snapshot = self.buffer.read(cx).snapshot(cx);
10660
10661        let mut edits = Vec::new();
10662        let mut boundaries = Vec::new();
10663
10664        for selection in self.selections.all::<Point>(cx).iter() {
10665            let Some(wrap_config) = snapshot
10666                .language_at(selection.start)
10667                .and_then(|lang| lang.config().wrap_characters.clone())
10668            else {
10669                continue;
10670            };
10671
10672            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10673            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10674
10675            let start_before = snapshot.anchor_before(selection.start);
10676            let end_after = snapshot.anchor_after(selection.end);
10677
10678            edits.push((start_before..start_before, open_tag));
10679            edits.push((end_after..end_after, close_tag));
10680
10681            boundaries.push((
10682                start_before,
10683                end_after,
10684                wrap_config.start_prefix.len(),
10685                wrap_config.end_suffix.len(),
10686            ));
10687        }
10688
10689        if edits.is_empty() {
10690            return;
10691        }
10692
10693        self.transact(window, cx, |this, window, cx| {
10694            let buffer = this.buffer.update(cx, |buffer, cx| {
10695                buffer.edit(edits, None, cx);
10696                buffer.snapshot(cx)
10697            });
10698
10699            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10700            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10701                boundaries.into_iter()
10702            {
10703                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10704                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10705                new_selections.push(open_offset..open_offset);
10706                new_selections.push(close_offset..close_offset);
10707            }
10708
10709            this.change_selections(Default::default(), window, cx, |s| {
10710                s.select_ranges(new_selections);
10711            });
10712
10713            this.request_autoscroll(Autoscroll::fit(), cx);
10714        });
10715    }
10716
10717    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10718        let Some(project) = self.project.clone() else {
10719            return;
10720        };
10721        self.reload(project, window, cx)
10722            .detach_and_notify_err(window, cx);
10723    }
10724
10725    pub fn restore_file(
10726        &mut self,
10727        _: &::git::RestoreFile,
10728        window: &mut Window,
10729        cx: &mut Context<Self>,
10730    ) {
10731        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10732        let mut buffer_ids = HashSet::default();
10733        let snapshot = self.buffer().read(cx).snapshot(cx);
10734        for selection in self.selections.all::<usize>(cx) {
10735            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10736        }
10737
10738        let buffer = self.buffer().read(cx);
10739        let ranges = buffer_ids
10740            .into_iter()
10741            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10742            .collect::<Vec<_>>();
10743
10744        self.restore_hunks_in_ranges(ranges, window, cx);
10745    }
10746
10747    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10748        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10749        let selections = self
10750            .selections
10751            .all(cx)
10752            .into_iter()
10753            .map(|s| s.range())
10754            .collect();
10755        self.restore_hunks_in_ranges(selections, window, cx);
10756    }
10757
10758    pub fn restore_hunks_in_ranges(
10759        &mut self,
10760        ranges: Vec<Range<Point>>,
10761        window: &mut Window,
10762        cx: &mut Context<Editor>,
10763    ) {
10764        let mut revert_changes = HashMap::default();
10765        let chunk_by = self
10766            .snapshot(window, cx)
10767            .hunks_for_ranges(ranges)
10768            .into_iter()
10769            .chunk_by(|hunk| hunk.buffer_id);
10770        for (buffer_id, hunks) in &chunk_by {
10771            let hunks = hunks.collect::<Vec<_>>();
10772            for hunk in &hunks {
10773                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10774            }
10775            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10776        }
10777        drop(chunk_by);
10778        if !revert_changes.is_empty() {
10779            self.transact(window, cx, |editor, window, cx| {
10780                editor.restore(revert_changes, window, cx);
10781            });
10782        }
10783    }
10784
10785    pub fn open_active_item_in_terminal(
10786        &mut self,
10787        _: &OpenInTerminal,
10788        window: &mut Window,
10789        cx: &mut Context<Self>,
10790    ) {
10791        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10792            let project_path = buffer.read(cx).project_path(cx)?;
10793            let project = self.project()?.read(cx);
10794            let entry = project.entry_for_path(&project_path, cx)?;
10795            let parent = match &entry.canonical_path {
10796                Some(canonical_path) => canonical_path.to_path_buf(),
10797                None => project.absolute_path(&project_path, cx)?,
10798            }
10799            .parent()?
10800            .to_path_buf();
10801            Some(parent)
10802        }) {
10803            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10804        }
10805    }
10806
10807    fn set_breakpoint_context_menu(
10808        &mut self,
10809        display_row: DisplayRow,
10810        position: Option<Anchor>,
10811        clicked_point: gpui::Point<Pixels>,
10812        window: &mut Window,
10813        cx: &mut Context<Self>,
10814    ) {
10815        let source = self
10816            .buffer
10817            .read(cx)
10818            .snapshot(cx)
10819            .anchor_before(Point::new(display_row.0, 0u32));
10820
10821        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10822
10823        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10824            self,
10825            source,
10826            clicked_point,
10827            context_menu,
10828            window,
10829            cx,
10830        );
10831    }
10832
10833    fn add_edit_breakpoint_block(
10834        &mut self,
10835        anchor: Anchor,
10836        breakpoint: &Breakpoint,
10837        edit_action: BreakpointPromptEditAction,
10838        window: &mut Window,
10839        cx: &mut Context<Self>,
10840    ) {
10841        let weak_editor = cx.weak_entity();
10842        let bp_prompt = cx.new(|cx| {
10843            BreakpointPromptEditor::new(
10844                weak_editor,
10845                anchor,
10846                breakpoint.clone(),
10847                edit_action,
10848                window,
10849                cx,
10850            )
10851        });
10852
10853        let height = bp_prompt.update(cx, |this, cx| {
10854            this.prompt
10855                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10856        });
10857        let cloned_prompt = bp_prompt.clone();
10858        let blocks = vec![BlockProperties {
10859            style: BlockStyle::Sticky,
10860            placement: BlockPlacement::Above(anchor),
10861            height: Some(height),
10862            render: Arc::new(move |cx| {
10863                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10864                cloned_prompt.clone().into_any_element()
10865            }),
10866            priority: 0,
10867        }];
10868
10869        let focus_handle = bp_prompt.focus_handle(cx);
10870        window.focus(&focus_handle);
10871
10872        let block_ids = self.insert_blocks(blocks, None, cx);
10873        bp_prompt.update(cx, |prompt, _| {
10874            prompt.add_block_ids(block_ids);
10875        });
10876    }
10877
10878    pub(crate) fn breakpoint_at_row(
10879        &self,
10880        row: u32,
10881        window: &mut Window,
10882        cx: &mut Context<Self>,
10883    ) -> Option<(Anchor, Breakpoint)> {
10884        let snapshot = self.snapshot(window, cx);
10885        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10886
10887        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10888    }
10889
10890    pub(crate) fn breakpoint_at_anchor(
10891        &self,
10892        breakpoint_position: Anchor,
10893        snapshot: &EditorSnapshot,
10894        cx: &mut Context<Self>,
10895    ) -> Option<(Anchor, Breakpoint)> {
10896        let buffer = self
10897            .buffer
10898            .read(cx)
10899            .buffer_for_anchor(breakpoint_position, cx)?;
10900
10901        let enclosing_excerpt = breakpoint_position.excerpt_id;
10902        let buffer_snapshot = buffer.read(cx).snapshot();
10903
10904        let row = buffer_snapshot
10905            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10906            .row;
10907
10908        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10909        let anchor_end = snapshot
10910            .buffer_snapshot
10911            .anchor_after(Point::new(row, line_len));
10912
10913        self.breakpoint_store
10914            .as_ref()?
10915            .read_with(cx, |breakpoint_store, cx| {
10916                breakpoint_store
10917                    .breakpoints(
10918                        &buffer,
10919                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10920                        &buffer_snapshot,
10921                        cx,
10922                    )
10923                    .next()
10924                    .and_then(|(bp, _)| {
10925                        let breakpoint_row = buffer_snapshot
10926                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10927                            .row;
10928
10929                        if breakpoint_row == row {
10930                            snapshot
10931                                .buffer_snapshot
10932                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10933                                .map(|position| (position, bp.bp.clone()))
10934                        } else {
10935                            None
10936                        }
10937                    })
10938            })
10939    }
10940
10941    pub fn edit_log_breakpoint(
10942        &mut self,
10943        _: &EditLogBreakpoint,
10944        window: &mut Window,
10945        cx: &mut Context<Self>,
10946    ) {
10947        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10948            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10949                message: None,
10950                state: BreakpointState::Enabled,
10951                condition: None,
10952                hit_condition: None,
10953            });
10954
10955            self.add_edit_breakpoint_block(
10956                anchor,
10957                &breakpoint,
10958                BreakpointPromptEditAction::Log,
10959                window,
10960                cx,
10961            );
10962        }
10963    }
10964
10965    fn breakpoints_at_cursors(
10966        &self,
10967        window: &mut Window,
10968        cx: &mut Context<Self>,
10969    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10970        let snapshot = self.snapshot(window, cx);
10971        let cursors = self
10972            .selections
10973            .disjoint_anchors_arc()
10974            .iter()
10975            .map(|selection| {
10976                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10977
10978                let breakpoint_position = self
10979                    .breakpoint_at_row(cursor_position.row, window, cx)
10980                    .map(|bp| bp.0)
10981                    .unwrap_or_else(|| {
10982                        snapshot
10983                            .display_snapshot
10984                            .buffer_snapshot
10985                            .anchor_after(Point::new(cursor_position.row, 0))
10986                    });
10987
10988                let breakpoint = self
10989                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10990                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10991
10992                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10993            })
10994            // 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.
10995            .collect::<HashMap<Anchor, _>>();
10996
10997        cursors.into_iter().collect()
10998    }
10999
11000    pub fn enable_breakpoint(
11001        &mut self,
11002        _: &crate::actions::EnableBreakpoint,
11003        window: &mut Window,
11004        cx: &mut Context<Self>,
11005    ) {
11006        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11007            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11008                continue;
11009            };
11010            self.edit_breakpoint_at_anchor(
11011                anchor,
11012                breakpoint,
11013                BreakpointEditAction::InvertState,
11014                cx,
11015            );
11016        }
11017    }
11018
11019    pub fn disable_breakpoint(
11020        &mut self,
11021        _: &crate::actions::DisableBreakpoint,
11022        window: &mut Window,
11023        cx: &mut Context<Self>,
11024    ) {
11025        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11026            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11027                continue;
11028            };
11029            self.edit_breakpoint_at_anchor(
11030                anchor,
11031                breakpoint,
11032                BreakpointEditAction::InvertState,
11033                cx,
11034            );
11035        }
11036    }
11037
11038    pub fn toggle_breakpoint(
11039        &mut self,
11040        _: &crate::actions::ToggleBreakpoint,
11041        window: &mut Window,
11042        cx: &mut Context<Self>,
11043    ) {
11044        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11045            if let Some(breakpoint) = breakpoint {
11046                self.edit_breakpoint_at_anchor(
11047                    anchor,
11048                    breakpoint,
11049                    BreakpointEditAction::Toggle,
11050                    cx,
11051                );
11052            } else {
11053                self.edit_breakpoint_at_anchor(
11054                    anchor,
11055                    Breakpoint::new_standard(),
11056                    BreakpointEditAction::Toggle,
11057                    cx,
11058                );
11059            }
11060        }
11061    }
11062
11063    pub fn edit_breakpoint_at_anchor(
11064        &mut self,
11065        breakpoint_position: Anchor,
11066        breakpoint: Breakpoint,
11067        edit_action: BreakpointEditAction,
11068        cx: &mut Context<Self>,
11069    ) {
11070        let Some(breakpoint_store) = &self.breakpoint_store else {
11071            return;
11072        };
11073
11074        let Some(buffer) = self
11075            .buffer
11076            .read(cx)
11077            .buffer_for_anchor(breakpoint_position, cx)
11078        else {
11079            return;
11080        };
11081
11082        breakpoint_store.update(cx, |breakpoint_store, cx| {
11083            breakpoint_store.toggle_breakpoint(
11084                buffer,
11085                BreakpointWithPosition {
11086                    position: breakpoint_position.text_anchor,
11087                    bp: breakpoint,
11088                },
11089                edit_action,
11090                cx,
11091            );
11092        });
11093
11094        cx.notify();
11095    }
11096
11097    #[cfg(any(test, feature = "test-support"))]
11098    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11099        self.breakpoint_store.clone()
11100    }
11101
11102    pub fn prepare_restore_change(
11103        &self,
11104        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11105        hunk: &MultiBufferDiffHunk,
11106        cx: &mut App,
11107    ) -> Option<()> {
11108        if hunk.is_created_file() {
11109            return None;
11110        }
11111        let buffer = self.buffer.read(cx);
11112        let diff = buffer.diff_for(hunk.buffer_id)?;
11113        let buffer = buffer.buffer(hunk.buffer_id)?;
11114        let buffer = buffer.read(cx);
11115        let original_text = diff
11116            .read(cx)
11117            .base_text()
11118            .as_rope()
11119            .slice(hunk.diff_base_byte_range.clone());
11120        let buffer_snapshot = buffer.snapshot();
11121        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11122        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11123            probe
11124                .0
11125                .start
11126                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11127                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11128        }) {
11129            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11130            Some(())
11131        } else {
11132            None
11133        }
11134    }
11135
11136    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11137        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11138    }
11139
11140    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11141        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11142    }
11143
11144    fn manipulate_lines<M>(
11145        &mut self,
11146        window: &mut Window,
11147        cx: &mut Context<Self>,
11148        mut manipulate: M,
11149    ) where
11150        M: FnMut(&str) -> LineManipulationResult,
11151    {
11152        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11153
11154        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11155        let buffer = self.buffer.read(cx).snapshot(cx);
11156
11157        let mut edits = Vec::new();
11158
11159        let selections = self.selections.all::<Point>(cx);
11160        let mut selections = selections.iter().peekable();
11161        let mut contiguous_row_selections = Vec::new();
11162        let mut new_selections = Vec::new();
11163        let mut added_lines = 0;
11164        let mut removed_lines = 0;
11165
11166        while let Some(selection) = selections.next() {
11167            let (start_row, end_row) = consume_contiguous_rows(
11168                &mut contiguous_row_selections,
11169                selection,
11170                &display_map,
11171                &mut selections,
11172            );
11173
11174            let start_point = Point::new(start_row.0, 0);
11175            let end_point = Point::new(
11176                end_row.previous_row().0,
11177                buffer.line_len(end_row.previous_row()),
11178            );
11179            let text = buffer
11180                .text_for_range(start_point..end_point)
11181                .collect::<String>();
11182
11183            let LineManipulationResult {
11184                new_text,
11185                line_count_before,
11186                line_count_after,
11187            } = manipulate(&text);
11188
11189            edits.push((start_point..end_point, new_text));
11190
11191            // Selections must change based on added and removed line count
11192            let start_row =
11193                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11194            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11195            new_selections.push(Selection {
11196                id: selection.id,
11197                start: start_row,
11198                end: end_row,
11199                goal: SelectionGoal::None,
11200                reversed: selection.reversed,
11201            });
11202
11203            if line_count_after > line_count_before {
11204                added_lines += line_count_after - line_count_before;
11205            } else if line_count_before > line_count_after {
11206                removed_lines += line_count_before - line_count_after;
11207            }
11208        }
11209
11210        self.transact(window, cx, |this, window, cx| {
11211            let buffer = this.buffer.update(cx, |buffer, cx| {
11212                buffer.edit(edits, None, cx);
11213                buffer.snapshot(cx)
11214            });
11215
11216            // Recalculate offsets on newly edited buffer
11217            let new_selections = new_selections
11218                .iter()
11219                .map(|s| {
11220                    let start_point = Point::new(s.start.0, 0);
11221                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11222                    Selection {
11223                        id: s.id,
11224                        start: buffer.point_to_offset(start_point),
11225                        end: buffer.point_to_offset(end_point),
11226                        goal: s.goal,
11227                        reversed: s.reversed,
11228                    }
11229                })
11230                .collect();
11231
11232            this.change_selections(Default::default(), window, cx, |s| {
11233                s.select(new_selections);
11234            });
11235
11236            this.request_autoscroll(Autoscroll::fit(), cx);
11237        });
11238    }
11239
11240    fn manipulate_immutable_lines<Fn>(
11241        &mut self,
11242        window: &mut Window,
11243        cx: &mut Context<Self>,
11244        mut callback: Fn,
11245    ) where
11246        Fn: FnMut(&mut Vec<&str>),
11247    {
11248        self.manipulate_lines(window, cx, |text| {
11249            let mut lines: Vec<&str> = text.split('\n').collect();
11250            let line_count_before = lines.len();
11251
11252            callback(&mut lines);
11253
11254            LineManipulationResult {
11255                new_text: lines.join("\n"),
11256                line_count_before,
11257                line_count_after: lines.len(),
11258            }
11259        });
11260    }
11261
11262    fn manipulate_mutable_lines<Fn>(
11263        &mut self,
11264        window: &mut Window,
11265        cx: &mut Context<Self>,
11266        mut callback: Fn,
11267    ) where
11268        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11269    {
11270        self.manipulate_lines(window, cx, |text| {
11271            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11272            let line_count_before = lines.len();
11273
11274            callback(&mut lines);
11275
11276            LineManipulationResult {
11277                new_text: lines.join("\n"),
11278                line_count_before,
11279                line_count_after: lines.len(),
11280            }
11281        });
11282    }
11283
11284    pub fn convert_indentation_to_spaces(
11285        &mut self,
11286        _: &ConvertIndentationToSpaces,
11287        window: &mut Window,
11288        cx: &mut Context<Self>,
11289    ) {
11290        let settings = self.buffer.read(cx).language_settings(cx);
11291        let tab_size = settings.tab_size.get() as usize;
11292
11293        self.manipulate_mutable_lines(window, cx, |lines| {
11294            // Allocates a reasonably sized scratch buffer once for the whole loop
11295            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11296            // Avoids recomputing spaces that could be inserted many times
11297            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11298                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11299                .collect();
11300
11301            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11302                let mut chars = line.as_ref().chars();
11303                let mut col = 0;
11304                let mut changed = false;
11305
11306                for ch in chars.by_ref() {
11307                    match ch {
11308                        ' ' => {
11309                            reindented_line.push(' ');
11310                            col += 1;
11311                        }
11312                        '\t' => {
11313                            // \t are converted to spaces depending on the current column
11314                            let spaces_len = tab_size - (col % tab_size);
11315                            reindented_line.extend(&space_cache[spaces_len - 1]);
11316                            col += spaces_len;
11317                            changed = true;
11318                        }
11319                        _ => {
11320                            // If we dont append before break, the character is consumed
11321                            reindented_line.push(ch);
11322                            break;
11323                        }
11324                    }
11325                }
11326
11327                if !changed {
11328                    reindented_line.clear();
11329                    continue;
11330                }
11331                // Append the rest of the line and replace old reference with new one
11332                reindented_line.extend(chars);
11333                *line = Cow::Owned(reindented_line.clone());
11334                reindented_line.clear();
11335            }
11336        });
11337    }
11338
11339    pub fn convert_indentation_to_tabs(
11340        &mut self,
11341        _: &ConvertIndentationToTabs,
11342        window: &mut Window,
11343        cx: &mut Context<Self>,
11344    ) {
11345        let settings = self.buffer.read(cx).language_settings(cx);
11346        let tab_size = settings.tab_size.get() as usize;
11347
11348        self.manipulate_mutable_lines(window, cx, |lines| {
11349            // Allocates a reasonably sized buffer once for the whole loop
11350            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11351            // Avoids recomputing spaces that could be inserted many times
11352            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11353                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11354                .collect();
11355
11356            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11357                let mut chars = line.chars();
11358                let mut spaces_count = 0;
11359                let mut first_non_indent_char = None;
11360                let mut changed = false;
11361
11362                for ch in chars.by_ref() {
11363                    match ch {
11364                        ' ' => {
11365                            // Keep track of spaces. Append \t when we reach tab_size
11366                            spaces_count += 1;
11367                            changed = true;
11368                            if spaces_count == tab_size {
11369                                reindented_line.push('\t');
11370                                spaces_count = 0;
11371                            }
11372                        }
11373                        '\t' => {
11374                            reindented_line.push('\t');
11375                            spaces_count = 0;
11376                        }
11377                        _ => {
11378                            // Dont append it yet, we might have remaining spaces
11379                            first_non_indent_char = Some(ch);
11380                            break;
11381                        }
11382                    }
11383                }
11384
11385                if !changed {
11386                    reindented_line.clear();
11387                    continue;
11388                }
11389                // Remaining spaces that didn't make a full tab stop
11390                if spaces_count > 0 {
11391                    reindented_line.extend(&space_cache[spaces_count - 1]);
11392                }
11393                // If we consume an extra character that was not indentation, add it back
11394                if let Some(extra_char) = first_non_indent_char {
11395                    reindented_line.push(extra_char);
11396                }
11397                // Append the rest of the line and replace old reference with new one
11398                reindented_line.extend(chars);
11399                *line = Cow::Owned(reindented_line.clone());
11400                reindented_line.clear();
11401            }
11402        });
11403    }
11404
11405    pub fn convert_to_upper_case(
11406        &mut self,
11407        _: &ConvertToUpperCase,
11408        window: &mut Window,
11409        cx: &mut Context<Self>,
11410    ) {
11411        self.manipulate_text(window, cx, |text| text.to_uppercase())
11412    }
11413
11414    pub fn convert_to_lower_case(
11415        &mut self,
11416        _: &ConvertToLowerCase,
11417        window: &mut Window,
11418        cx: &mut Context<Self>,
11419    ) {
11420        self.manipulate_text(window, cx, |text| text.to_lowercase())
11421    }
11422
11423    pub fn convert_to_title_case(
11424        &mut self,
11425        _: &ConvertToTitleCase,
11426        window: &mut Window,
11427        cx: &mut Context<Self>,
11428    ) {
11429        self.manipulate_text(window, cx, |text| {
11430            text.split('\n')
11431                .map(|line| line.to_case(Case::Title))
11432                .join("\n")
11433        })
11434    }
11435
11436    pub fn convert_to_snake_case(
11437        &mut self,
11438        _: &ConvertToSnakeCase,
11439        window: &mut Window,
11440        cx: &mut Context<Self>,
11441    ) {
11442        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11443    }
11444
11445    pub fn convert_to_kebab_case(
11446        &mut self,
11447        _: &ConvertToKebabCase,
11448        window: &mut Window,
11449        cx: &mut Context<Self>,
11450    ) {
11451        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11452    }
11453
11454    pub fn convert_to_upper_camel_case(
11455        &mut self,
11456        _: &ConvertToUpperCamelCase,
11457        window: &mut Window,
11458        cx: &mut Context<Self>,
11459    ) {
11460        self.manipulate_text(window, cx, |text| {
11461            text.split('\n')
11462                .map(|line| line.to_case(Case::UpperCamel))
11463                .join("\n")
11464        })
11465    }
11466
11467    pub fn convert_to_lower_camel_case(
11468        &mut self,
11469        _: &ConvertToLowerCamelCase,
11470        window: &mut Window,
11471        cx: &mut Context<Self>,
11472    ) {
11473        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11474    }
11475
11476    pub fn convert_to_opposite_case(
11477        &mut self,
11478        _: &ConvertToOppositeCase,
11479        window: &mut Window,
11480        cx: &mut Context<Self>,
11481    ) {
11482        self.manipulate_text(window, cx, |text| {
11483            text.chars()
11484                .fold(String::with_capacity(text.len()), |mut t, c| {
11485                    if c.is_uppercase() {
11486                        t.extend(c.to_lowercase());
11487                    } else {
11488                        t.extend(c.to_uppercase());
11489                    }
11490                    t
11491                })
11492        })
11493    }
11494
11495    pub fn convert_to_sentence_case(
11496        &mut self,
11497        _: &ConvertToSentenceCase,
11498        window: &mut Window,
11499        cx: &mut Context<Self>,
11500    ) {
11501        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11502    }
11503
11504    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11505        self.manipulate_text(window, cx, |text| {
11506            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11507            if has_upper_case_characters {
11508                text.to_lowercase()
11509            } else {
11510                text.to_uppercase()
11511            }
11512        })
11513    }
11514
11515    pub fn convert_to_rot13(
11516        &mut self,
11517        _: &ConvertToRot13,
11518        window: &mut Window,
11519        cx: &mut Context<Self>,
11520    ) {
11521        self.manipulate_text(window, cx, |text| {
11522            text.chars()
11523                .map(|c| match c {
11524                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11525                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11526                    _ => c,
11527                })
11528                .collect()
11529        })
11530    }
11531
11532    pub fn convert_to_rot47(
11533        &mut self,
11534        _: &ConvertToRot47,
11535        window: &mut Window,
11536        cx: &mut Context<Self>,
11537    ) {
11538        self.manipulate_text(window, cx, |text| {
11539            text.chars()
11540                .map(|c| {
11541                    let code_point = c as u32;
11542                    if code_point >= 33 && code_point <= 126 {
11543                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11544                    }
11545                    c
11546                })
11547                .collect()
11548        })
11549    }
11550
11551    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11552    where
11553        Fn: FnMut(&str) -> String,
11554    {
11555        let buffer = self.buffer.read(cx).snapshot(cx);
11556
11557        let mut new_selections = Vec::new();
11558        let mut edits = Vec::new();
11559        let mut selection_adjustment = 0i32;
11560
11561        for selection in self.selections.all_adjusted(cx) {
11562            let selection_is_empty = selection.is_empty();
11563
11564            let (start, end) = if selection_is_empty {
11565                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11566                (word_range.start, word_range.end)
11567            } else {
11568                (
11569                    buffer.point_to_offset(selection.start),
11570                    buffer.point_to_offset(selection.end),
11571                )
11572            };
11573
11574            let text = buffer.text_for_range(start..end).collect::<String>();
11575            let old_length = text.len() as i32;
11576            let text = callback(&text);
11577
11578            new_selections.push(Selection {
11579                start: (start as i32 - selection_adjustment) as usize,
11580                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11581                goal: SelectionGoal::None,
11582                id: selection.id,
11583                reversed: selection.reversed,
11584            });
11585
11586            selection_adjustment += old_length - text.len() as i32;
11587
11588            edits.push((start..end, text));
11589        }
11590
11591        self.transact(window, cx, |this, window, cx| {
11592            this.buffer.update(cx, |buffer, cx| {
11593                buffer.edit(edits, None, cx);
11594            });
11595
11596            this.change_selections(Default::default(), window, cx, |s| {
11597                s.select(new_selections);
11598            });
11599
11600            this.request_autoscroll(Autoscroll::fit(), cx);
11601        });
11602    }
11603
11604    pub fn move_selection_on_drop(
11605        &mut self,
11606        selection: &Selection<Anchor>,
11607        target: DisplayPoint,
11608        is_cut: bool,
11609        window: &mut Window,
11610        cx: &mut Context<Self>,
11611    ) {
11612        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11613        let buffer = &display_map.buffer_snapshot;
11614        let mut edits = Vec::new();
11615        let insert_point = display_map
11616            .clip_point(target, Bias::Left)
11617            .to_point(&display_map);
11618        let text = buffer
11619            .text_for_range(selection.start..selection.end)
11620            .collect::<String>();
11621        if is_cut {
11622            edits.push(((selection.start..selection.end), String::new()));
11623        }
11624        let insert_anchor = buffer.anchor_before(insert_point);
11625        edits.push(((insert_anchor..insert_anchor), text));
11626        let last_edit_start = insert_anchor.bias_left(buffer);
11627        let last_edit_end = insert_anchor.bias_right(buffer);
11628        self.transact(window, cx, |this, window, cx| {
11629            this.buffer.update(cx, |buffer, cx| {
11630                buffer.edit(edits, None, cx);
11631            });
11632            this.change_selections(Default::default(), window, cx, |s| {
11633                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11634            });
11635        });
11636    }
11637
11638    pub fn clear_selection_drag_state(&mut self) {
11639        self.selection_drag_state = SelectionDragState::None;
11640    }
11641
11642    pub fn duplicate(
11643        &mut self,
11644        upwards: bool,
11645        whole_lines: bool,
11646        window: &mut Window,
11647        cx: &mut Context<Self>,
11648    ) {
11649        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11650
11651        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11652        let buffer = &display_map.buffer_snapshot;
11653        let selections = self.selections.all::<Point>(cx);
11654
11655        let mut edits = Vec::new();
11656        let mut selections_iter = selections.iter().peekable();
11657        while let Some(selection) = selections_iter.next() {
11658            let mut rows = selection.spanned_rows(false, &display_map);
11659            // duplicate line-wise
11660            if whole_lines || selection.start == selection.end {
11661                // Avoid duplicating the same lines twice.
11662                while let Some(next_selection) = selections_iter.peek() {
11663                    let next_rows = next_selection.spanned_rows(false, &display_map);
11664                    if next_rows.start < rows.end {
11665                        rows.end = next_rows.end;
11666                        selections_iter.next().unwrap();
11667                    } else {
11668                        break;
11669                    }
11670                }
11671
11672                // Copy the text from the selected row region and splice it either at the start
11673                // or end of the region.
11674                let start = Point::new(rows.start.0, 0);
11675                let end = Point::new(
11676                    rows.end.previous_row().0,
11677                    buffer.line_len(rows.end.previous_row()),
11678                );
11679                let text = buffer
11680                    .text_for_range(start..end)
11681                    .chain(Some("\n"))
11682                    .collect::<String>();
11683                let insert_location = if upwards {
11684                    Point::new(rows.end.0, 0)
11685                } else {
11686                    start
11687                };
11688                edits.push((insert_location..insert_location, text));
11689            } else {
11690                // duplicate character-wise
11691                let start = selection.start;
11692                let end = selection.end;
11693                let text = buffer.text_for_range(start..end).collect::<String>();
11694                edits.push((selection.end..selection.end, text));
11695            }
11696        }
11697
11698        self.transact(window, cx, |this, _, cx| {
11699            this.buffer.update(cx, |buffer, cx| {
11700                buffer.edit(edits, None, cx);
11701            });
11702
11703            this.request_autoscroll(Autoscroll::fit(), cx);
11704        });
11705    }
11706
11707    pub fn duplicate_line_up(
11708        &mut self,
11709        _: &DuplicateLineUp,
11710        window: &mut Window,
11711        cx: &mut Context<Self>,
11712    ) {
11713        self.duplicate(true, true, window, cx);
11714    }
11715
11716    pub fn duplicate_line_down(
11717        &mut self,
11718        _: &DuplicateLineDown,
11719        window: &mut Window,
11720        cx: &mut Context<Self>,
11721    ) {
11722        self.duplicate(false, true, window, cx);
11723    }
11724
11725    pub fn duplicate_selection(
11726        &mut self,
11727        _: &DuplicateSelection,
11728        window: &mut Window,
11729        cx: &mut Context<Self>,
11730    ) {
11731        self.duplicate(false, false, window, cx);
11732    }
11733
11734    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11735        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11736        if self.mode.is_single_line() {
11737            cx.propagate();
11738            return;
11739        }
11740
11741        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11742        let buffer = self.buffer.read(cx).snapshot(cx);
11743
11744        let mut edits = Vec::new();
11745        let mut unfold_ranges = Vec::new();
11746        let mut refold_creases = Vec::new();
11747
11748        let selections = self.selections.all::<Point>(cx);
11749        let mut selections = selections.iter().peekable();
11750        let mut contiguous_row_selections = Vec::new();
11751        let mut new_selections = Vec::new();
11752
11753        while let Some(selection) = selections.next() {
11754            // Find all the selections that span a contiguous row range
11755            let (start_row, end_row) = consume_contiguous_rows(
11756                &mut contiguous_row_selections,
11757                selection,
11758                &display_map,
11759                &mut selections,
11760            );
11761
11762            // Move the text spanned by the row range to be before the line preceding the row range
11763            if start_row.0 > 0 {
11764                let range_to_move = Point::new(
11765                    start_row.previous_row().0,
11766                    buffer.line_len(start_row.previous_row()),
11767                )
11768                    ..Point::new(
11769                        end_row.previous_row().0,
11770                        buffer.line_len(end_row.previous_row()),
11771                    );
11772                let insertion_point = display_map
11773                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11774                    .0;
11775
11776                // Don't move lines across excerpts
11777                if buffer
11778                    .excerpt_containing(insertion_point..range_to_move.end)
11779                    .is_some()
11780                {
11781                    let text = buffer
11782                        .text_for_range(range_to_move.clone())
11783                        .flat_map(|s| s.chars())
11784                        .skip(1)
11785                        .chain(['\n'])
11786                        .collect::<String>();
11787
11788                    edits.push((
11789                        buffer.anchor_after(range_to_move.start)
11790                            ..buffer.anchor_before(range_to_move.end),
11791                        String::new(),
11792                    ));
11793                    let insertion_anchor = buffer.anchor_after(insertion_point);
11794                    edits.push((insertion_anchor..insertion_anchor, text));
11795
11796                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11797
11798                    // Move selections up
11799                    new_selections.extend(contiguous_row_selections.drain(..).map(
11800                        |mut selection| {
11801                            selection.start.row -= row_delta;
11802                            selection.end.row -= row_delta;
11803                            selection
11804                        },
11805                    ));
11806
11807                    // Move folds up
11808                    unfold_ranges.push(range_to_move.clone());
11809                    for fold in display_map.folds_in_range(
11810                        buffer.anchor_before(range_to_move.start)
11811                            ..buffer.anchor_after(range_to_move.end),
11812                    ) {
11813                        let mut start = fold.range.start.to_point(&buffer);
11814                        let mut end = fold.range.end.to_point(&buffer);
11815                        start.row -= row_delta;
11816                        end.row -= row_delta;
11817                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11818                    }
11819                }
11820            }
11821
11822            // If we didn't move line(s), preserve the existing selections
11823            new_selections.append(&mut contiguous_row_selections);
11824        }
11825
11826        self.transact(window, cx, |this, window, cx| {
11827            this.unfold_ranges(&unfold_ranges, true, true, cx);
11828            this.buffer.update(cx, |buffer, cx| {
11829                for (range, text) in edits {
11830                    buffer.edit([(range, text)], None, cx);
11831                }
11832            });
11833            this.fold_creases(refold_creases, true, window, cx);
11834            this.change_selections(Default::default(), window, cx, |s| {
11835                s.select(new_selections);
11836            })
11837        });
11838    }
11839
11840    pub fn move_line_down(
11841        &mut self,
11842        _: &MoveLineDown,
11843        window: &mut Window,
11844        cx: &mut Context<Self>,
11845    ) {
11846        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11847        if self.mode.is_single_line() {
11848            cx.propagate();
11849            return;
11850        }
11851
11852        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11853        let buffer = self.buffer.read(cx).snapshot(cx);
11854
11855        let mut edits = Vec::new();
11856        let mut unfold_ranges = Vec::new();
11857        let mut refold_creases = Vec::new();
11858
11859        let selections = self.selections.all::<Point>(cx);
11860        let mut selections = selections.iter().peekable();
11861        let mut contiguous_row_selections = Vec::new();
11862        let mut new_selections = Vec::new();
11863
11864        while let Some(selection) = selections.next() {
11865            // Find all the selections that span a contiguous row range
11866            let (start_row, end_row) = consume_contiguous_rows(
11867                &mut contiguous_row_selections,
11868                selection,
11869                &display_map,
11870                &mut selections,
11871            );
11872
11873            // Move the text spanned by the row range to be after the last line of the row range
11874            if end_row.0 <= buffer.max_point().row {
11875                let range_to_move =
11876                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11877                let insertion_point = display_map
11878                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11879                    .0;
11880
11881                // Don't move lines across excerpt boundaries
11882                if buffer
11883                    .excerpt_containing(range_to_move.start..insertion_point)
11884                    .is_some()
11885                {
11886                    let mut text = String::from("\n");
11887                    text.extend(buffer.text_for_range(range_to_move.clone()));
11888                    text.pop(); // Drop trailing newline
11889                    edits.push((
11890                        buffer.anchor_after(range_to_move.start)
11891                            ..buffer.anchor_before(range_to_move.end),
11892                        String::new(),
11893                    ));
11894                    let insertion_anchor = buffer.anchor_after(insertion_point);
11895                    edits.push((insertion_anchor..insertion_anchor, text));
11896
11897                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11898
11899                    // Move selections down
11900                    new_selections.extend(contiguous_row_selections.drain(..).map(
11901                        |mut selection| {
11902                            selection.start.row += row_delta;
11903                            selection.end.row += row_delta;
11904                            selection
11905                        },
11906                    ));
11907
11908                    // Move folds down
11909                    unfold_ranges.push(range_to_move.clone());
11910                    for fold in display_map.folds_in_range(
11911                        buffer.anchor_before(range_to_move.start)
11912                            ..buffer.anchor_after(range_to_move.end),
11913                    ) {
11914                        let mut start = fold.range.start.to_point(&buffer);
11915                        let mut end = fold.range.end.to_point(&buffer);
11916                        start.row += row_delta;
11917                        end.row += row_delta;
11918                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11919                    }
11920                }
11921            }
11922
11923            // If we didn't move line(s), preserve the existing selections
11924            new_selections.append(&mut contiguous_row_selections);
11925        }
11926
11927        self.transact(window, cx, |this, window, cx| {
11928            this.unfold_ranges(&unfold_ranges, true, true, cx);
11929            this.buffer.update(cx, |buffer, cx| {
11930                for (range, text) in edits {
11931                    buffer.edit([(range, text)], None, cx);
11932                }
11933            });
11934            this.fold_creases(refold_creases, true, window, cx);
11935            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11936        });
11937    }
11938
11939    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11940        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11941        let text_layout_details = &self.text_layout_details(window);
11942        self.transact(window, cx, |this, window, cx| {
11943            let edits = this.change_selections(Default::default(), window, cx, |s| {
11944                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11945                s.move_with(|display_map, selection| {
11946                    if !selection.is_empty() {
11947                        return;
11948                    }
11949
11950                    let mut head = selection.head();
11951                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11952                    if head.column() == display_map.line_len(head.row()) {
11953                        transpose_offset = display_map
11954                            .buffer_snapshot
11955                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11956                    }
11957
11958                    if transpose_offset == 0 {
11959                        return;
11960                    }
11961
11962                    *head.column_mut() += 1;
11963                    head = display_map.clip_point(head, Bias::Right);
11964                    let goal = SelectionGoal::HorizontalPosition(
11965                        display_map
11966                            .x_for_display_point(head, text_layout_details)
11967                            .into(),
11968                    );
11969                    selection.collapse_to(head, goal);
11970
11971                    let transpose_start = display_map
11972                        .buffer_snapshot
11973                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11974                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11975                        let transpose_end = display_map
11976                            .buffer_snapshot
11977                            .clip_offset(transpose_offset + 1, Bias::Right);
11978                        if let Some(ch) =
11979                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11980                        {
11981                            edits.push((transpose_start..transpose_offset, String::new()));
11982                            edits.push((transpose_end..transpose_end, ch.to_string()));
11983                        }
11984                    }
11985                });
11986                edits
11987            });
11988            this.buffer
11989                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11990            let selections = this.selections.all::<usize>(cx);
11991            this.change_selections(Default::default(), window, cx, |s| {
11992                s.select(selections);
11993            });
11994        });
11995    }
11996
11997    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11998        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11999        if self.mode.is_single_line() {
12000            cx.propagate();
12001            return;
12002        }
12003
12004        self.rewrap_impl(RewrapOptions::default(), cx)
12005    }
12006
12007    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12008        let buffer = self.buffer.read(cx).snapshot(cx);
12009        let selections = self.selections.all::<Point>(cx);
12010
12011        #[derive(Clone, Debug, PartialEq)]
12012        enum CommentFormat {
12013            /// single line comment, with prefix for line
12014            Line(String),
12015            /// single line within a block comment, with prefix for line
12016            BlockLine(String),
12017            /// a single line of a block comment that includes the initial delimiter
12018            BlockCommentWithStart(BlockCommentConfig),
12019            /// a single line of a block comment that includes the ending delimiter
12020            BlockCommentWithEnd(BlockCommentConfig),
12021        }
12022
12023        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12024        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12025            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12026                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12027                .peekable();
12028
12029            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12030                row
12031            } else {
12032                return Vec::new();
12033            };
12034
12035            let language_settings = buffer.language_settings_at(selection.head(), cx);
12036            let language_scope = buffer.language_scope_at(selection.head());
12037
12038            let indent_and_prefix_for_row =
12039                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12040                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12041                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12042                        &language_scope
12043                    {
12044                        let indent_end = Point::new(row, indent.len);
12045                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12046                        let line_text_after_indent = buffer
12047                            .text_for_range(indent_end..line_end)
12048                            .collect::<String>();
12049
12050                        let is_within_comment_override = buffer
12051                            .language_scope_at(indent_end)
12052                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12053                        let comment_delimiters = if is_within_comment_override {
12054                            // we are within a comment syntax node, but we don't
12055                            // yet know what kind of comment: block, doc or line
12056                            match (
12057                                language_scope.documentation_comment(),
12058                                language_scope.block_comment(),
12059                            ) {
12060                                (Some(config), _) | (_, Some(config))
12061                                    if buffer.contains_str_at(indent_end, &config.start) =>
12062                                {
12063                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12064                                }
12065                                (Some(config), _) | (_, Some(config))
12066                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12067                                {
12068                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12069                                }
12070                                (Some(config), _) | (_, Some(config))
12071                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12072                                {
12073                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12074                                }
12075                                (_, _) => language_scope
12076                                    .line_comment_prefixes()
12077                                    .iter()
12078                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12079                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12080                            }
12081                        } else {
12082                            // we not in an overridden comment node, but we may
12083                            // be within a non-overridden line comment node
12084                            language_scope
12085                                .line_comment_prefixes()
12086                                .iter()
12087                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12088                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12089                        };
12090
12091                        let rewrap_prefix = language_scope
12092                            .rewrap_prefixes()
12093                            .iter()
12094                            .find_map(|prefix_regex| {
12095                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12096                                    if mat.start() == 0 {
12097                                        Some(mat.as_str().to_string())
12098                                    } else {
12099                                        None
12100                                    }
12101                                })
12102                            })
12103                            .flatten();
12104                        (comment_delimiters, rewrap_prefix)
12105                    } else {
12106                        (None, None)
12107                    };
12108                    (indent, comment_prefix, rewrap_prefix)
12109                };
12110
12111            let mut ranges = Vec::new();
12112            let from_empty_selection = selection.is_empty();
12113
12114            let mut current_range_start = first_row;
12115            let mut prev_row = first_row;
12116            let (
12117                mut current_range_indent,
12118                mut current_range_comment_delimiters,
12119                mut current_range_rewrap_prefix,
12120            ) = indent_and_prefix_for_row(first_row);
12121
12122            for row in non_blank_rows_iter.skip(1) {
12123                let has_paragraph_break = row > prev_row + 1;
12124
12125                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12126                    indent_and_prefix_for_row(row);
12127
12128                let has_indent_change = row_indent != current_range_indent;
12129                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12130
12131                let has_boundary_change = has_comment_change
12132                    || row_rewrap_prefix.is_some()
12133                    || (has_indent_change && current_range_comment_delimiters.is_some());
12134
12135                if has_paragraph_break || has_boundary_change {
12136                    ranges.push((
12137                        language_settings.clone(),
12138                        Point::new(current_range_start, 0)
12139                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12140                        current_range_indent,
12141                        current_range_comment_delimiters.clone(),
12142                        current_range_rewrap_prefix.clone(),
12143                        from_empty_selection,
12144                    ));
12145                    current_range_start = row;
12146                    current_range_indent = row_indent;
12147                    current_range_comment_delimiters = row_comment_delimiters;
12148                    current_range_rewrap_prefix = row_rewrap_prefix;
12149                }
12150                prev_row = row;
12151            }
12152
12153            ranges.push((
12154                language_settings.clone(),
12155                Point::new(current_range_start, 0)
12156                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12157                current_range_indent,
12158                current_range_comment_delimiters,
12159                current_range_rewrap_prefix,
12160                from_empty_selection,
12161            ));
12162
12163            ranges
12164        });
12165
12166        let mut edits = Vec::new();
12167        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12168
12169        for (
12170            language_settings,
12171            wrap_range,
12172            mut indent_size,
12173            comment_prefix,
12174            rewrap_prefix,
12175            from_empty_selection,
12176        ) in wrap_ranges
12177        {
12178            let mut start_row = wrap_range.start.row;
12179            let mut end_row = wrap_range.end.row;
12180
12181            // Skip selections that overlap with a range that has already been rewrapped.
12182            let selection_range = start_row..end_row;
12183            if rewrapped_row_ranges
12184                .iter()
12185                .any(|range| range.overlaps(&selection_range))
12186            {
12187                continue;
12188            }
12189
12190            let tab_size = language_settings.tab_size;
12191
12192            let (line_prefix, inside_comment) = match &comment_prefix {
12193                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12194                    (Some(prefix.as_str()), true)
12195                }
12196                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12197                    (Some(prefix.as_ref()), true)
12198                }
12199                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12200                    start: _,
12201                    end: _,
12202                    prefix,
12203                    tab_size,
12204                })) => {
12205                    indent_size.len += tab_size;
12206                    (Some(prefix.as_ref()), true)
12207                }
12208                None => (None, false),
12209            };
12210            let indent_prefix = indent_size.chars().collect::<String>();
12211            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12212
12213            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12214                RewrapBehavior::InComments => inside_comment,
12215                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12216                RewrapBehavior::Anywhere => true,
12217            };
12218
12219            let should_rewrap = options.override_language_settings
12220                || allow_rewrap_based_on_language
12221                || self.hard_wrap.is_some();
12222            if !should_rewrap {
12223                continue;
12224            }
12225
12226            if from_empty_selection {
12227                'expand_upwards: while start_row > 0 {
12228                    let prev_row = start_row - 1;
12229                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12230                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12231                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12232                    {
12233                        start_row = prev_row;
12234                    } else {
12235                        break 'expand_upwards;
12236                    }
12237                }
12238
12239                'expand_downwards: while end_row < buffer.max_point().row {
12240                    let next_row = end_row + 1;
12241                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12242                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12243                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12244                    {
12245                        end_row = next_row;
12246                    } else {
12247                        break 'expand_downwards;
12248                    }
12249                }
12250            }
12251
12252            let start = Point::new(start_row, 0);
12253            let start_offset = ToOffset::to_offset(&start, &buffer);
12254            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12255            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12256            let mut first_line_delimiter = None;
12257            let mut last_line_delimiter = None;
12258            let Some(lines_without_prefixes) = selection_text
12259                .lines()
12260                .enumerate()
12261                .map(|(ix, line)| {
12262                    let line_trimmed = line.trim_start();
12263                    if rewrap_prefix.is_some() && ix > 0 {
12264                        Ok(line_trimmed)
12265                    } else if let Some(
12266                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12267                            start,
12268                            prefix,
12269                            end,
12270                            tab_size,
12271                        })
12272                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12273                            start,
12274                            prefix,
12275                            end,
12276                            tab_size,
12277                        }),
12278                    ) = &comment_prefix
12279                    {
12280                        let line_trimmed = line_trimmed
12281                            .strip_prefix(start.as_ref())
12282                            .map(|s| {
12283                                let mut indent_size = indent_size;
12284                                indent_size.len -= tab_size;
12285                                let indent_prefix: String = indent_size.chars().collect();
12286                                first_line_delimiter = Some((indent_prefix, start));
12287                                s.trim_start()
12288                            })
12289                            .unwrap_or(line_trimmed);
12290                        let line_trimmed = line_trimmed
12291                            .strip_suffix(end.as_ref())
12292                            .map(|s| {
12293                                last_line_delimiter = Some(end);
12294                                s.trim_end()
12295                            })
12296                            .unwrap_or(line_trimmed);
12297                        let line_trimmed = line_trimmed
12298                            .strip_prefix(prefix.as_ref())
12299                            .unwrap_or(line_trimmed);
12300                        Ok(line_trimmed)
12301                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12302                        line_trimmed.strip_prefix(prefix).with_context(|| {
12303                            format!("line did not start with prefix {prefix:?}: {line:?}")
12304                        })
12305                    } else {
12306                        line_trimmed
12307                            .strip_prefix(&line_prefix.trim_start())
12308                            .with_context(|| {
12309                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12310                            })
12311                    }
12312                })
12313                .collect::<Result<Vec<_>, _>>()
12314                .log_err()
12315            else {
12316                continue;
12317            };
12318
12319            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12320                buffer
12321                    .language_settings_at(Point::new(start_row, 0), cx)
12322                    .preferred_line_length as usize
12323            });
12324
12325            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12326                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12327            } else {
12328                line_prefix.clone()
12329            };
12330
12331            let wrapped_text = {
12332                let mut wrapped_text = wrap_with_prefix(
12333                    line_prefix,
12334                    subsequent_lines_prefix,
12335                    lines_without_prefixes.join("\n"),
12336                    wrap_column,
12337                    tab_size,
12338                    options.preserve_existing_whitespace,
12339                );
12340
12341                if let Some((indent, delimiter)) = first_line_delimiter {
12342                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12343                }
12344                if let Some(last_line) = last_line_delimiter {
12345                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12346                }
12347
12348                wrapped_text
12349            };
12350
12351            // TODO: should always use char-based diff while still supporting cursor behavior that
12352            // matches vim.
12353            let mut diff_options = DiffOptions::default();
12354            if options.override_language_settings {
12355                diff_options.max_word_diff_len = 0;
12356                diff_options.max_word_diff_line_count = 0;
12357            } else {
12358                diff_options.max_word_diff_len = usize::MAX;
12359                diff_options.max_word_diff_line_count = usize::MAX;
12360            }
12361
12362            for (old_range, new_text) in
12363                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12364            {
12365                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12366                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12367                edits.push((edit_start..edit_end, new_text));
12368            }
12369
12370            rewrapped_row_ranges.push(start_row..=end_row);
12371        }
12372
12373        self.buffer
12374            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12375    }
12376
12377    pub fn cut_common(
12378        &mut self,
12379        cut_no_selection_line: bool,
12380        window: &mut Window,
12381        cx: &mut Context<Self>,
12382    ) -> ClipboardItem {
12383        let mut text = String::new();
12384        let buffer = self.buffer.read(cx).snapshot(cx);
12385        let mut selections = self.selections.all::<Point>(cx);
12386        let mut clipboard_selections = Vec::with_capacity(selections.len());
12387        {
12388            let max_point = buffer.max_point();
12389            let mut is_first = true;
12390            for selection in &mut selections {
12391                let is_entire_line =
12392                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12393                if is_entire_line {
12394                    selection.start = Point::new(selection.start.row, 0);
12395                    if !selection.is_empty() && selection.end.column == 0 {
12396                        selection.end = cmp::min(max_point, selection.end);
12397                    } else {
12398                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12399                    }
12400                    selection.goal = SelectionGoal::None;
12401                }
12402                if is_first {
12403                    is_first = false;
12404                } else {
12405                    text += "\n";
12406                }
12407                let mut len = 0;
12408                for chunk in buffer.text_for_range(selection.start..selection.end) {
12409                    text.push_str(chunk);
12410                    len += chunk.len();
12411                }
12412                clipboard_selections.push(ClipboardSelection {
12413                    len,
12414                    is_entire_line,
12415                    first_line_indent: buffer
12416                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12417                        .len,
12418                });
12419            }
12420        }
12421
12422        self.transact(window, cx, |this, window, cx| {
12423            this.change_selections(Default::default(), window, cx, |s| {
12424                s.select(selections);
12425            });
12426            this.insert("", window, cx);
12427        });
12428        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12429    }
12430
12431    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12432        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12433        let item = self.cut_common(true, window, cx);
12434        cx.write_to_clipboard(item);
12435    }
12436
12437    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12438        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12439        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12440            s.move_with(|snapshot, sel| {
12441                if sel.is_empty() {
12442                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12443                }
12444                if sel.is_empty() {
12445                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12446                }
12447            });
12448        });
12449        let item = self.cut_common(false, window, cx);
12450        cx.set_global(KillRing(item))
12451    }
12452
12453    pub fn kill_ring_yank(
12454        &mut self,
12455        _: &KillRingYank,
12456        window: &mut Window,
12457        cx: &mut Context<Self>,
12458    ) {
12459        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12460        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12461            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12462                (kill_ring.text().to_string(), kill_ring.metadata_json())
12463            } else {
12464                return;
12465            }
12466        } else {
12467            return;
12468        };
12469        self.do_paste(&text, metadata, false, window, cx);
12470    }
12471
12472    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12473        self.do_copy(true, cx);
12474    }
12475
12476    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12477        self.do_copy(false, cx);
12478    }
12479
12480    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12481        let selections = self.selections.all::<Point>(cx);
12482        let buffer = self.buffer.read(cx).read(cx);
12483        let mut text = String::new();
12484
12485        let mut clipboard_selections = Vec::with_capacity(selections.len());
12486        {
12487            let max_point = buffer.max_point();
12488            let mut is_first = true;
12489            for selection in &selections {
12490                let mut start = selection.start;
12491                let mut end = selection.end;
12492                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12493                if is_entire_line {
12494                    start = Point::new(start.row, 0);
12495                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12496                }
12497
12498                let mut trimmed_selections = Vec::new();
12499                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12500                    let row = MultiBufferRow(start.row);
12501                    let first_indent = buffer.indent_size_for_line(row);
12502                    if first_indent.len == 0 || start.column > first_indent.len {
12503                        trimmed_selections.push(start..end);
12504                    } else {
12505                        trimmed_selections.push(
12506                            Point::new(row.0, first_indent.len)
12507                                ..Point::new(row.0, buffer.line_len(row)),
12508                        );
12509                        for row in start.row + 1..=end.row {
12510                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12511                            if row == end.row {
12512                                line_len = end.column;
12513                            }
12514                            if line_len == 0 {
12515                                trimmed_selections
12516                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12517                                continue;
12518                            }
12519                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12520                            if row_indent_size.len >= first_indent.len {
12521                                trimmed_selections.push(
12522                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12523                                );
12524                            } else {
12525                                trimmed_selections.clear();
12526                                trimmed_selections.push(start..end);
12527                                break;
12528                            }
12529                        }
12530                    }
12531                } else {
12532                    trimmed_selections.push(start..end);
12533                }
12534
12535                for trimmed_range in trimmed_selections {
12536                    if is_first {
12537                        is_first = false;
12538                    } else {
12539                        text += "\n";
12540                    }
12541                    let mut len = 0;
12542                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12543                        text.push_str(chunk);
12544                        len += chunk.len();
12545                    }
12546                    clipboard_selections.push(ClipboardSelection {
12547                        len,
12548                        is_entire_line,
12549                        first_line_indent: buffer
12550                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12551                            .len,
12552                    });
12553                }
12554            }
12555        }
12556
12557        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12558            text,
12559            clipboard_selections,
12560        ));
12561    }
12562
12563    pub fn do_paste(
12564        &mut self,
12565        text: &String,
12566        clipboard_selections: Option<Vec<ClipboardSelection>>,
12567        handle_entire_lines: bool,
12568        window: &mut Window,
12569        cx: &mut Context<Self>,
12570    ) {
12571        if self.read_only(cx) {
12572            return;
12573        }
12574
12575        let clipboard_text = Cow::Borrowed(text.as_str());
12576
12577        self.transact(window, cx, |this, window, cx| {
12578            let had_active_edit_prediction = this.has_active_edit_prediction();
12579            let old_selections = this.selections.all::<usize>(cx);
12580            let cursor_offset = this.selections.last::<usize>(cx).head();
12581
12582            if let Some(mut clipboard_selections) = clipboard_selections {
12583                let all_selections_were_entire_line =
12584                    clipboard_selections.iter().all(|s| s.is_entire_line);
12585                let first_selection_indent_column =
12586                    clipboard_selections.first().map(|s| s.first_line_indent);
12587                if clipboard_selections.len() != old_selections.len() {
12588                    clipboard_selections.drain(..);
12589                }
12590                let mut auto_indent_on_paste = true;
12591
12592                this.buffer.update(cx, |buffer, cx| {
12593                    let snapshot = buffer.read(cx);
12594                    auto_indent_on_paste = snapshot
12595                        .language_settings_at(cursor_offset, cx)
12596                        .auto_indent_on_paste;
12597
12598                    let mut start_offset = 0;
12599                    let mut edits = Vec::new();
12600                    let mut original_indent_columns = Vec::new();
12601                    for (ix, selection) in old_selections.iter().enumerate() {
12602                        let to_insert;
12603                        let entire_line;
12604                        let original_indent_column;
12605                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12606                            let end_offset = start_offset + clipboard_selection.len;
12607                            to_insert = &clipboard_text[start_offset..end_offset];
12608                            entire_line = clipboard_selection.is_entire_line;
12609                            start_offset = end_offset + 1;
12610                            original_indent_column = Some(clipboard_selection.first_line_indent);
12611                        } else {
12612                            to_insert = &*clipboard_text;
12613                            entire_line = all_selections_were_entire_line;
12614                            original_indent_column = first_selection_indent_column
12615                        }
12616
12617                        let (range, to_insert) =
12618                            if selection.is_empty() && handle_entire_lines && entire_line {
12619                                // If the corresponding selection was empty when this slice of the
12620                                // clipboard text was written, then the entire line containing the
12621                                // selection was copied. If this selection is also currently empty,
12622                                // then paste the line before the current line of the buffer.
12623                                let column = selection.start.to_point(&snapshot).column as usize;
12624                                let line_start = selection.start - column;
12625                                (line_start..line_start, Cow::Borrowed(to_insert))
12626                            } else {
12627                                let language = snapshot.language_at(selection.head());
12628                                let range = selection.range();
12629                                if let Some(language) = language
12630                                    && language.name() == "Markdown".into()
12631                                {
12632                                    edit_for_markdown_paste(
12633                                        &snapshot,
12634                                        range,
12635                                        to_insert,
12636                                        url::Url::parse(to_insert).ok(),
12637                                    )
12638                                } else {
12639                                    (range, Cow::Borrowed(to_insert))
12640                                }
12641                            };
12642
12643                        edits.push((range, to_insert));
12644                        original_indent_columns.push(original_indent_column);
12645                    }
12646                    drop(snapshot);
12647
12648                    buffer.edit(
12649                        edits,
12650                        if auto_indent_on_paste {
12651                            Some(AutoindentMode::Block {
12652                                original_indent_columns,
12653                            })
12654                        } else {
12655                            None
12656                        },
12657                        cx,
12658                    );
12659                });
12660
12661                let selections = this.selections.all::<usize>(cx);
12662                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12663            } else {
12664                let url = url::Url::parse(&clipboard_text).ok();
12665
12666                let auto_indent_mode = if !clipboard_text.is_empty() {
12667                    Some(AutoindentMode::Block {
12668                        original_indent_columns: Vec::new(),
12669                    })
12670                } else {
12671                    None
12672                };
12673
12674                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12675                    let snapshot = buffer.snapshot(cx);
12676
12677                    let anchors = old_selections
12678                        .iter()
12679                        .map(|s| {
12680                            let anchor = snapshot.anchor_after(s.head());
12681                            s.map(|_| anchor)
12682                        })
12683                        .collect::<Vec<_>>();
12684
12685                    let mut edits = Vec::new();
12686
12687                    for selection in old_selections.iter() {
12688                        let language = snapshot.language_at(selection.head());
12689                        let range = selection.range();
12690
12691                        let (edit_range, edit_text) = if let Some(language) = language
12692                            && language.name() == "Markdown".into()
12693                        {
12694                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12695                        } else {
12696                            (range, clipboard_text.clone())
12697                        };
12698
12699                        edits.push((edit_range, edit_text));
12700                    }
12701
12702                    drop(snapshot);
12703                    buffer.edit(edits, auto_indent_mode, cx);
12704
12705                    anchors
12706                });
12707
12708                this.change_selections(Default::default(), window, cx, |s| {
12709                    s.select_anchors(selection_anchors);
12710                });
12711            }
12712
12713            let trigger_in_words =
12714                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12715
12716            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12717        });
12718    }
12719
12720    pub fn diff_clipboard_with_selection(
12721        &mut self,
12722        _: &DiffClipboardWithSelection,
12723        window: &mut Window,
12724        cx: &mut Context<Self>,
12725    ) {
12726        let selections = self.selections.all::<usize>(cx);
12727
12728        if selections.is_empty() {
12729            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12730            return;
12731        };
12732
12733        let clipboard_text = match cx.read_from_clipboard() {
12734            Some(item) => match item.entries().first() {
12735                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12736                _ => None,
12737            },
12738            None => None,
12739        };
12740
12741        let Some(clipboard_text) = clipboard_text else {
12742            log::warn!("Clipboard doesn't contain text.");
12743            return;
12744        };
12745
12746        window.dispatch_action(
12747            Box::new(DiffClipboardWithSelectionData {
12748                clipboard_text,
12749                editor: cx.entity(),
12750            }),
12751            cx,
12752        );
12753    }
12754
12755    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12756        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12757        if let Some(item) = cx.read_from_clipboard() {
12758            let entries = item.entries();
12759
12760            match entries.first() {
12761                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12762                // of all the pasted entries.
12763                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12764                    .do_paste(
12765                        clipboard_string.text(),
12766                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12767                        true,
12768                        window,
12769                        cx,
12770                    ),
12771                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12772            }
12773        }
12774    }
12775
12776    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12777        if self.read_only(cx) {
12778            return;
12779        }
12780
12781        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12782
12783        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12784            if let Some((selections, _)) =
12785                self.selection_history.transaction(transaction_id).cloned()
12786            {
12787                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12788                    s.select_anchors(selections.to_vec());
12789                });
12790            } else {
12791                log::error!(
12792                    "No entry in selection_history found for undo. \
12793                     This may correspond to a bug where undo does not update the selection. \
12794                     If this is occurring, please add details to \
12795                     https://github.com/zed-industries/zed/issues/22692"
12796                );
12797            }
12798            self.request_autoscroll(Autoscroll::fit(), cx);
12799            self.unmark_text(window, cx);
12800            self.refresh_edit_prediction(true, false, window, cx);
12801            cx.emit(EditorEvent::Edited { transaction_id });
12802            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12803        }
12804    }
12805
12806    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12807        if self.read_only(cx) {
12808            return;
12809        }
12810
12811        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12812
12813        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12814            if let Some((_, Some(selections))) =
12815                self.selection_history.transaction(transaction_id).cloned()
12816            {
12817                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12818                    s.select_anchors(selections.to_vec());
12819                });
12820            } else {
12821                log::error!(
12822                    "No entry in selection_history found for redo. \
12823                     This may correspond to a bug where undo does not update the selection. \
12824                     If this is occurring, please add details to \
12825                     https://github.com/zed-industries/zed/issues/22692"
12826                );
12827            }
12828            self.request_autoscroll(Autoscroll::fit(), cx);
12829            self.unmark_text(window, cx);
12830            self.refresh_edit_prediction(true, false, window, cx);
12831            cx.emit(EditorEvent::Edited { transaction_id });
12832        }
12833    }
12834
12835    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12836        self.buffer
12837            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12838    }
12839
12840    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12841        self.buffer
12842            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12843    }
12844
12845    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12846        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12847        self.change_selections(Default::default(), window, cx, |s| {
12848            s.move_with(|map, selection| {
12849                let cursor = if selection.is_empty() {
12850                    movement::left(map, selection.start)
12851                } else {
12852                    selection.start
12853                };
12854                selection.collapse_to(cursor, SelectionGoal::None);
12855            });
12856        })
12857    }
12858
12859    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12860        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12861        self.change_selections(Default::default(), window, cx, |s| {
12862            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12863        })
12864    }
12865
12866    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12867        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12868        self.change_selections(Default::default(), window, cx, |s| {
12869            s.move_with(|map, selection| {
12870                let cursor = if selection.is_empty() {
12871                    movement::right(map, selection.end)
12872                } else {
12873                    selection.end
12874                };
12875                selection.collapse_to(cursor, SelectionGoal::None)
12876            });
12877        })
12878    }
12879
12880    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12881        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12882        self.change_selections(Default::default(), window, cx, |s| {
12883            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12884        });
12885    }
12886
12887    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12888        if self.take_rename(true, window, cx).is_some() {
12889            return;
12890        }
12891
12892        if self.mode.is_single_line() {
12893            cx.propagate();
12894            return;
12895        }
12896
12897        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12898
12899        let text_layout_details = &self.text_layout_details(window);
12900        let selection_count = self.selections.count();
12901        let first_selection = self.selections.first_anchor();
12902
12903        self.change_selections(Default::default(), window, cx, |s| {
12904            s.move_with(|map, selection| {
12905                if !selection.is_empty() {
12906                    selection.goal = SelectionGoal::None;
12907                }
12908                let (cursor, goal) = movement::up(
12909                    map,
12910                    selection.start,
12911                    selection.goal,
12912                    false,
12913                    text_layout_details,
12914                );
12915                selection.collapse_to(cursor, goal);
12916            });
12917        });
12918
12919        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12920        {
12921            cx.propagate();
12922        }
12923    }
12924
12925    pub fn move_up_by_lines(
12926        &mut self,
12927        action: &MoveUpByLines,
12928        window: &mut Window,
12929        cx: &mut Context<Self>,
12930    ) {
12931        if self.take_rename(true, window, cx).is_some() {
12932            return;
12933        }
12934
12935        if self.mode.is_single_line() {
12936            cx.propagate();
12937            return;
12938        }
12939
12940        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12941
12942        let text_layout_details = &self.text_layout_details(window);
12943
12944        self.change_selections(Default::default(), window, cx, |s| {
12945            s.move_with(|map, selection| {
12946                if !selection.is_empty() {
12947                    selection.goal = SelectionGoal::None;
12948                }
12949                let (cursor, goal) = movement::up_by_rows(
12950                    map,
12951                    selection.start,
12952                    action.lines,
12953                    selection.goal,
12954                    false,
12955                    text_layout_details,
12956                );
12957                selection.collapse_to(cursor, goal);
12958            });
12959        })
12960    }
12961
12962    pub fn move_down_by_lines(
12963        &mut self,
12964        action: &MoveDownByLines,
12965        window: &mut Window,
12966        cx: &mut Context<Self>,
12967    ) {
12968        if self.take_rename(true, window, cx).is_some() {
12969            return;
12970        }
12971
12972        if self.mode.is_single_line() {
12973            cx.propagate();
12974            return;
12975        }
12976
12977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12978
12979        let text_layout_details = &self.text_layout_details(window);
12980
12981        self.change_selections(Default::default(), window, cx, |s| {
12982            s.move_with(|map, selection| {
12983                if !selection.is_empty() {
12984                    selection.goal = SelectionGoal::None;
12985                }
12986                let (cursor, goal) = movement::down_by_rows(
12987                    map,
12988                    selection.start,
12989                    action.lines,
12990                    selection.goal,
12991                    false,
12992                    text_layout_details,
12993                );
12994                selection.collapse_to(cursor, goal);
12995            });
12996        })
12997    }
12998
12999    pub fn select_down_by_lines(
13000        &mut self,
13001        action: &SelectDownByLines,
13002        window: &mut Window,
13003        cx: &mut Context<Self>,
13004    ) {
13005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13006        let text_layout_details = &self.text_layout_details(window);
13007        self.change_selections(Default::default(), window, cx, |s| {
13008            s.move_heads_with(|map, head, goal| {
13009                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13010            })
13011        })
13012    }
13013
13014    pub fn select_up_by_lines(
13015        &mut self,
13016        action: &SelectUpByLines,
13017        window: &mut Window,
13018        cx: &mut Context<Self>,
13019    ) {
13020        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13021        let text_layout_details = &self.text_layout_details(window);
13022        self.change_selections(Default::default(), window, cx, |s| {
13023            s.move_heads_with(|map, head, goal| {
13024                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13025            })
13026        })
13027    }
13028
13029    pub fn select_page_up(
13030        &mut self,
13031        _: &SelectPageUp,
13032        window: &mut Window,
13033        cx: &mut Context<Self>,
13034    ) {
13035        let Some(row_count) = self.visible_row_count() else {
13036            return;
13037        };
13038
13039        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13040
13041        let text_layout_details = &self.text_layout_details(window);
13042
13043        self.change_selections(Default::default(), window, cx, |s| {
13044            s.move_heads_with(|map, head, goal| {
13045                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13046            })
13047        })
13048    }
13049
13050    pub fn move_page_up(
13051        &mut self,
13052        action: &MovePageUp,
13053        window: &mut Window,
13054        cx: &mut Context<Self>,
13055    ) {
13056        if self.take_rename(true, window, cx).is_some() {
13057            return;
13058        }
13059
13060        if self
13061            .context_menu
13062            .borrow_mut()
13063            .as_mut()
13064            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13065            .unwrap_or(false)
13066        {
13067            return;
13068        }
13069
13070        if matches!(self.mode, EditorMode::SingleLine) {
13071            cx.propagate();
13072            return;
13073        }
13074
13075        let Some(row_count) = self.visible_row_count() else {
13076            return;
13077        };
13078
13079        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13080
13081        let effects = if action.center_cursor {
13082            SelectionEffects::scroll(Autoscroll::center())
13083        } else {
13084            SelectionEffects::default()
13085        };
13086
13087        let text_layout_details = &self.text_layout_details(window);
13088
13089        self.change_selections(effects, window, cx, |s| {
13090            s.move_with(|map, selection| {
13091                if !selection.is_empty() {
13092                    selection.goal = SelectionGoal::None;
13093                }
13094                let (cursor, goal) = movement::up_by_rows(
13095                    map,
13096                    selection.end,
13097                    row_count,
13098                    selection.goal,
13099                    false,
13100                    text_layout_details,
13101                );
13102                selection.collapse_to(cursor, goal);
13103            });
13104        });
13105    }
13106
13107    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13109        let text_layout_details = &self.text_layout_details(window);
13110        self.change_selections(Default::default(), window, cx, |s| {
13111            s.move_heads_with(|map, head, goal| {
13112                movement::up(map, head, goal, false, text_layout_details)
13113            })
13114        })
13115    }
13116
13117    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13118        self.take_rename(true, window, cx);
13119
13120        if self.mode.is_single_line() {
13121            cx.propagate();
13122            return;
13123        }
13124
13125        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13126
13127        let text_layout_details = &self.text_layout_details(window);
13128        let selection_count = self.selections.count();
13129        let first_selection = self.selections.first_anchor();
13130
13131        self.change_selections(Default::default(), window, cx, |s| {
13132            s.move_with(|map, selection| {
13133                if !selection.is_empty() {
13134                    selection.goal = SelectionGoal::None;
13135                }
13136                let (cursor, goal) = movement::down(
13137                    map,
13138                    selection.end,
13139                    selection.goal,
13140                    false,
13141                    text_layout_details,
13142                );
13143                selection.collapse_to(cursor, goal);
13144            });
13145        });
13146
13147        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13148        {
13149            cx.propagate();
13150        }
13151    }
13152
13153    pub fn select_page_down(
13154        &mut self,
13155        _: &SelectPageDown,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        let Some(row_count) = self.visible_row_count() else {
13160            return;
13161        };
13162
13163        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13164
13165        let text_layout_details = &self.text_layout_details(window);
13166
13167        self.change_selections(Default::default(), window, cx, |s| {
13168            s.move_heads_with(|map, head, goal| {
13169                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13170            })
13171        })
13172    }
13173
13174    pub fn move_page_down(
13175        &mut self,
13176        action: &MovePageDown,
13177        window: &mut Window,
13178        cx: &mut Context<Self>,
13179    ) {
13180        if self.take_rename(true, window, cx).is_some() {
13181            return;
13182        }
13183
13184        if self
13185            .context_menu
13186            .borrow_mut()
13187            .as_mut()
13188            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13189            .unwrap_or(false)
13190        {
13191            return;
13192        }
13193
13194        if matches!(self.mode, EditorMode::SingleLine) {
13195            cx.propagate();
13196            return;
13197        }
13198
13199        let Some(row_count) = self.visible_row_count() else {
13200            return;
13201        };
13202
13203        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13204
13205        let effects = if action.center_cursor {
13206            SelectionEffects::scroll(Autoscroll::center())
13207        } else {
13208            SelectionEffects::default()
13209        };
13210
13211        let text_layout_details = &self.text_layout_details(window);
13212        self.change_selections(effects, window, cx, |s| {
13213            s.move_with(|map, selection| {
13214                if !selection.is_empty() {
13215                    selection.goal = SelectionGoal::None;
13216                }
13217                let (cursor, goal) = movement::down_by_rows(
13218                    map,
13219                    selection.end,
13220                    row_count,
13221                    selection.goal,
13222                    false,
13223                    text_layout_details,
13224                );
13225                selection.collapse_to(cursor, goal);
13226            });
13227        });
13228    }
13229
13230    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13231        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13232        let text_layout_details = &self.text_layout_details(window);
13233        self.change_selections(Default::default(), window, cx, |s| {
13234            s.move_heads_with(|map, head, goal| {
13235                movement::down(map, head, goal, false, text_layout_details)
13236            })
13237        });
13238    }
13239
13240    pub fn context_menu_first(
13241        &mut self,
13242        _: &ContextMenuFirst,
13243        window: &mut Window,
13244        cx: &mut Context<Self>,
13245    ) {
13246        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13247            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13248        }
13249    }
13250
13251    pub fn context_menu_prev(
13252        &mut self,
13253        _: &ContextMenuPrevious,
13254        window: &mut Window,
13255        cx: &mut Context<Self>,
13256    ) {
13257        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13258            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13259        }
13260    }
13261
13262    pub fn context_menu_next(
13263        &mut self,
13264        _: &ContextMenuNext,
13265        window: &mut Window,
13266        cx: &mut Context<Self>,
13267    ) {
13268        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13269            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13270        }
13271    }
13272
13273    pub fn context_menu_last(
13274        &mut self,
13275        _: &ContextMenuLast,
13276        window: &mut Window,
13277        cx: &mut Context<Self>,
13278    ) {
13279        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13280            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13281        }
13282    }
13283
13284    pub fn signature_help_prev(
13285        &mut self,
13286        _: &SignatureHelpPrevious,
13287        _: &mut Window,
13288        cx: &mut Context<Self>,
13289    ) {
13290        if let Some(popover) = self.signature_help_state.popover_mut() {
13291            if popover.current_signature == 0 {
13292                popover.current_signature = popover.signatures.len() - 1;
13293            } else {
13294                popover.current_signature -= 1;
13295            }
13296            cx.notify();
13297        }
13298    }
13299
13300    pub fn signature_help_next(
13301        &mut self,
13302        _: &SignatureHelpNext,
13303        _: &mut Window,
13304        cx: &mut Context<Self>,
13305    ) {
13306        if let Some(popover) = self.signature_help_state.popover_mut() {
13307            if popover.current_signature + 1 == popover.signatures.len() {
13308                popover.current_signature = 0;
13309            } else {
13310                popover.current_signature += 1;
13311            }
13312            cx.notify();
13313        }
13314    }
13315
13316    pub fn move_to_previous_word_start(
13317        &mut self,
13318        _: &MoveToPreviousWordStart,
13319        window: &mut Window,
13320        cx: &mut Context<Self>,
13321    ) {
13322        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13323        self.change_selections(Default::default(), window, cx, |s| {
13324            s.move_cursors_with(|map, head, _| {
13325                (
13326                    movement::previous_word_start(map, head),
13327                    SelectionGoal::None,
13328                )
13329            });
13330        })
13331    }
13332
13333    pub fn move_to_previous_subword_start(
13334        &mut self,
13335        _: &MoveToPreviousSubwordStart,
13336        window: &mut Window,
13337        cx: &mut Context<Self>,
13338    ) {
13339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13340        self.change_selections(Default::default(), window, cx, |s| {
13341            s.move_cursors_with(|map, head, _| {
13342                (
13343                    movement::previous_subword_start(map, head),
13344                    SelectionGoal::None,
13345                )
13346            });
13347        })
13348    }
13349
13350    pub fn select_to_previous_word_start(
13351        &mut self,
13352        _: &SelectToPreviousWordStart,
13353        window: &mut Window,
13354        cx: &mut Context<Self>,
13355    ) {
13356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13357        self.change_selections(Default::default(), window, cx, |s| {
13358            s.move_heads_with(|map, head, _| {
13359                (
13360                    movement::previous_word_start(map, head),
13361                    SelectionGoal::None,
13362                )
13363            });
13364        })
13365    }
13366
13367    pub fn select_to_previous_subword_start(
13368        &mut self,
13369        _: &SelectToPreviousSubwordStart,
13370        window: &mut Window,
13371        cx: &mut Context<Self>,
13372    ) {
13373        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13374        self.change_selections(Default::default(), window, cx, |s| {
13375            s.move_heads_with(|map, head, _| {
13376                (
13377                    movement::previous_subword_start(map, head),
13378                    SelectionGoal::None,
13379                )
13380            });
13381        })
13382    }
13383
13384    pub fn delete_to_previous_word_start(
13385        &mut self,
13386        action: &DeleteToPreviousWordStart,
13387        window: &mut Window,
13388        cx: &mut Context<Self>,
13389    ) {
13390        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13391        self.transact(window, cx, |this, window, cx| {
13392            this.select_autoclose_pair(window, cx);
13393            this.change_selections(Default::default(), window, cx, |s| {
13394                s.move_with(|map, selection| {
13395                    if selection.is_empty() {
13396                        let mut cursor = if action.ignore_newlines {
13397                            movement::previous_word_start(map, selection.head())
13398                        } else {
13399                            movement::previous_word_start_or_newline(map, selection.head())
13400                        };
13401                        cursor = movement::adjust_greedy_deletion(
13402                            map,
13403                            selection.head(),
13404                            cursor,
13405                            action.ignore_brackets,
13406                        );
13407                        selection.set_head(cursor, SelectionGoal::None);
13408                    }
13409                });
13410            });
13411            this.insert("", window, cx);
13412        });
13413    }
13414
13415    pub fn delete_to_previous_subword_start(
13416        &mut self,
13417        _: &DeleteToPreviousSubwordStart,
13418        window: &mut Window,
13419        cx: &mut Context<Self>,
13420    ) {
13421        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13422        self.transact(window, cx, |this, window, cx| {
13423            this.select_autoclose_pair(window, cx);
13424            this.change_selections(Default::default(), window, cx, |s| {
13425                s.move_with(|map, selection| {
13426                    if selection.is_empty() {
13427                        let mut cursor = movement::previous_subword_start(map, selection.head());
13428                        cursor =
13429                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13430                        selection.set_head(cursor, SelectionGoal::None);
13431                    }
13432                });
13433            });
13434            this.insert("", window, cx);
13435        });
13436    }
13437
13438    pub fn move_to_next_word_end(
13439        &mut self,
13440        _: &MoveToNextWordEnd,
13441        window: &mut Window,
13442        cx: &mut Context<Self>,
13443    ) {
13444        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13445        self.change_selections(Default::default(), window, cx, |s| {
13446            s.move_cursors_with(|map, head, _| {
13447                (movement::next_word_end(map, head), SelectionGoal::None)
13448            });
13449        })
13450    }
13451
13452    pub fn move_to_next_subword_end(
13453        &mut self,
13454        _: &MoveToNextSubwordEnd,
13455        window: &mut Window,
13456        cx: &mut Context<Self>,
13457    ) {
13458        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13459        self.change_selections(Default::default(), window, cx, |s| {
13460            s.move_cursors_with(|map, head, _| {
13461                (movement::next_subword_end(map, head), SelectionGoal::None)
13462            });
13463        })
13464    }
13465
13466    pub fn select_to_next_word_end(
13467        &mut self,
13468        _: &SelectToNextWordEnd,
13469        window: &mut Window,
13470        cx: &mut Context<Self>,
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                (movement::next_word_end(map, head), SelectionGoal::None)
13476            });
13477        })
13478    }
13479
13480    pub fn select_to_next_subword_end(
13481        &mut self,
13482        _: &SelectToNextSubwordEnd,
13483        window: &mut Window,
13484        cx: &mut Context<Self>,
13485    ) {
13486        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13487        self.change_selections(Default::default(), window, cx, |s| {
13488            s.move_heads_with(|map, head, _| {
13489                (movement::next_subword_end(map, head), SelectionGoal::None)
13490            });
13491        })
13492    }
13493
13494    pub fn delete_to_next_word_end(
13495        &mut self,
13496        action: &DeleteToNextWordEnd,
13497        window: &mut Window,
13498        cx: &mut Context<Self>,
13499    ) {
13500        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13501        self.transact(window, cx, |this, window, cx| {
13502            this.change_selections(Default::default(), window, cx, |s| {
13503                s.move_with(|map, selection| {
13504                    if selection.is_empty() {
13505                        let mut cursor = if action.ignore_newlines {
13506                            movement::next_word_end(map, selection.head())
13507                        } else {
13508                            movement::next_word_end_or_newline(map, selection.head())
13509                        };
13510                        cursor = movement::adjust_greedy_deletion(
13511                            map,
13512                            selection.head(),
13513                            cursor,
13514                            action.ignore_brackets,
13515                        );
13516                        selection.set_head(cursor, SelectionGoal::None);
13517                    }
13518                });
13519            });
13520            this.insert("", window, cx);
13521        });
13522    }
13523
13524    pub fn delete_to_next_subword_end(
13525        &mut self,
13526        _: &DeleteToNextSubwordEnd,
13527        window: &mut Window,
13528        cx: &mut Context<Self>,
13529    ) {
13530        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13531        self.transact(window, cx, |this, window, cx| {
13532            this.change_selections(Default::default(), window, cx, |s| {
13533                s.move_with(|map, selection| {
13534                    if selection.is_empty() {
13535                        let mut cursor = movement::next_subword_end(map, selection.head());
13536                        cursor =
13537                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13538                        selection.set_head(cursor, SelectionGoal::None);
13539                    }
13540                });
13541            });
13542            this.insert("", window, cx);
13543        });
13544    }
13545
13546    pub fn move_to_beginning_of_line(
13547        &mut self,
13548        action: &MoveToBeginningOfLine,
13549        window: &mut Window,
13550        cx: &mut Context<Self>,
13551    ) {
13552        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13553        self.change_selections(Default::default(), window, cx, |s| {
13554            s.move_cursors_with(|map, head, _| {
13555                (
13556                    movement::indented_line_beginning(
13557                        map,
13558                        head,
13559                        action.stop_at_soft_wraps,
13560                        action.stop_at_indent,
13561                    ),
13562                    SelectionGoal::None,
13563                )
13564            });
13565        })
13566    }
13567
13568    pub fn select_to_beginning_of_line(
13569        &mut self,
13570        action: &SelectToBeginningOfLine,
13571        window: &mut Window,
13572        cx: &mut Context<Self>,
13573    ) {
13574        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13575        self.change_selections(Default::default(), window, cx, |s| {
13576            s.move_heads_with(|map, head, _| {
13577                (
13578                    movement::indented_line_beginning(
13579                        map,
13580                        head,
13581                        action.stop_at_soft_wraps,
13582                        action.stop_at_indent,
13583                    ),
13584                    SelectionGoal::None,
13585                )
13586            });
13587        });
13588    }
13589
13590    pub fn delete_to_beginning_of_line(
13591        &mut self,
13592        action: &DeleteToBeginningOfLine,
13593        window: &mut Window,
13594        cx: &mut Context<Self>,
13595    ) {
13596        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13597        self.transact(window, cx, |this, window, cx| {
13598            this.change_selections(Default::default(), window, cx, |s| {
13599                s.move_with(|_, selection| {
13600                    selection.reversed = true;
13601                });
13602            });
13603
13604            this.select_to_beginning_of_line(
13605                &SelectToBeginningOfLine {
13606                    stop_at_soft_wraps: false,
13607                    stop_at_indent: action.stop_at_indent,
13608                },
13609                window,
13610                cx,
13611            );
13612            this.backspace(&Backspace, window, cx);
13613        });
13614    }
13615
13616    pub fn move_to_end_of_line(
13617        &mut self,
13618        action: &MoveToEndOfLine,
13619        window: &mut Window,
13620        cx: &mut Context<Self>,
13621    ) {
13622        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13623        self.change_selections(Default::default(), window, cx, |s| {
13624            s.move_cursors_with(|map, head, _| {
13625                (
13626                    movement::line_end(map, head, action.stop_at_soft_wraps),
13627                    SelectionGoal::None,
13628                )
13629            });
13630        })
13631    }
13632
13633    pub fn select_to_end_of_line(
13634        &mut self,
13635        action: &SelectToEndOfLine,
13636        window: &mut Window,
13637        cx: &mut Context<Self>,
13638    ) {
13639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13640        self.change_selections(Default::default(), window, cx, |s| {
13641            s.move_heads_with(|map, head, _| {
13642                (
13643                    movement::line_end(map, head, action.stop_at_soft_wraps),
13644                    SelectionGoal::None,
13645                )
13646            });
13647        })
13648    }
13649
13650    pub fn delete_to_end_of_line(
13651        &mut self,
13652        _: &DeleteToEndOfLine,
13653        window: &mut Window,
13654        cx: &mut Context<Self>,
13655    ) {
13656        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13657        self.transact(window, cx, |this, window, cx| {
13658            this.select_to_end_of_line(
13659                &SelectToEndOfLine {
13660                    stop_at_soft_wraps: false,
13661                },
13662                window,
13663                cx,
13664            );
13665            this.delete(&Delete, window, cx);
13666        });
13667    }
13668
13669    pub fn cut_to_end_of_line(
13670        &mut self,
13671        action: &CutToEndOfLine,
13672        window: &mut Window,
13673        cx: &mut Context<Self>,
13674    ) {
13675        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13676        self.transact(window, cx, |this, window, cx| {
13677            this.select_to_end_of_line(
13678                &SelectToEndOfLine {
13679                    stop_at_soft_wraps: false,
13680                },
13681                window,
13682                cx,
13683            );
13684            if !action.stop_at_newlines {
13685                this.change_selections(Default::default(), window, cx, |s| {
13686                    s.move_with(|_, sel| {
13687                        if sel.is_empty() {
13688                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13689                        }
13690                    });
13691                });
13692            }
13693            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13694            let item = this.cut_common(false, window, cx);
13695            cx.write_to_clipboard(item);
13696        });
13697    }
13698
13699    pub fn move_to_start_of_paragraph(
13700        &mut self,
13701        _: &MoveToStartOfParagraph,
13702        window: &mut Window,
13703        cx: &mut Context<Self>,
13704    ) {
13705        if matches!(self.mode, EditorMode::SingleLine) {
13706            cx.propagate();
13707            return;
13708        }
13709        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13710        self.change_selections(Default::default(), window, cx, |s| {
13711            s.move_with(|map, selection| {
13712                selection.collapse_to(
13713                    movement::start_of_paragraph(map, selection.head(), 1),
13714                    SelectionGoal::None,
13715                )
13716            });
13717        })
13718    }
13719
13720    pub fn move_to_end_of_paragraph(
13721        &mut self,
13722        _: &MoveToEndOfParagraph,
13723        window: &mut Window,
13724        cx: &mut Context<Self>,
13725    ) {
13726        if matches!(self.mode, EditorMode::SingleLine) {
13727            cx.propagate();
13728            return;
13729        }
13730        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13731        self.change_selections(Default::default(), window, cx, |s| {
13732            s.move_with(|map, selection| {
13733                selection.collapse_to(
13734                    movement::end_of_paragraph(map, selection.head(), 1),
13735                    SelectionGoal::None,
13736                )
13737            });
13738        })
13739    }
13740
13741    pub fn select_to_start_of_paragraph(
13742        &mut self,
13743        _: &SelectToStartOfParagraph,
13744        window: &mut Window,
13745        cx: &mut Context<Self>,
13746    ) {
13747        if matches!(self.mode, EditorMode::SingleLine) {
13748            cx.propagate();
13749            return;
13750        }
13751        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13752        self.change_selections(Default::default(), window, cx, |s| {
13753            s.move_heads_with(|map, head, _| {
13754                (
13755                    movement::start_of_paragraph(map, head, 1),
13756                    SelectionGoal::None,
13757                )
13758            });
13759        })
13760    }
13761
13762    pub fn select_to_end_of_paragraph(
13763        &mut self,
13764        _: &SelectToEndOfParagraph,
13765        window: &mut Window,
13766        cx: &mut Context<Self>,
13767    ) {
13768        if matches!(self.mode, EditorMode::SingleLine) {
13769            cx.propagate();
13770            return;
13771        }
13772        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13773        self.change_selections(Default::default(), window, cx, |s| {
13774            s.move_heads_with(|map, head, _| {
13775                (
13776                    movement::end_of_paragraph(map, head, 1),
13777                    SelectionGoal::None,
13778                )
13779            });
13780        })
13781    }
13782
13783    pub fn move_to_start_of_excerpt(
13784        &mut self,
13785        _: &MoveToStartOfExcerpt,
13786        window: &mut Window,
13787        cx: &mut Context<Self>,
13788    ) {
13789        if matches!(self.mode, EditorMode::SingleLine) {
13790            cx.propagate();
13791            return;
13792        }
13793        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13794        self.change_selections(Default::default(), window, cx, |s| {
13795            s.move_with(|map, selection| {
13796                selection.collapse_to(
13797                    movement::start_of_excerpt(
13798                        map,
13799                        selection.head(),
13800                        workspace::searchable::Direction::Prev,
13801                    ),
13802                    SelectionGoal::None,
13803                )
13804            });
13805        })
13806    }
13807
13808    pub fn move_to_start_of_next_excerpt(
13809        &mut self,
13810        _: &MoveToStartOfNextExcerpt,
13811        window: &mut Window,
13812        cx: &mut Context<Self>,
13813    ) {
13814        if matches!(self.mode, EditorMode::SingleLine) {
13815            cx.propagate();
13816            return;
13817        }
13818
13819        self.change_selections(Default::default(), window, cx, |s| {
13820            s.move_with(|map, selection| {
13821                selection.collapse_to(
13822                    movement::start_of_excerpt(
13823                        map,
13824                        selection.head(),
13825                        workspace::searchable::Direction::Next,
13826                    ),
13827                    SelectionGoal::None,
13828                )
13829            });
13830        })
13831    }
13832
13833    pub fn move_to_end_of_excerpt(
13834        &mut self,
13835        _: &MoveToEndOfExcerpt,
13836        window: &mut Window,
13837        cx: &mut Context<Self>,
13838    ) {
13839        if matches!(self.mode, EditorMode::SingleLine) {
13840            cx.propagate();
13841            return;
13842        }
13843        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13844        self.change_selections(Default::default(), window, cx, |s| {
13845            s.move_with(|map, selection| {
13846                selection.collapse_to(
13847                    movement::end_of_excerpt(
13848                        map,
13849                        selection.head(),
13850                        workspace::searchable::Direction::Next,
13851                    ),
13852                    SelectionGoal::None,
13853                )
13854            });
13855        })
13856    }
13857
13858    pub fn move_to_end_of_previous_excerpt(
13859        &mut self,
13860        _: &MoveToEndOfPreviousExcerpt,
13861        window: &mut Window,
13862        cx: &mut Context<Self>,
13863    ) {
13864        if matches!(self.mode, EditorMode::SingleLine) {
13865            cx.propagate();
13866            return;
13867        }
13868        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13869        self.change_selections(Default::default(), window, cx, |s| {
13870            s.move_with(|map, selection| {
13871                selection.collapse_to(
13872                    movement::end_of_excerpt(
13873                        map,
13874                        selection.head(),
13875                        workspace::searchable::Direction::Prev,
13876                    ),
13877                    SelectionGoal::None,
13878                )
13879            });
13880        })
13881    }
13882
13883    pub fn select_to_start_of_excerpt(
13884        &mut self,
13885        _: &SelectToStartOfExcerpt,
13886        window: &mut Window,
13887        cx: &mut Context<Self>,
13888    ) {
13889        if matches!(self.mode, EditorMode::SingleLine) {
13890            cx.propagate();
13891            return;
13892        }
13893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13894        self.change_selections(Default::default(), window, cx, |s| {
13895            s.move_heads_with(|map, head, _| {
13896                (
13897                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13898                    SelectionGoal::None,
13899                )
13900            });
13901        })
13902    }
13903
13904    pub fn select_to_start_of_next_excerpt(
13905        &mut self,
13906        _: &SelectToStartOfNextExcerpt,
13907        window: &mut Window,
13908        cx: &mut Context<Self>,
13909    ) {
13910        if matches!(self.mode, EditorMode::SingleLine) {
13911            cx.propagate();
13912            return;
13913        }
13914        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13915        self.change_selections(Default::default(), window, cx, |s| {
13916            s.move_heads_with(|map, head, _| {
13917                (
13918                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13919                    SelectionGoal::None,
13920                )
13921            });
13922        })
13923    }
13924
13925    pub fn select_to_end_of_excerpt(
13926        &mut self,
13927        _: &SelectToEndOfExcerpt,
13928        window: &mut Window,
13929        cx: &mut Context<Self>,
13930    ) {
13931        if matches!(self.mode, EditorMode::SingleLine) {
13932            cx.propagate();
13933            return;
13934        }
13935        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13936        self.change_selections(Default::default(), window, cx, |s| {
13937            s.move_heads_with(|map, head, _| {
13938                (
13939                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13940                    SelectionGoal::None,
13941                )
13942            });
13943        })
13944    }
13945
13946    pub fn select_to_end_of_previous_excerpt(
13947        &mut self,
13948        _: &SelectToEndOfPreviousExcerpt,
13949        window: &mut Window,
13950        cx: &mut Context<Self>,
13951    ) {
13952        if matches!(self.mode, EditorMode::SingleLine) {
13953            cx.propagate();
13954            return;
13955        }
13956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13957        self.change_selections(Default::default(), window, cx, |s| {
13958            s.move_heads_with(|map, head, _| {
13959                (
13960                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13961                    SelectionGoal::None,
13962                )
13963            });
13964        })
13965    }
13966
13967    pub fn move_to_beginning(
13968        &mut self,
13969        _: &MoveToBeginning,
13970        window: &mut Window,
13971        cx: &mut Context<Self>,
13972    ) {
13973        if matches!(self.mode, EditorMode::SingleLine) {
13974            cx.propagate();
13975            return;
13976        }
13977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13978        self.change_selections(Default::default(), window, cx, |s| {
13979            s.select_ranges(vec![0..0]);
13980        });
13981    }
13982
13983    pub fn select_to_beginning(
13984        &mut self,
13985        _: &SelectToBeginning,
13986        window: &mut Window,
13987        cx: &mut Context<Self>,
13988    ) {
13989        let mut selection = self.selections.last::<Point>(cx);
13990        selection.set_head(Point::zero(), SelectionGoal::None);
13991        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13992        self.change_selections(Default::default(), window, cx, |s| {
13993            s.select(vec![selection]);
13994        });
13995    }
13996
13997    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13998        if matches!(self.mode, EditorMode::SingleLine) {
13999            cx.propagate();
14000            return;
14001        }
14002        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14003        let cursor = self.buffer.read(cx).read(cx).len();
14004        self.change_selections(Default::default(), window, cx, |s| {
14005            s.select_ranges(vec![cursor..cursor])
14006        });
14007    }
14008
14009    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14010        self.nav_history = nav_history;
14011    }
14012
14013    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14014        self.nav_history.as_ref()
14015    }
14016
14017    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14018        self.push_to_nav_history(
14019            self.selections.newest_anchor().head(),
14020            None,
14021            false,
14022            true,
14023            cx,
14024        );
14025    }
14026
14027    fn push_to_nav_history(
14028        &mut self,
14029        cursor_anchor: Anchor,
14030        new_position: Option<Point>,
14031        is_deactivate: bool,
14032        always: bool,
14033        cx: &mut Context<Self>,
14034    ) {
14035        if let Some(nav_history) = self.nav_history.as_mut() {
14036            let buffer = self.buffer.read(cx).read(cx);
14037            let cursor_position = cursor_anchor.to_point(&buffer);
14038            let scroll_state = self.scroll_manager.anchor();
14039            let scroll_top_row = scroll_state.top_row(&buffer);
14040            drop(buffer);
14041
14042            if let Some(new_position) = new_position {
14043                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14044                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14045                    return;
14046                }
14047            }
14048
14049            nav_history.push(
14050                Some(NavigationData {
14051                    cursor_anchor,
14052                    cursor_position,
14053                    scroll_anchor: scroll_state,
14054                    scroll_top_row,
14055                }),
14056                cx,
14057            );
14058            cx.emit(EditorEvent::PushedToNavHistory {
14059                anchor: cursor_anchor,
14060                is_deactivate,
14061            })
14062        }
14063    }
14064
14065    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14066        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14067        let buffer = self.buffer.read(cx).snapshot(cx);
14068        let mut selection = self.selections.first::<usize>(cx);
14069        selection.set_head(buffer.len(), SelectionGoal::None);
14070        self.change_selections(Default::default(), window, cx, |s| {
14071            s.select(vec![selection]);
14072        });
14073    }
14074
14075    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14076        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14077        let end = self.buffer.read(cx).read(cx).len();
14078        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14079            s.select_ranges(vec![0..end]);
14080        });
14081    }
14082
14083    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14084        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14085        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14086        let mut selections = self.selections.all::<Point>(cx);
14087        let max_point = display_map.buffer_snapshot.max_point();
14088        for selection in &mut selections {
14089            let rows = selection.spanned_rows(true, &display_map);
14090            selection.start = Point::new(rows.start.0, 0);
14091            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14092            selection.reversed = false;
14093        }
14094        self.change_selections(Default::default(), window, cx, |s| {
14095            s.select(selections);
14096        });
14097    }
14098
14099    pub fn split_selection_into_lines(
14100        &mut self,
14101        action: &SplitSelectionIntoLines,
14102        window: &mut Window,
14103        cx: &mut Context<Self>,
14104    ) {
14105        let selections = self
14106            .selections
14107            .all::<Point>(cx)
14108            .into_iter()
14109            .map(|selection| selection.start..selection.end)
14110            .collect::<Vec<_>>();
14111        self.unfold_ranges(&selections, true, true, cx);
14112
14113        let mut new_selection_ranges = Vec::new();
14114        {
14115            let buffer = self.buffer.read(cx).read(cx);
14116            for selection in selections {
14117                for row in selection.start.row..selection.end.row {
14118                    let line_start = Point::new(row, 0);
14119                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14120
14121                    if action.keep_selections {
14122                        // Keep the selection range for each line
14123                        let selection_start = if row == selection.start.row {
14124                            selection.start
14125                        } else {
14126                            line_start
14127                        };
14128                        new_selection_ranges.push(selection_start..line_end);
14129                    } else {
14130                        // Collapse to cursor at end of line
14131                        new_selection_ranges.push(line_end..line_end);
14132                    }
14133                }
14134
14135                let is_multiline_selection = selection.start.row != selection.end.row;
14136                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14137                // so this action feels more ergonomic when paired with other selection operations
14138                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14139                if !should_skip_last {
14140                    if action.keep_selections {
14141                        if is_multiline_selection {
14142                            let line_start = Point::new(selection.end.row, 0);
14143                            new_selection_ranges.push(line_start..selection.end);
14144                        } else {
14145                            new_selection_ranges.push(selection.start..selection.end);
14146                        }
14147                    } else {
14148                        new_selection_ranges.push(selection.end..selection.end);
14149                    }
14150                }
14151            }
14152        }
14153        self.change_selections(Default::default(), window, cx, |s| {
14154            s.select_ranges(new_selection_ranges);
14155        });
14156    }
14157
14158    pub fn add_selection_above(
14159        &mut self,
14160        _: &AddSelectionAbove,
14161        window: &mut Window,
14162        cx: &mut Context<Self>,
14163    ) {
14164        self.add_selection(true, window, cx);
14165    }
14166
14167    pub fn add_selection_below(
14168        &mut self,
14169        _: &AddSelectionBelow,
14170        window: &mut Window,
14171        cx: &mut Context<Self>,
14172    ) {
14173        self.add_selection(false, window, cx);
14174    }
14175
14176    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14177        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14178
14179        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14180        let all_selections = self.selections.all::<Point>(cx);
14181        let text_layout_details = self.text_layout_details(window);
14182
14183        let (mut columnar_selections, new_selections_to_columnarize) = {
14184            if let Some(state) = self.add_selections_state.as_ref() {
14185                let columnar_selection_ids: HashSet<_> = state
14186                    .groups
14187                    .iter()
14188                    .flat_map(|group| group.stack.iter())
14189                    .copied()
14190                    .collect();
14191
14192                all_selections
14193                    .into_iter()
14194                    .partition(|s| columnar_selection_ids.contains(&s.id))
14195            } else {
14196                (Vec::new(), all_selections)
14197            }
14198        };
14199
14200        let mut state = self
14201            .add_selections_state
14202            .take()
14203            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14204
14205        for selection in new_selections_to_columnarize {
14206            let range = selection.display_range(&display_map).sorted();
14207            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14208            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14209            let positions = start_x.min(end_x)..start_x.max(end_x);
14210            let mut stack = Vec::new();
14211            for row in range.start.row().0..=range.end.row().0 {
14212                if let Some(selection) = self.selections.build_columnar_selection(
14213                    &display_map,
14214                    DisplayRow(row),
14215                    &positions,
14216                    selection.reversed,
14217                    &text_layout_details,
14218                ) {
14219                    stack.push(selection.id);
14220                    columnar_selections.push(selection);
14221                }
14222            }
14223            if !stack.is_empty() {
14224                if above {
14225                    stack.reverse();
14226                }
14227                state.groups.push(AddSelectionsGroup { above, stack });
14228            }
14229        }
14230
14231        let mut final_selections = Vec::new();
14232        let end_row = if above {
14233            DisplayRow(0)
14234        } else {
14235            display_map.max_point().row()
14236        };
14237
14238        let mut last_added_item_per_group = HashMap::default();
14239        for group in state.groups.iter_mut() {
14240            if let Some(last_id) = group.stack.last() {
14241                last_added_item_per_group.insert(*last_id, group);
14242            }
14243        }
14244
14245        for selection in columnar_selections {
14246            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14247                if above == group.above {
14248                    let range = selection.display_range(&display_map).sorted();
14249                    debug_assert_eq!(range.start.row(), range.end.row());
14250                    let mut row = range.start.row();
14251                    let positions =
14252                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14253                            px(start)..px(end)
14254                        } else {
14255                            let start_x =
14256                                display_map.x_for_display_point(range.start, &text_layout_details);
14257                            let end_x =
14258                                display_map.x_for_display_point(range.end, &text_layout_details);
14259                            start_x.min(end_x)..start_x.max(end_x)
14260                        };
14261
14262                    let mut maybe_new_selection = None;
14263                    while row != end_row {
14264                        if above {
14265                            row.0 -= 1;
14266                        } else {
14267                            row.0 += 1;
14268                        }
14269                        if let Some(new_selection) = self.selections.build_columnar_selection(
14270                            &display_map,
14271                            row,
14272                            &positions,
14273                            selection.reversed,
14274                            &text_layout_details,
14275                        ) {
14276                            maybe_new_selection = Some(new_selection);
14277                            break;
14278                        }
14279                    }
14280
14281                    if let Some(new_selection) = maybe_new_selection {
14282                        group.stack.push(new_selection.id);
14283                        if above {
14284                            final_selections.push(new_selection);
14285                            final_selections.push(selection);
14286                        } else {
14287                            final_selections.push(selection);
14288                            final_selections.push(new_selection);
14289                        }
14290                    } else {
14291                        final_selections.push(selection);
14292                    }
14293                } else {
14294                    group.stack.pop();
14295                }
14296            } else {
14297                final_selections.push(selection);
14298            }
14299        }
14300
14301        self.change_selections(Default::default(), window, cx, |s| {
14302            s.select(final_selections);
14303        });
14304
14305        let final_selection_ids: HashSet<_> = self
14306            .selections
14307            .all::<Point>(cx)
14308            .iter()
14309            .map(|s| s.id)
14310            .collect();
14311        state.groups.retain_mut(|group| {
14312            // selections might get merged above so we remove invalid items from stacks
14313            group.stack.retain(|id| final_selection_ids.contains(id));
14314
14315            // single selection in stack can be treated as initial state
14316            group.stack.len() > 1
14317        });
14318
14319        if !state.groups.is_empty() {
14320            self.add_selections_state = Some(state);
14321        }
14322    }
14323
14324    fn select_match_ranges(
14325        &mut self,
14326        range: Range<usize>,
14327        reversed: bool,
14328        replace_newest: bool,
14329        auto_scroll: Option<Autoscroll>,
14330        window: &mut Window,
14331        cx: &mut Context<Editor>,
14332    ) {
14333        self.unfold_ranges(
14334            std::slice::from_ref(&range),
14335            false,
14336            auto_scroll.is_some(),
14337            cx,
14338        );
14339        let effects = if let Some(scroll) = auto_scroll {
14340            SelectionEffects::scroll(scroll)
14341        } else {
14342            SelectionEffects::no_scroll()
14343        };
14344        self.change_selections(effects, window, cx, |s| {
14345            if replace_newest {
14346                s.delete(s.newest_anchor().id);
14347            }
14348            if reversed {
14349                s.insert_range(range.end..range.start);
14350            } else {
14351                s.insert_range(range);
14352            }
14353        });
14354    }
14355
14356    pub fn select_next_match_internal(
14357        &mut self,
14358        display_map: &DisplaySnapshot,
14359        replace_newest: bool,
14360        autoscroll: Option<Autoscroll>,
14361        window: &mut Window,
14362        cx: &mut Context<Self>,
14363    ) -> Result<()> {
14364        let buffer = &display_map.buffer_snapshot;
14365        let mut selections = self.selections.all::<usize>(cx);
14366        if let Some(mut select_next_state) = self.select_next_state.take() {
14367            let query = &select_next_state.query;
14368            if !select_next_state.done {
14369                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14370                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14371                let mut next_selected_range = None;
14372
14373                let bytes_after_last_selection =
14374                    buffer.bytes_in_range(last_selection.end..buffer.len());
14375                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14376                let query_matches = query
14377                    .stream_find_iter(bytes_after_last_selection)
14378                    .map(|result| (last_selection.end, result))
14379                    .chain(
14380                        query
14381                            .stream_find_iter(bytes_before_first_selection)
14382                            .map(|result| (0, result)),
14383                    );
14384
14385                for (start_offset, query_match) in query_matches {
14386                    let query_match = query_match.unwrap(); // can only fail due to I/O
14387                    let offset_range =
14388                        start_offset + query_match.start()..start_offset + query_match.end();
14389
14390                    if !select_next_state.wordwise
14391                        || (!buffer.is_inside_word(offset_range.start, None)
14392                            && !buffer.is_inside_word(offset_range.end, None))
14393                    {
14394                        // TODO: This is n^2, because we might check all the selections
14395                        if !selections
14396                            .iter()
14397                            .any(|selection| selection.range().overlaps(&offset_range))
14398                        {
14399                            next_selected_range = Some(offset_range);
14400                            break;
14401                        }
14402                    }
14403                }
14404
14405                if let Some(next_selected_range) = next_selected_range {
14406                    self.select_match_ranges(
14407                        next_selected_range,
14408                        last_selection.reversed,
14409                        replace_newest,
14410                        autoscroll,
14411                        window,
14412                        cx,
14413                    );
14414                } else {
14415                    select_next_state.done = true;
14416                }
14417            }
14418
14419            self.select_next_state = Some(select_next_state);
14420        } else {
14421            let mut only_carets = true;
14422            let mut same_text_selected = true;
14423            let mut selected_text = None;
14424
14425            let mut selections_iter = selections.iter().peekable();
14426            while let Some(selection) = selections_iter.next() {
14427                if selection.start != selection.end {
14428                    only_carets = false;
14429                }
14430
14431                if same_text_selected {
14432                    if selected_text.is_none() {
14433                        selected_text =
14434                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14435                    }
14436
14437                    if let Some(next_selection) = selections_iter.peek() {
14438                        if next_selection.range().len() == selection.range().len() {
14439                            let next_selected_text = buffer
14440                                .text_for_range(next_selection.range())
14441                                .collect::<String>();
14442                            if Some(next_selected_text) != selected_text {
14443                                same_text_selected = false;
14444                                selected_text = None;
14445                            }
14446                        } else {
14447                            same_text_selected = false;
14448                            selected_text = None;
14449                        }
14450                    }
14451                }
14452            }
14453
14454            if only_carets {
14455                for selection in &mut selections {
14456                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14457                    selection.start = word_range.start;
14458                    selection.end = word_range.end;
14459                    selection.goal = SelectionGoal::None;
14460                    selection.reversed = false;
14461                    self.select_match_ranges(
14462                        selection.start..selection.end,
14463                        selection.reversed,
14464                        replace_newest,
14465                        autoscroll,
14466                        window,
14467                        cx,
14468                    );
14469                }
14470
14471                if selections.len() == 1 {
14472                    let selection = selections
14473                        .last()
14474                        .expect("ensured that there's only one selection");
14475                    let query = buffer
14476                        .text_for_range(selection.start..selection.end)
14477                        .collect::<String>();
14478                    let is_empty = query.is_empty();
14479                    let select_state = SelectNextState {
14480                        query: AhoCorasick::new(&[query])?,
14481                        wordwise: true,
14482                        done: is_empty,
14483                    };
14484                    self.select_next_state = Some(select_state);
14485                } else {
14486                    self.select_next_state = None;
14487                }
14488            } else if let Some(selected_text) = selected_text {
14489                self.select_next_state = Some(SelectNextState {
14490                    query: AhoCorasick::new(&[selected_text])?,
14491                    wordwise: false,
14492                    done: false,
14493                });
14494                self.select_next_match_internal(
14495                    display_map,
14496                    replace_newest,
14497                    autoscroll,
14498                    window,
14499                    cx,
14500                )?;
14501            }
14502        }
14503        Ok(())
14504    }
14505
14506    pub fn select_all_matches(
14507        &mut self,
14508        _action: &SelectAllMatches,
14509        window: &mut Window,
14510        cx: &mut Context<Self>,
14511    ) -> Result<()> {
14512        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14513
14514        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14515
14516        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14517        let Some(select_next_state) = self.select_next_state.as_mut() else {
14518            return Ok(());
14519        };
14520        if select_next_state.done {
14521            return Ok(());
14522        }
14523
14524        let mut new_selections = Vec::new();
14525
14526        let reversed = self.selections.oldest::<usize>(cx).reversed;
14527        let buffer = &display_map.buffer_snapshot;
14528        let query_matches = select_next_state
14529            .query
14530            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14531
14532        for query_match in query_matches.into_iter() {
14533            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14534            let offset_range = if reversed {
14535                query_match.end()..query_match.start()
14536            } else {
14537                query_match.start()..query_match.end()
14538            };
14539
14540            if !select_next_state.wordwise
14541                || (!buffer.is_inside_word(offset_range.start, None)
14542                    && !buffer.is_inside_word(offset_range.end, None))
14543            {
14544                new_selections.push(offset_range.start..offset_range.end);
14545            }
14546        }
14547
14548        select_next_state.done = true;
14549
14550        if new_selections.is_empty() {
14551            log::error!("bug: new_selections is empty in select_all_matches");
14552            return Ok(());
14553        }
14554
14555        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14556        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14557            selections.select_ranges(new_selections)
14558        });
14559
14560        Ok(())
14561    }
14562
14563    pub fn select_next(
14564        &mut self,
14565        action: &SelectNext,
14566        window: &mut Window,
14567        cx: &mut Context<Self>,
14568    ) -> Result<()> {
14569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14570        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14571        self.select_next_match_internal(
14572            &display_map,
14573            action.replace_newest,
14574            Some(Autoscroll::newest()),
14575            window,
14576            cx,
14577        )?;
14578        Ok(())
14579    }
14580
14581    pub fn select_previous(
14582        &mut self,
14583        action: &SelectPrevious,
14584        window: &mut Window,
14585        cx: &mut Context<Self>,
14586    ) -> Result<()> {
14587        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14588        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14589        let buffer = &display_map.buffer_snapshot;
14590        let mut selections = self.selections.all::<usize>(cx);
14591        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14592            let query = &select_prev_state.query;
14593            if !select_prev_state.done {
14594                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14595                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14596                let mut next_selected_range = None;
14597                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14598                let bytes_before_last_selection =
14599                    buffer.reversed_bytes_in_range(0..last_selection.start);
14600                let bytes_after_first_selection =
14601                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14602                let query_matches = query
14603                    .stream_find_iter(bytes_before_last_selection)
14604                    .map(|result| (last_selection.start, result))
14605                    .chain(
14606                        query
14607                            .stream_find_iter(bytes_after_first_selection)
14608                            .map(|result| (buffer.len(), result)),
14609                    );
14610                for (end_offset, query_match) in query_matches {
14611                    let query_match = query_match.unwrap(); // can only fail due to I/O
14612                    let offset_range =
14613                        end_offset - query_match.end()..end_offset - query_match.start();
14614
14615                    if !select_prev_state.wordwise
14616                        || (!buffer.is_inside_word(offset_range.start, None)
14617                            && !buffer.is_inside_word(offset_range.end, None))
14618                    {
14619                        next_selected_range = Some(offset_range);
14620                        break;
14621                    }
14622                }
14623
14624                if let Some(next_selected_range) = next_selected_range {
14625                    self.select_match_ranges(
14626                        next_selected_range,
14627                        last_selection.reversed,
14628                        action.replace_newest,
14629                        Some(Autoscroll::newest()),
14630                        window,
14631                        cx,
14632                    );
14633                } else {
14634                    select_prev_state.done = true;
14635                }
14636            }
14637
14638            self.select_prev_state = Some(select_prev_state);
14639        } else {
14640            let mut only_carets = true;
14641            let mut same_text_selected = true;
14642            let mut selected_text = None;
14643
14644            let mut selections_iter = selections.iter().peekable();
14645            while let Some(selection) = selections_iter.next() {
14646                if selection.start != selection.end {
14647                    only_carets = false;
14648                }
14649
14650                if same_text_selected {
14651                    if selected_text.is_none() {
14652                        selected_text =
14653                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14654                    }
14655
14656                    if let Some(next_selection) = selections_iter.peek() {
14657                        if next_selection.range().len() == selection.range().len() {
14658                            let next_selected_text = buffer
14659                                .text_for_range(next_selection.range())
14660                                .collect::<String>();
14661                            if Some(next_selected_text) != selected_text {
14662                                same_text_selected = false;
14663                                selected_text = None;
14664                            }
14665                        } else {
14666                            same_text_selected = false;
14667                            selected_text = None;
14668                        }
14669                    }
14670                }
14671            }
14672
14673            if only_carets {
14674                for selection in &mut selections {
14675                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14676                    selection.start = word_range.start;
14677                    selection.end = word_range.end;
14678                    selection.goal = SelectionGoal::None;
14679                    selection.reversed = false;
14680                    self.select_match_ranges(
14681                        selection.start..selection.end,
14682                        selection.reversed,
14683                        action.replace_newest,
14684                        Some(Autoscroll::newest()),
14685                        window,
14686                        cx,
14687                    );
14688                }
14689                if selections.len() == 1 {
14690                    let selection = selections
14691                        .last()
14692                        .expect("ensured that there's only one selection");
14693                    let query = buffer
14694                        .text_for_range(selection.start..selection.end)
14695                        .collect::<String>();
14696                    let is_empty = query.is_empty();
14697                    let select_state = SelectNextState {
14698                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14699                        wordwise: true,
14700                        done: is_empty,
14701                    };
14702                    self.select_prev_state = Some(select_state);
14703                } else {
14704                    self.select_prev_state = None;
14705                }
14706            } else if let Some(selected_text) = selected_text {
14707                self.select_prev_state = Some(SelectNextState {
14708                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14709                    wordwise: false,
14710                    done: false,
14711                });
14712                self.select_previous(action, window, cx)?;
14713            }
14714        }
14715        Ok(())
14716    }
14717
14718    pub fn find_next_match(
14719        &mut self,
14720        _: &FindNextMatch,
14721        window: &mut Window,
14722        cx: &mut Context<Self>,
14723    ) -> Result<()> {
14724        let selections = self.selections.disjoint_anchors_arc();
14725        match selections.first() {
14726            Some(first) if selections.len() >= 2 => {
14727                self.change_selections(Default::default(), window, cx, |s| {
14728                    s.select_ranges([first.range()]);
14729                });
14730            }
14731            _ => self.select_next(
14732                &SelectNext {
14733                    replace_newest: true,
14734                },
14735                window,
14736                cx,
14737            )?,
14738        }
14739        Ok(())
14740    }
14741
14742    pub fn find_previous_match(
14743        &mut self,
14744        _: &FindPreviousMatch,
14745        window: &mut Window,
14746        cx: &mut Context<Self>,
14747    ) -> Result<()> {
14748        let selections = self.selections.disjoint_anchors_arc();
14749        match selections.last() {
14750            Some(last) if selections.len() >= 2 => {
14751                self.change_selections(Default::default(), window, cx, |s| {
14752                    s.select_ranges([last.range()]);
14753                });
14754            }
14755            _ => self.select_previous(
14756                &SelectPrevious {
14757                    replace_newest: true,
14758                },
14759                window,
14760                cx,
14761            )?,
14762        }
14763        Ok(())
14764    }
14765
14766    pub fn toggle_comments(
14767        &mut self,
14768        action: &ToggleComments,
14769        window: &mut Window,
14770        cx: &mut Context<Self>,
14771    ) {
14772        if self.read_only(cx) {
14773            return;
14774        }
14775        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14776        let text_layout_details = &self.text_layout_details(window);
14777        self.transact(window, cx, |this, window, cx| {
14778            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14779            let mut edits = Vec::new();
14780            let mut selection_edit_ranges = Vec::new();
14781            let mut last_toggled_row = None;
14782            let snapshot = this.buffer.read(cx).read(cx);
14783            let empty_str: Arc<str> = Arc::default();
14784            let mut suffixes_inserted = Vec::new();
14785            let ignore_indent = action.ignore_indent;
14786
14787            fn comment_prefix_range(
14788                snapshot: &MultiBufferSnapshot,
14789                row: MultiBufferRow,
14790                comment_prefix: &str,
14791                comment_prefix_whitespace: &str,
14792                ignore_indent: bool,
14793            ) -> Range<Point> {
14794                let indent_size = if ignore_indent {
14795                    0
14796                } else {
14797                    snapshot.indent_size_for_line(row).len
14798                };
14799
14800                let start = Point::new(row.0, indent_size);
14801
14802                let mut line_bytes = snapshot
14803                    .bytes_in_range(start..snapshot.max_point())
14804                    .flatten()
14805                    .copied();
14806
14807                // If this line currently begins with the line comment prefix, then record
14808                // the range containing the prefix.
14809                if line_bytes
14810                    .by_ref()
14811                    .take(comment_prefix.len())
14812                    .eq(comment_prefix.bytes())
14813                {
14814                    // Include any whitespace that matches the comment prefix.
14815                    let matching_whitespace_len = line_bytes
14816                        .zip(comment_prefix_whitespace.bytes())
14817                        .take_while(|(a, b)| a == b)
14818                        .count() as u32;
14819                    let end = Point::new(
14820                        start.row,
14821                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14822                    );
14823                    start..end
14824                } else {
14825                    start..start
14826                }
14827            }
14828
14829            fn comment_suffix_range(
14830                snapshot: &MultiBufferSnapshot,
14831                row: MultiBufferRow,
14832                comment_suffix: &str,
14833                comment_suffix_has_leading_space: bool,
14834            ) -> Range<Point> {
14835                let end = Point::new(row.0, snapshot.line_len(row));
14836                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14837
14838                let mut line_end_bytes = snapshot
14839                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14840                    .flatten()
14841                    .copied();
14842
14843                let leading_space_len = if suffix_start_column > 0
14844                    && line_end_bytes.next() == Some(b' ')
14845                    && comment_suffix_has_leading_space
14846                {
14847                    1
14848                } else {
14849                    0
14850                };
14851
14852                // If this line currently begins with the line comment prefix, then record
14853                // the range containing the prefix.
14854                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14855                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14856                    start..end
14857                } else {
14858                    end..end
14859                }
14860            }
14861
14862            // TODO: Handle selections that cross excerpts
14863            for selection in &mut selections {
14864                let start_column = snapshot
14865                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14866                    .len;
14867                let language = if let Some(language) =
14868                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14869                {
14870                    language
14871                } else {
14872                    continue;
14873                };
14874
14875                selection_edit_ranges.clear();
14876
14877                // If multiple selections contain a given row, avoid processing that
14878                // row more than once.
14879                let mut start_row = MultiBufferRow(selection.start.row);
14880                if last_toggled_row == Some(start_row) {
14881                    start_row = start_row.next_row();
14882                }
14883                let end_row =
14884                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14885                        MultiBufferRow(selection.end.row - 1)
14886                    } else {
14887                        MultiBufferRow(selection.end.row)
14888                    };
14889                last_toggled_row = Some(end_row);
14890
14891                if start_row > end_row {
14892                    continue;
14893                }
14894
14895                // If the language has line comments, toggle those.
14896                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14897
14898                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14899                if ignore_indent {
14900                    full_comment_prefixes = full_comment_prefixes
14901                        .into_iter()
14902                        .map(|s| Arc::from(s.trim_end()))
14903                        .collect();
14904                }
14905
14906                if !full_comment_prefixes.is_empty() {
14907                    let first_prefix = full_comment_prefixes
14908                        .first()
14909                        .expect("prefixes is non-empty");
14910                    let prefix_trimmed_lengths = full_comment_prefixes
14911                        .iter()
14912                        .map(|p| p.trim_end_matches(' ').len())
14913                        .collect::<SmallVec<[usize; 4]>>();
14914
14915                    let mut all_selection_lines_are_comments = true;
14916
14917                    for row in start_row.0..=end_row.0 {
14918                        let row = MultiBufferRow(row);
14919                        if start_row < end_row && snapshot.is_line_blank(row) {
14920                            continue;
14921                        }
14922
14923                        let prefix_range = full_comment_prefixes
14924                            .iter()
14925                            .zip(prefix_trimmed_lengths.iter().copied())
14926                            .map(|(prefix, trimmed_prefix_len)| {
14927                                comment_prefix_range(
14928                                    snapshot.deref(),
14929                                    row,
14930                                    &prefix[..trimmed_prefix_len],
14931                                    &prefix[trimmed_prefix_len..],
14932                                    ignore_indent,
14933                                )
14934                            })
14935                            .max_by_key(|range| range.end.column - range.start.column)
14936                            .expect("prefixes is non-empty");
14937
14938                        if prefix_range.is_empty() {
14939                            all_selection_lines_are_comments = false;
14940                        }
14941
14942                        selection_edit_ranges.push(prefix_range);
14943                    }
14944
14945                    if all_selection_lines_are_comments {
14946                        edits.extend(
14947                            selection_edit_ranges
14948                                .iter()
14949                                .cloned()
14950                                .map(|range| (range, empty_str.clone())),
14951                        );
14952                    } else {
14953                        let min_column = selection_edit_ranges
14954                            .iter()
14955                            .map(|range| range.start.column)
14956                            .min()
14957                            .unwrap_or(0);
14958                        edits.extend(selection_edit_ranges.iter().map(|range| {
14959                            let position = Point::new(range.start.row, min_column);
14960                            (position..position, first_prefix.clone())
14961                        }));
14962                    }
14963                } else if let Some(BlockCommentConfig {
14964                    start: full_comment_prefix,
14965                    end: comment_suffix,
14966                    ..
14967                }) = language.block_comment()
14968                {
14969                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14970                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14971                    let prefix_range = comment_prefix_range(
14972                        snapshot.deref(),
14973                        start_row,
14974                        comment_prefix,
14975                        comment_prefix_whitespace,
14976                        ignore_indent,
14977                    );
14978                    let suffix_range = comment_suffix_range(
14979                        snapshot.deref(),
14980                        end_row,
14981                        comment_suffix.trim_start_matches(' '),
14982                        comment_suffix.starts_with(' '),
14983                    );
14984
14985                    if prefix_range.is_empty() || suffix_range.is_empty() {
14986                        edits.push((
14987                            prefix_range.start..prefix_range.start,
14988                            full_comment_prefix.clone(),
14989                        ));
14990                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14991                        suffixes_inserted.push((end_row, comment_suffix.len()));
14992                    } else {
14993                        edits.push((prefix_range, empty_str.clone()));
14994                        edits.push((suffix_range, empty_str.clone()));
14995                    }
14996                } else {
14997                    continue;
14998                }
14999            }
15000
15001            drop(snapshot);
15002            this.buffer.update(cx, |buffer, cx| {
15003                buffer.edit(edits, None, cx);
15004            });
15005
15006            // Adjust selections so that they end before any comment suffixes that
15007            // were inserted.
15008            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15009            let mut selections = this.selections.all::<Point>(cx);
15010            let snapshot = this.buffer.read(cx).read(cx);
15011            for selection in &mut selections {
15012                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15013                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15014                        Ordering::Less => {
15015                            suffixes_inserted.next();
15016                            continue;
15017                        }
15018                        Ordering::Greater => break,
15019                        Ordering::Equal => {
15020                            if selection.end.column == snapshot.line_len(row) {
15021                                if selection.is_empty() {
15022                                    selection.start.column -= suffix_len as u32;
15023                                }
15024                                selection.end.column -= suffix_len as u32;
15025                            }
15026                            break;
15027                        }
15028                    }
15029                }
15030            }
15031
15032            drop(snapshot);
15033            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15034
15035            let selections = this.selections.all::<Point>(cx);
15036            let selections_on_single_row = selections.windows(2).all(|selections| {
15037                selections[0].start.row == selections[1].start.row
15038                    && selections[0].end.row == selections[1].end.row
15039                    && selections[0].start.row == selections[0].end.row
15040            });
15041            let selections_selecting = selections
15042                .iter()
15043                .any(|selection| selection.start != selection.end);
15044            let advance_downwards = action.advance_downwards
15045                && selections_on_single_row
15046                && !selections_selecting
15047                && !matches!(this.mode, EditorMode::SingleLine);
15048
15049            if advance_downwards {
15050                let snapshot = this.buffer.read(cx).snapshot(cx);
15051
15052                this.change_selections(Default::default(), window, cx, |s| {
15053                    s.move_cursors_with(|display_snapshot, display_point, _| {
15054                        let mut point = display_point.to_point(display_snapshot);
15055                        point.row += 1;
15056                        point = snapshot.clip_point(point, Bias::Left);
15057                        let display_point = point.to_display_point(display_snapshot);
15058                        let goal = SelectionGoal::HorizontalPosition(
15059                            display_snapshot
15060                                .x_for_display_point(display_point, text_layout_details)
15061                                .into(),
15062                        );
15063                        (display_point, goal)
15064                    })
15065                });
15066            }
15067        });
15068    }
15069
15070    pub fn select_enclosing_symbol(
15071        &mut self,
15072        _: &SelectEnclosingSymbol,
15073        window: &mut Window,
15074        cx: &mut Context<Self>,
15075    ) {
15076        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15077
15078        let buffer = self.buffer.read(cx).snapshot(cx);
15079        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15080
15081        fn update_selection(
15082            selection: &Selection<usize>,
15083            buffer_snap: &MultiBufferSnapshot,
15084        ) -> Option<Selection<usize>> {
15085            let cursor = selection.head();
15086            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15087            for symbol in symbols.iter().rev() {
15088                let start = symbol.range.start.to_offset(buffer_snap);
15089                let end = symbol.range.end.to_offset(buffer_snap);
15090                let new_range = start..end;
15091                if start < selection.start || end > selection.end {
15092                    return Some(Selection {
15093                        id: selection.id,
15094                        start: new_range.start,
15095                        end: new_range.end,
15096                        goal: SelectionGoal::None,
15097                        reversed: selection.reversed,
15098                    });
15099                }
15100            }
15101            None
15102        }
15103
15104        let mut selected_larger_symbol = false;
15105        let new_selections = old_selections
15106            .iter()
15107            .map(|selection| match update_selection(selection, &buffer) {
15108                Some(new_selection) => {
15109                    if new_selection.range() != selection.range() {
15110                        selected_larger_symbol = true;
15111                    }
15112                    new_selection
15113                }
15114                None => selection.clone(),
15115            })
15116            .collect::<Vec<_>>();
15117
15118        if selected_larger_symbol {
15119            self.change_selections(Default::default(), window, cx, |s| {
15120                s.select(new_selections);
15121            });
15122        }
15123    }
15124
15125    pub fn select_larger_syntax_node(
15126        &mut self,
15127        _: &SelectLargerSyntaxNode,
15128        window: &mut Window,
15129        cx: &mut Context<Self>,
15130    ) {
15131        let Some(visible_row_count) = self.visible_row_count() else {
15132            return;
15133        };
15134        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15135        if old_selections.is_empty() {
15136            return;
15137        }
15138
15139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15140
15141        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15142        let buffer = self.buffer.read(cx).snapshot(cx);
15143
15144        let mut selected_larger_node = false;
15145        let mut new_selections = old_selections
15146            .iter()
15147            .map(|selection| {
15148                let old_range = selection.start..selection.end;
15149
15150                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15151                    // manually select word at selection
15152                    if ["string_content", "inline"].contains(&node.kind()) {
15153                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15154                        // ignore if word is already selected
15155                        if !word_range.is_empty() && old_range != word_range {
15156                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15157                            // only select word if start and end point belongs to same word
15158                            if word_range == last_word_range {
15159                                selected_larger_node = true;
15160                                return Selection {
15161                                    id: selection.id,
15162                                    start: word_range.start,
15163                                    end: word_range.end,
15164                                    goal: SelectionGoal::None,
15165                                    reversed: selection.reversed,
15166                                };
15167                            }
15168                        }
15169                    }
15170                }
15171
15172                let mut new_range = old_range.clone();
15173                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15174                    new_range = range;
15175                    if !node.is_named() {
15176                        continue;
15177                    }
15178                    if !display_map.intersects_fold(new_range.start)
15179                        && !display_map.intersects_fold(new_range.end)
15180                    {
15181                        break;
15182                    }
15183                }
15184
15185                selected_larger_node |= new_range != old_range;
15186                Selection {
15187                    id: selection.id,
15188                    start: new_range.start,
15189                    end: new_range.end,
15190                    goal: SelectionGoal::None,
15191                    reversed: selection.reversed,
15192                }
15193            })
15194            .collect::<Vec<_>>();
15195
15196        if !selected_larger_node {
15197            return; // don't put this call in the history
15198        }
15199
15200        // scroll based on transformation done to the last selection created by the user
15201        let (last_old, last_new) = old_selections
15202            .last()
15203            .zip(new_selections.last().cloned())
15204            .expect("old_selections isn't empty");
15205
15206        // revert selection
15207        let is_selection_reversed = {
15208            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15209            new_selections.last_mut().expect("checked above").reversed =
15210                should_newest_selection_be_reversed;
15211            should_newest_selection_be_reversed
15212        };
15213
15214        if selected_larger_node {
15215            self.select_syntax_node_history.disable_clearing = true;
15216            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15217                s.select(new_selections.clone());
15218            });
15219            self.select_syntax_node_history.disable_clearing = false;
15220        }
15221
15222        let start_row = last_new.start.to_display_point(&display_map).row().0;
15223        let end_row = last_new.end.to_display_point(&display_map).row().0;
15224        let selection_height = end_row - start_row + 1;
15225        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15226
15227        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15228        let scroll_behavior = if fits_on_the_screen {
15229            self.request_autoscroll(Autoscroll::fit(), cx);
15230            SelectSyntaxNodeScrollBehavior::FitSelection
15231        } else if is_selection_reversed {
15232            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15233            SelectSyntaxNodeScrollBehavior::CursorTop
15234        } else {
15235            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15236            SelectSyntaxNodeScrollBehavior::CursorBottom
15237        };
15238
15239        self.select_syntax_node_history.push((
15240            old_selections,
15241            scroll_behavior,
15242            is_selection_reversed,
15243        ));
15244    }
15245
15246    pub fn select_smaller_syntax_node(
15247        &mut self,
15248        _: &SelectSmallerSyntaxNode,
15249        window: &mut Window,
15250        cx: &mut Context<Self>,
15251    ) {
15252        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15253
15254        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15255            self.select_syntax_node_history.pop()
15256        {
15257            if let Some(selection) = selections.last_mut() {
15258                selection.reversed = is_selection_reversed;
15259            }
15260
15261            self.select_syntax_node_history.disable_clearing = true;
15262            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15263                s.select(selections.to_vec());
15264            });
15265            self.select_syntax_node_history.disable_clearing = false;
15266
15267            match scroll_behavior {
15268                SelectSyntaxNodeScrollBehavior::CursorTop => {
15269                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15270                }
15271                SelectSyntaxNodeScrollBehavior::FitSelection => {
15272                    self.request_autoscroll(Autoscroll::fit(), cx);
15273                }
15274                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15275                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15276                }
15277            }
15278        }
15279    }
15280
15281    pub fn unwrap_syntax_node(
15282        &mut self,
15283        _: &UnwrapSyntaxNode,
15284        window: &mut Window,
15285        cx: &mut Context<Self>,
15286    ) {
15287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15288
15289        let buffer = self.buffer.read(cx).snapshot(cx);
15290        let selections = self
15291            .selections
15292            .all::<usize>(cx)
15293            .into_iter()
15294            // subtracting the offset requires sorting
15295            .sorted_by_key(|i| i.start);
15296
15297        let full_edits = selections
15298            .into_iter()
15299            .filter_map(|selection| {
15300                let child = if selection.is_empty()
15301                    && let Some((_, ancestor_range)) =
15302                        buffer.syntax_ancestor(selection.start..selection.end)
15303                {
15304                    ancestor_range
15305                } else {
15306                    selection.range()
15307                };
15308
15309                let mut parent = child.clone();
15310                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15311                    parent = ancestor_range;
15312                    if parent.start < child.start || parent.end > child.end {
15313                        break;
15314                    }
15315                }
15316
15317                if parent == child {
15318                    return None;
15319                }
15320                let text = buffer.text_for_range(child).collect::<String>();
15321                Some((selection.id, parent, text))
15322            })
15323            .collect::<Vec<_>>();
15324        if full_edits.is_empty() {
15325            return;
15326        }
15327
15328        self.transact(window, cx, |this, window, cx| {
15329            this.buffer.update(cx, |buffer, cx| {
15330                buffer.edit(
15331                    full_edits
15332                        .iter()
15333                        .map(|(_, p, t)| (p.clone(), t.clone()))
15334                        .collect::<Vec<_>>(),
15335                    None,
15336                    cx,
15337                );
15338            });
15339            this.change_selections(Default::default(), window, cx, |s| {
15340                let mut offset = 0;
15341                let mut selections = vec![];
15342                for (id, parent, text) in full_edits {
15343                    let start = parent.start - offset;
15344                    offset += parent.len() - text.len();
15345                    selections.push(Selection {
15346                        id,
15347                        start,
15348                        end: start + text.len(),
15349                        reversed: false,
15350                        goal: Default::default(),
15351                    });
15352                }
15353                s.select(selections);
15354            });
15355        });
15356    }
15357
15358    pub fn select_next_syntax_node(
15359        &mut self,
15360        _: &SelectNextSyntaxNode,
15361        window: &mut Window,
15362        cx: &mut Context<Self>,
15363    ) {
15364        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15365        if old_selections.is_empty() {
15366            return;
15367        }
15368
15369        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15370
15371        let buffer = self.buffer.read(cx).snapshot(cx);
15372        let mut selected_sibling = false;
15373
15374        let new_selections = old_selections
15375            .iter()
15376            .map(|selection| {
15377                let old_range = selection.start..selection.end;
15378
15379                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15380                    let new_range = node.byte_range();
15381                    selected_sibling = true;
15382                    Selection {
15383                        id: selection.id,
15384                        start: new_range.start,
15385                        end: new_range.end,
15386                        goal: SelectionGoal::None,
15387                        reversed: selection.reversed,
15388                    }
15389                } else {
15390                    selection.clone()
15391                }
15392            })
15393            .collect::<Vec<_>>();
15394
15395        if selected_sibling {
15396            self.change_selections(
15397                SelectionEffects::scroll(Autoscroll::fit()),
15398                window,
15399                cx,
15400                |s| {
15401                    s.select(new_selections);
15402                },
15403            );
15404        }
15405    }
15406
15407    pub fn select_prev_syntax_node(
15408        &mut self,
15409        _: &SelectPreviousSyntaxNode,
15410        window: &mut Window,
15411        cx: &mut Context<Self>,
15412    ) {
15413        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15414        if old_selections.is_empty() {
15415            return;
15416        }
15417
15418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15419
15420        let buffer = self.buffer.read(cx).snapshot(cx);
15421        let mut selected_sibling = false;
15422
15423        let new_selections = old_selections
15424            .iter()
15425            .map(|selection| {
15426                let old_range = selection.start..selection.end;
15427
15428                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15429                    let new_range = node.byte_range();
15430                    selected_sibling = true;
15431                    Selection {
15432                        id: selection.id,
15433                        start: new_range.start,
15434                        end: new_range.end,
15435                        goal: SelectionGoal::None,
15436                        reversed: selection.reversed,
15437                    }
15438                } else {
15439                    selection.clone()
15440                }
15441            })
15442            .collect::<Vec<_>>();
15443
15444        if selected_sibling {
15445            self.change_selections(
15446                SelectionEffects::scroll(Autoscroll::fit()),
15447                window,
15448                cx,
15449                |s| {
15450                    s.select(new_selections);
15451                },
15452            );
15453        }
15454    }
15455
15456    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15457        if !EditorSettings::get_global(cx).gutter.runnables {
15458            self.clear_tasks();
15459            return Task::ready(());
15460        }
15461        let project = self.project().map(Entity::downgrade);
15462        let task_sources = self.lsp_task_sources(cx);
15463        let multi_buffer = self.buffer.downgrade();
15464        cx.spawn_in(window, async move |editor, cx| {
15465            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15466            let Some(project) = project.and_then(|p| p.upgrade()) else {
15467                return;
15468            };
15469            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15470                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15471            }) else {
15472                return;
15473            };
15474
15475            let hide_runnables = project
15476                .update(cx, |project, _| project.is_via_collab())
15477                .unwrap_or(true);
15478            if hide_runnables {
15479                return;
15480            }
15481            let new_rows =
15482                cx.background_spawn({
15483                    let snapshot = display_snapshot.clone();
15484                    async move {
15485                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15486                    }
15487                })
15488                    .await;
15489            let Ok(lsp_tasks) =
15490                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15491            else {
15492                return;
15493            };
15494            let lsp_tasks = lsp_tasks.await;
15495
15496            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15497                lsp_tasks
15498                    .into_iter()
15499                    .flat_map(|(kind, tasks)| {
15500                        tasks.into_iter().filter_map(move |(location, task)| {
15501                            Some((kind.clone(), location?, task))
15502                        })
15503                    })
15504                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15505                        let buffer = location.target.buffer;
15506                        let buffer_snapshot = buffer.read(cx).snapshot();
15507                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15508                            |(excerpt_id, snapshot, _)| {
15509                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15510                                    display_snapshot
15511                                        .buffer_snapshot
15512                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15513                                } else {
15514                                    None
15515                                }
15516                            },
15517                        );
15518                        if let Some(offset) = offset {
15519                            let task_buffer_range =
15520                                location.target.range.to_point(&buffer_snapshot);
15521                            let context_buffer_range =
15522                                task_buffer_range.to_offset(&buffer_snapshot);
15523                            let context_range = BufferOffset(context_buffer_range.start)
15524                                ..BufferOffset(context_buffer_range.end);
15525
15526                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15527                                .or_insert_with(|| RunnableTasks {
15528                                    templates: Vec::new(),
15529                                    offset,
15530                                    column: task_buffer_range.start.column,
15531                                    extra_variables: HashMap::default(),
15532                                    context_range,
15533                                })
15534                                .templates
15535                                .push((kind, task.original_task().clone()));
15536                        }
15537
15538                        acc
15539                    })
15540            }) else {
15541                return;
15542            };
15543
15544            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15545                buffer.language_settings(cx).tasks.prefer_lsp
15546            }) else {
15547                return;
15548            };
15549
15550            let rows = Self::runnable_rows(
15551                project,
15552                display_snapshot,
15553                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15554                new_rows,
15555                cx.clone(),
15556            )
15557            .await;
15558            editor
15559                .update(cx, |editor, _| {
15560                    editor.clear_tasks();
15561                    for (key, mut value) in rows {
15562                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15563                            value.templates.extend(lsp_tasks.templates);
15564                        }
15565
15566                        editor.insert_tasks(key, value);
15567                    }
15568                    for (key, value) in lsp_tasks_by_rows {
15569                        editor.insert_tasks(key, value);
15570                    }
15571                })
15572                .ok();
15573        })
15574    }
15575    fn fetch_runnable_ranges(
15576        snapshot: &DisplaySnapshot,
15577        range: Range<Anchor>,
15578    ) -> Vec<language::RunnableRange> {
15579        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15580    }
15581
15582    fn runnable_rows(
15583        project: Entity<Project>,
15584        snapshot: DisplaySnapshot,
15585        prefer_lsp: bool,
15586        runnable_ranges: Vec<RunnableRange>,
15587        cx: AsyncWindowContext,
15588    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15589        cx.spawn(async move |cx| {
15590            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15591            for mut runnable in runnable_ranges {
15592                let Some(tasks) = cx
15593                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15594                    .ok()
15595                else {
15596                    continue;
15597                };
15598                let mut tasks = tasks.await;
15599
15600                if prefer_lsp {
15601                    tasks.retain(|(task_kind, _)| {
15602                        !matches!(task_kind, TaskSourceKind::Language { .. })
15603                    });
15604                }
15605                if tasks.is_empty() {
15606                    continue;
15607                }
15608
15609                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15610                let Some(row) = snapshot
15611                    .buffer_snapshot
15612                    .buffer_line_for_row(MultiBufferRow(point.row))
15613                    .map(|(_, range)| range.start.row)
15614                else {
15615                    continue;
15616                };
15617
15618                let context_range =
15619                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15620                runnable_rows.push((
15621                    (runnable.buffer_id, row),
15622                    RunnableTasks {
15623                        templates: tasks,
15624                        offset: snapshot
15625                            .buffer_snapshot
15626                            .anchor_before(runnable.run_range.start),
15627                        context_range,
15628                        column: point.column,
15629                        extra_variables: runnable.extra_captures,
15630                    },
15631                ));
15632            }
15633            runnable_rows
15634        })
15635    }
15636
15637    fn templates_with_tags(
15638        project: &Entity<Project>,
15639        runnable: &mut Runnable,
15640        cx: &mut App,
15641    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15642        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15643            let (worktree_id, file) = project
15644                .buffer_for_id(runnable.buffer, cx)
15645                .and_then(|buffer| buffer.read(cx).file())
15646                .map(|file| (file.worktree_id(cx), file.clone()))
15647                .unzip();
15648
15649            (
15650                project.task_store().read(cx).task_inventory().cloned(),
15651                worktree_id,
15652                file,
15653            )
15654        });
15655
15656        let tags = mem::take(&mut runnable.tags);
15657        let language = runnable.language.clone();
15658        cx.spawn(async move |cx| {
15659            let mut templates_with_tags = Vec::new();
15660            if let Some(inventory) = inventory {
15661                for RunnableTag(tag) in tags {
15662                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15663                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15664                    }) else {
15665                        return templates_with_tags;
15666                    };
15667                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15668                        move |(_, template)| {
15669                            template.tags.iter().any(|source_tag| source_tag == &tag)
15670                        },
15671                    ));
15672                }
15673            }
15674            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15675
15676            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15677                // Strongest source wins; if we have worktree tag binding, prefer that to
15678                // global and language bindings;
15679                // if we have a global binding, prefer that to language binding.
15680                let first_mismatch = templates_with_tags
15681                    .iter()
15682                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15683                if let Some(index) = first_mismatch {
15684                    templates_with_tags.truncate(index);
15685                }
15686            }
15687
15688            templates_with_tags
15689        })
15690    }
15691
15692    pub fn move_to_enclosing_bracket(
15693        &mut self,
15694        _: &MoveToEnclosingBracket,
15695        window: &mut Window,
15696        cx: &mut Context<Self>,
15697    ) {
15698        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15699        self.change_selections(Default::default(), window, cx, |s| {
15700            s.move_offsets_with(|snapshot, selection| {
15701                let Some(enclosing_bracket_ranges) =
15702                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15703                else {
15704                    return;
15705                };
15706
15707                let mut best_length = usize::MAX;
15708                let mut best_inside = false;
15709                let mut best_in_bracket_range = false;
15710                let mut best_destination = None;
15711                for (open, close) in enclosing_bracket_ranges {
15712                    let close = close.to_inclusive();
15713                    let length = close.end() - open.start;
15714                    let inside = selection.start >= open.end && selection.end <= *close.start();
15715                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15716                        || close.contains(&selection.head());
15717
15718                    // If best is next to a bracket and current isn't, skip
15719                    if !in_bracket_range && best_in_bracket_range {
15720                        continue;
15721                    }
15722
15723                    // Prefer smaller lengths unless best is inside and current isn't
15724                    if length > best_length && (best_inside || !inside) {
15725                        continue;
15726                    }
15727
15728                    best_length = length;
15729                    best_inside = inside;
15730                    best_in_bracket_range = in_bracket_range;
15731                    best_destination = Some(
15732                        if close.contains(&selection.start) && close.contains(&selection.end) {
15733                            if inside { open.end } else { open.start }
15734                        } else if inside {
15735                            *close.start()
15736                        } else {
15737                            *close.end()
15738                        },
15739                    );
15740                }
15741
15742                if let Some(destination) = best_destination {
15743                    selection.collapse_to(destination, SelectionGoal::None);
15744                }
15745            })
15746        });
15747    }
15748
15749    pub fn undo_selection(
15750        &mut self,
15751        _: &UndoSelection,
15752        window: &mut Window,
15753        cx: &mut Context<Self>,
15754    ) {
15755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15756        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15757            self.selection_history.mode = SelectionHistoryMode::Undoing;
15758            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15759                this.end_selection(window, cx);
15760                this.change_selections(
15761                    SelectionEffects::scroll(Autoscroll::newest()),
15762                    window,
15763                    cx,
15764                    |s| s.select_anchors(entry.selections.to_vec()),
15765                );
15766            });
15767            self.selection_history.mode = SelectionHistoryMode::Normal;
15768
15769            self.select_next_state = entry.select_next_state;
15770            self.select_prev_state = entry.select_prev_state;
15771            self.add_selections_state = entry.add_selections_state;
15772        }
15773    }
15774
15775    pub fn redo_selection(
15776        &mut self,
15777        _: &RedoSelection,
15778        window: &mut Window,
15779        cx: &mut Context<Self>,
15780    ) {
15781        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15782        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15783            self.selection_history.mode = SelectionHistoryMode::Redoing;
15784            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15785                this.end_selection(window, cx);
15786                this.change_selections(
15787                    SelectionEffects::scroll(Autoscroll::newest()),
15788                    window,
15789                    cx,
15790                    |s| s.select_anchors(entry.selections.to_vec()),
15791                );
15792            });
15793            self.selection_history.mode = SelectionHistoryMode::Normal;
15794
15795            self.select_next_state = entry.select_next_state;
15796            self.select_prev_state = entry.select_prev_state;
15797            self.add_selections_state = entry.add_selections_state;
15798        }
15799    }
15800
15801    pub fn expand_excerpts(
15802        &mut self,
15803        action: &ExpandExcerpts,
15804        _: &mut Window,
15805        cx: &mut Context<Self>,
15806    ) {
15807        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15808    }
15809
15810    pub fn expand_excerpts_down(
15811        &mut self,
15812        action: &ExpandExcerptsDown,
15813        _: &mut Window,
15814        cx: &mut Context<Self>,
15815    ) {
15816        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15817    }
15818
15819    pub fn expand_excerpts_up(
15820        &mut self,
15821        action: &ExpandExcerptsUp,
15822        _: &mut Window,
15823        cx: &mut Context<Self>,
15824    ) {
15825        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15826    }
15827
15828    pub fn expand_excerpts_for_direction(
15829        &mut self,
15830        lines: u32,
15831        direction: ExpandExcerptDirection,
15832
15833        cx: &mut Context<Self>,
15834    ) {
15835        let selections = self.selections.disjoint_anchors_arc();
15836
15837        let lines = if lines == 0 {
15838            EditorSettings::get_global(cx).expand_excerpt_lines
15839        } else {
15840            lines
15841        };
15842
15843        self.buffer.update(cx, |buffer, cx| {
15844            let snapshot = buffer.snapshot(cx);
15845            let mut excerpt_ids = selections
15846                .iter()
15847                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15848                .collect::<Vec<_>>();
15849            excerpt_ids.sort();
15850            excerpt_ids.dedup();
15851            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15852        })
15853    }
15854
15855    pub fn expand_excerpt(
15856        &mut self,
15857        excerpt: ExcerptId,
15858        direction: ExpandExcerptDirection,
15859        window: &mut Window,
15860        cx: &mut Context<Self>,
15861    ) {
15862        let current_scroll_position = self.scroll_position(cx);
15863        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15864        let mut should_scroll_up = false;
15865
15866        if direction == ExpandExcerptDirection::Down {
15867            let multi_buffer = self.buffer.read(cx);
15868            let snapshot = multi_buffer.snapshot(cx);
15869            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15870                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15871                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15872            {
15873                let buffer_snapshot = buffer.read(cx).snapshot();
15874                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15875                let last_row = buffer_snapshot.max_point().row;
15876                let lines_below = last_row.saturating_sub(excerpt_end_row);
15877                should_scroll_up = lines_below >= lines_to_expand;
15878            }
15879        }
15880
15881        self.buffer.update(cx, |buffer, cx| {
15882            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15883        });
15884
15885        if should_scroll_up {
15886            let new_scroll_position =
15887                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15888            self.set_scroll_position(new_scroll_position, window, cx);
15889        }
15890    }
15891
15892    pub fn go_to_singleton_buffer_point(
15893        &mut self,
15894        point: Point,
15895        window: &mut Window,
15896        cx: &mut Context<Self>,
15897    ) {
15898        self.go_to_singleton_buffer_range(point..point, window, cx);
15899    }
15900
15901    pub fn go_to_singleton_buffer_range(
15902        &mut self,
15903        range: Range<Point>,
15904        window: &mut Window,
15905        cx: &mut Context<Self>,
15906    ) {
15907        let multibuffer = self.buffer().read(cx);
15908        let Some(buffer) = multibuffer.as_singleton() else {
15909            return;
15910        };
15911        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15912            return;
15913        };
15914        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15915            return;
15916        };
15917        self.change_selections(
15918            SelectionEffects::default().nav_history(true),
15919            window,
15920            cx,
15921            |s| s.select_anchor_ranges([start..end]),
15922        );
15923    }
15924
15925    pub fn go_to_diagnostic(
15926        &mut self,
15927        action: &GoToDiagnostic,
15928        window: &mut Window,
15929        cx: &mut Context<Self>,
15930    ) {
15931        if !self.diagnostics_enabled() {
15932            return;
15933        }
15934        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15935        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15936    }
15937
15938    pub fn go_to_prev_diagnostic(
15939        &mut self,
15940        action: &GoToPreviousDiagnostic,
15941        window: &mut Window,
15942        cx: &mut Context<Self>,
15943    ) {
15944        if !self.diagnostics_enabled() {
15945            return;
15946        }
15947        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15948        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15949    }
15950
15951    pub fn go_to_diagnostic_impl(
15952        &mut self,
15953        direction: Direction,
15954        severity: GoToDiagnosticSeverityFilter,
15955        window: &mut Window,
15956        cx: &mut Context<Self>,
15957    ) {
15958        let buffer = self.buffer.read(cx).snapshot(cx);
15959        let selection = self.selections.newest::<usize>(cx);
15960
15961        let mut active_group_id = None;
15962        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15963            && active_group.active_range.start.to_offset(&buffer) == selection.start
15964        {
15965            active_group_id = Some(active_group.group_id);
15966        }
15967
15968        fn filtered<'a>(
15969            snapshot: EditorSnapshot,
15970            severity: GoToDiagnosticSeverityFilter,
15971            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
15972        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
15973            diagnostics
15974                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15975                .filter(|entry| entry.range.start != entry.range.end)
15976                .filter(|entry| !entry.diagnostic.is_unnecessary)
15977                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15978        }
15979
15980        let snapshot = self.snapshot(window, cx);
15981        let before = filtered(
15982            snapshot.clone(),
15983            severity,
15984            buffer
15985                .diagnostics_in_range(0..selection.start)
15986                .filter(|entry| entry.range.start <= selection.start),
15987        );
15988        let after = filtered(
15989            snapshot,
15990            severity,
15991            buffer
15992                .diagnostics_in_range(selection.start..buffer.len())
15993                .filter(|entry| entry.range.start >= selection.start),
15994        );
15995
15996        let mut found: Option<DiagnosticEntryRef<usize>> = None;
15997        if direction == Direction::Prev {
15998            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15999            {
16000                for diagnostic in prev_diagnostics.into_iter().rev() {
16001                    if diagnostic.range.start != selection.start
16002                        || active_group_id
16003                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16004                    {
16005                        found = Some(diagnostic);
16006                        break 'outer;
16007                    }
16008                }
16009            }
16010        } else {
16011            for diagnostic in after.chain(before) {
16012                if diagnostic.range.start != selection.start
16013                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16014                {
16015                    found = Some(diagnostic);
16016                    break;
16017                }
16018            }
16019        }
16020        let Some(next_diagnostic) = found else {
16021            return;
16022        };
16023
16024        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16025        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16026            return;
16027        };
16028        self.change_selections(Default::default(), window, cx, |s| {
16029            s.select_ranges(vec![
16030                next_diagnostic.range.start..next_diagnostic.range.start,
16031            ])
16032        });
16033        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16034        self.refresh_edit_prediction(false, true, window, cx);
16035    }
16036
16037    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16038        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16039        let snapshot = self.snapshot(window, cx);
16040        let selection = self.selections.newest::<Point>(cx);
16041        self.go_to_hunk_before_or_after_position(
16042            &snapshot,
16043            selection.head(),
16044            Direction::Next,
16045            window,
16046            cx,
16047        );
16048    }
16049
16050    pub fn go_to_hunk_before_or_after_position(
16051        &mut self,
16052        snapshot: &EditorSnapshot,
16053        position: Point,
16054        direction: Direction,
16055        window: &mut Window,
16056        cx: &mut Context<Editor>,
16057    ) {
16058        let row = if direction == Direction::Next {
16059            self.hunk_after_position(snapshot, position)
16060                .map(|hunk| hunk.row_range.start)
16061        } else {
16062            self.hunk_before_position(snapshot, position)
16063        };
16064
16065        if let Some(row) = row {
16066            let destination = Point::new(row.0, 0);
16067            let autoscroll = Autoscroll::center();
16068
16069            self.unfold_ranges(&[destination..destination], false, false, cx);
16070            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16071                s.select_ranges([destination..destination]);
16072            });
16073        }
16074    }
16075
16076    fn hunk_after_position(
16077        &mut self,
16078        snapshot: &EditorSnapshot,
16079        position: Point,
16080    ) -> Option<MultiBufferDiffHunk> {
16081        snapshot
16082            .buffer_snapshot
16083            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16084            .find(|hunk| hunk.row_range.start.0 > position.row)
16085            .or_else(|| {
16086                snapshot
16087                    .buffer_snapshot
16088                    .diff_hunks_in_range(Point::zero()..position)
16089                    .find(|hunk| hunk.row_range.end.0 < position.row)
16090            })
16091    }
16092
16093    fn go_to_prev_hunk(
16094        &mut self,
16095        _: &GoToPreviousHunk,
16096        window: &mut Window,
16097        cx: &mut Context<Self>,
16098    ) {
16099        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16100        let snapshot = self.snapshot(window, cx);
16101        let selection = self.selections.newest::<Point>(cx);
16102        self.go_to_hunk_before_or_after_position(
16103            &snapshot,
16104            selection.head(),
16105            Direction::Prev,
16106            window,
16107            cx,
16108        );
16109    }
16110
16111    fn hunk_before_position(
16112        &mut self,
16113        snapshot: &EditorSnapshot,
16114        position: Point,
16115    ) -> Option<MultiBufferRow> {
16116        snapshot
16117            .buffer_snapshot
16118            .diff_hunk_before(position)
16119            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
16120    }
16121
16122    fn go_to_next_change(
16123        &mut self,
16124        _: &GoToNextChange,
16125        window: &mut Window,
16126        cx: &mut Context<Self>,
16127    ) {
16128        if let Some(selections) = self
16129            .change_list
16130            .next_change(1, Direction::Next)
16131            .map(|s| s.to_vec())
16132        {
16133            self.change_selections(Default::default(), window, cx, |s| {
16134                let map = s.display_map();
16135                s.select_display_ranges(selections.iter().map(|a| {
16136                    let point = a.to_display_point(&map);
16137                    point..point
16138                }))
16139            })
16140        }
16141    }
16142
16143    fn go_to_previous_change(
16144        &mut self,
16145        _: &GoToPreviousChange,
16146        window: &mut Window,
16147        cx: &mut Context<Self>,
16148    ) {
16149        if let Some(selections) = self
16150            .change_list
16151            .next_change(1, Direction::Prev)
16152            .map(|s| s.to_vec())
16153        {
16154            self.change_selections(Default::default(), window, cx, |s| {
16155                let map = s.display_map();
16156                s.select_display_ranges(selections.iter().map(|a| {
16157                    let point = a.to_display_point(&map);
16158                    point..point
16159                }))
16160            })
16161        }
16162    }
16163
16164    pub fn go_to_next_document_highlight(
16165        &mut self,
16166        _: &GoToNextDocumentHighlight,
16167        window: &mut Window,
16168        cx: &mut Context<Self>,
16169    ) {
16170        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16171    }
16172
16173    pub fn go_to_prev_document_highlight(
16174        &mut self,
16175        _: &GoToPreviousDocumentHighlight,
16176        window: &mut Window,
16177        cx: &mut Context<Self>,
16178    ) {
16179        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16180    }
16181
16182    pub fn go_to_document_highlight_before_or_after_position(
16183        &mut self,
16184        direction: Direction,
16185        window: &mut Window,
16186        cx: &mut Context<Editor>,
16187    ) {
16188        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16189        let snapshot = self.snapshot(window, cx);
16190        let buffer = &snapshot.buffer_snapshot;
16191        let position = self.selections.newest::<Point>(cx).head();
16192        let anchor_position = buffer.anchor_after(position);
16193
16194        // Get all document highlights (both read and write)
16195        let mut all_highlights = Vec::new();
16196
16197        if let Some((_, read_highlights)) = self
16198            .background_highlights
16199            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16200        {
16201            all_highlights.extend(read_highlights.iter());
16202        }
16203
16204        if let Some((_, write_highlights)) = self
16205            .background_highlights
16206            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16207        {
16208            all_highlights.extend(write_highlights.iter());
16209        }
16210
16211        if all_highlights.is_empty() {
16212            return;
16213        }
16214
16215        // Sort highlights by position
16216        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16217
16218        let target_highlight = match direction {
16219            Direction::Next => {
16220                // Find the first highlight after the current position
16221                all_highlights
16222                    .iter()
16223                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16224            }
16225            Direction::Prev => {
16226                // Find the last highlight before the current position
16227                all_highlights
16228                    .iter()
16229                    .rev()
16230                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16231            }
16232        };
16233
16234        if let Some(highlight) = target_highlight {
16235            let destination = highlight.start.to_point(buffer);
16236            let autoscroll = Autoscroll::center();
16237
16238            self.unfold_ranges(&[destination..destination], false, false, cx);
16239            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16240                s.select_ranges([destination..destination]);
16241            });
16242        }
16243    }
16244
16245    fn go_to_line<T: 'static>(
16246        &mut self,
16247        position: Anchor,
16248        highlight_color: Option<Hsla>,
16249        window: &mut Window,
16250        cx: &mut Context<Self>,
16251    ) {
16252        let snapshot = self.snapshot(window, cx).display_snapshot;
16253        let position = position.to_point(&snapshot.buffer_snapshot);
16254        let start = snapshot
16255            .buffer_snapshot
16256            .clip_point(Point::new(position.row, 0), Bias::Left);
16257        let end = start + Point::new(1, 0);
16258        let start = snapshot.buffer_snapshot.anchor_before(start);
16259        let end = snapshot.buffer_snapshot.anchor_before(end);
16260
16261        self.highlight_rows::<T>(
16262            start..end,
16263            highlight_color
16264                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16265            Default::default(),
16266            cx,
16267        );
16268
16269        if self.buffer.read(cx).is_singleton() {
16270            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16271        }
16272    }
16273
16274    pub fn go_to_definition(
16275        &mut self,
16276        _: &GoToDefinition,
16277        window: &mut Window,
16278        cx: &mut Context<Self>,
16279    ) -> Task<Result<Navigated>> {
16280        let definition =
16281            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16282        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16283        cx.spawn_in(window, async move |editor, cx| {
16284            if definition.await? == Navigated::Yes {
16285                return Ok(Navigated::Yes);
16286            }
16287            match fallback_strategy {
16288                GoToDefinitionFallback::None => Ok(Navigated::No),
16289                GoToDefinitionFallback::FindAllReferences => {
16290                    match editor.update_in(cx, |editor, window, cx| {
16291                        editor.find_all_references(&FindAllReferences, window, cx)
16292                    })? {
16293                        Some(references) => references.await,
16294                        None => Ok(Navigated::No),
16295                    }
16296                }
16297            }
16298        })
16299    }
16300
16301    pub fn go_to_declaration(
16302        &mut self,
16303        _: &GoToDeclaration,
16304        window: &mut Window,
16305        cx: &mut Context<Self>,
16306    ) -> Task<Result<Navigated>> {
16307        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16308    }
16309
16310    pub fn go_to_declaration_split(
16311        &mut self,
16312        _: &GoToDeclaration,
16313        window: &mut Window,
16314        cx: &mut Context<Self>,
16315    ) -> Task<Result<Navigated>> {
16316        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16317    }
16318
16319    pub fn go_to_implementation(
16320        &mut self,
16321        _: &GoToImplementation,
16322        window: &mut Window,
16323        cx: &mut Context<Self>,
16324    ) -> Task<Result<Navigated>> {
16325        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16326    }
16327
16328    pub fn go_to_implementation_split(
16329        &mut self,
16330        _: &GoToImplementationSplit,
16331        window: &mut Window,
16332        cx: &mut Context<Self>,
16333    ) -> Task<Result<Navigated>> {
16334        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16335    }
16336
16337    pub fn go_to_type_definition(
16338        &mut self,
16339        _: &GoToTypeDefinition,
16340        window: &mut Window,
16341        cx: &mut Context<Self>,
16342    ) -> Task<Result<Navigated>> {
16343        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16344    }
16345
16346    pub fn go_to_definition_split(
16347        &mut self,
16348        _: &GoToDefinitionSplit,
16349        window: &mut Window,
16350        cx: &mut Context<Self>,
16351    ) -> Task<Result<Navigated>> {
16352        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16353    }
16354
16355    pub fn go_to_type_definition_split(
16356        &mut self,
16357        _: &GoToTypeDefinitionSplit,
16358        window: &mut Window,
16359        cx: &mut Context<Self>,
16360    ) -> Task<Result<Navigated>> {
16361        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16362    }
16363
16364    fn go_to_definition_of_kind(
16365        &mut self,
16366        kind: GotoDefinitionKind,
16367        split: bool,
16368        window: &mut Window,
16369        cx: &mut Context<Self>,
16370    ) -> Task<Result<Navigated>> {
16371        let Some(provider) = self.semantics_provider.clone() else {
16372            return Task::ready(Ok(Navigated::No));
16373        };
16374        let head = self.selections.newest::<usize>(cx).head();
16375        let buffer = self.buffer.read(cx);
16376        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16377            return Task::ready(Ok(Navigated::No));
16378        };
16379        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16380            return Task::ready(Ok(Navigated::No));
16381        };
16382
16383        cx.spawn_in(window, async move |editor, cx| {
16384            let Some(definitions) = definitions.await? else {
16385                return Ok(Navigated::No);
16386            };
16387            let navigated = editor
16388                .update_in(cx, |editor, window, cx| {
16389                    editor.navigate_to_hover_links(
16390                        Some(kind),
16391                        definitions
16392                            .into_iter()
16393                            .filter(|location| {
16394                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16395                            })
16396                            .map(HoverLink::Text)
16397                            .collect::<Vec<_>>(),
16398                        split,
16399                        window,
16400                        cx,
16401                    )
16402                })?
16403                .await?;
16404            anyhow::Ok(navigated)
16405        })
16406    }
16407
16408    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16409        let selection = self.selections.newest_anchor();
16410        let head = selection.head();
16411        let tail = selection.tail();
16412
16413        let Some((buffer, start_position)) =
16414            self.buffer.read(cx).text_anchor_for_position(head, cx)
16415        else {
16416            return;
16417        };
16418
16419        let end_position = if head != tail {
16420            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16421                return;
16422            };
16423            Some(pos)
16424        } else {
16425            None
16426        };
16427
16428        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16429            let url = if let Some(end_pos) = end_position {
16430                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16431            } else {
16432                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16433            };
16434
16435            if let Some(url) = url {
16436                cx.update(|window, cx| {
16437                    if parse_zed_link(&url, cx).is_some() {
16438                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16439                    } else {
16440                        cx.open_url(&url);
16441                    }
16442                })?;
16443            }
16444
16445            anyhow::Ok(())
16446        });
16447
16448        url_finder.detach();
16449    }
16450
16451    pub fn open_selected_filename(
16452        &mut self,
16453        _: &OpenSelectedFilename,
16454        window: &mut Window,
16455        cx: &mut Context<Self>,
16456    ) {
16457        let Some(workspace) = self.workspace() else {
16458            return;
16459        };
16460
16461        let position = self.selections.newest_anchor().head();
16462
16463        let Some((buffer, buffer_position)) =
16464            self.buffer.read(cx).text_anchor_for_position(position, cx)
16465        else {
16466            return;
16467        };
16468
16469        let project = self.project.clone();
16470
16471        cx.spawn_in(window, async move |_, cx| {
16472            let result = find_file(&buffer, project, buffer_position, cx).await;
16473
16474            if let Some((_, path)) = result {
16475                workspace
16476                    .update_in(cx, |workspace, window, cx| {
16477                        workspace.open_resolved_path(path, window, cx)
16478                    })?
16479                    .await?;
16480            }
16481            anyhow::Ok(())
16482        })
16483        .detach();
16484    }
16485
16486    pub(crate) fn navigate_to_hover_links(
16487        &mut self,
16488        kind: Option<GotoDefinitionKind>,
16489        definitions: Vec<HoverLink>,
16490        split: bool,
16491        window: &mut Window,
16492        cx: &mut Context<Editor>,
16493    ) -> Task<Result<Navigated>> {
16494        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16495        let mut first_url_or_file = None;
16496        let definitions: Vec<_> = definitions
16497            .into_iter()
16498            .filter_map(|def| match def {
16499                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16500                HoverLink::InlayHint(lsp_location, server_id) => {
16501                    let computation =
16502                        self.compute_target_location(lsp_location, server_id, window, cx);
16503                    Some(cx.background_spawn(computation))
16504                }
16505                HoverLink::Url(url) => {
16506                    first_url_or_file = Some(Either::Left(url));
16507                    None
16508                }
16509                HoverLink::File(path) => {
16510                    first_url_or_file = Some(Either::Right(path));
16511                    None
16512                }
16513            })
16514            .collect();
16515
16516        let workspace = self.workspace();
16517
16518        cx.spawn_in(window, async move |editor, cx| {
16519            let locations: Vec<Location> = future::join_all(definitions)
16520                .await
16521                .into_iter()
16522                .filter_map(|location| location.transpose())
16523                .collect::<Result<_>>()
16524                .context("location tasks")?;
16525            let mut locations = cx.update(|_, cx| {
16526                locations
16527                    .into_iter()
16528                    .map(|location| {
16529                        let buffer = location.buffer.read(cx);
16530                        (location.buffer, location.range.to_point(buffer))
16531                    })
16532                    .into_group_map()
16533            })?;
16534            let mut num_locations = 0;
16535            for ranges in locations.values_mut() {
16536                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16537                ranges.dedup();
16538                num_locations += ranges.len();
16539            }
16540
16541            if num_locations > 1 {
16542                let Some(workspace) = workspace else {
16543                    return Ok(Navigated::No);
16544                };
16545
16546                let tab_kind = match kind {
16547                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16548                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16549                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16550                    Some(GotoDefinitionKind::Type) => "Types",
16551                };
16552                let title = editor
16553                    .update_in(cx, |_, _, cx| {
16554                        let target = locations
16555                            .iter()
16556                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16557                            .map(|(buffer, location)| {
16558                                buffer
16559                                    .read(cx)
16560                                    .text_for_range(location.clone())
16561                                    .collect::<String>()
16562                            })
16563                            .filter(|text| !text.contains('\n'))
16564                            .unique()
16565                            .take(3)
16566                            .join(", ");
16567                        if target.is_empty() {
16568                            tab_kind.to_owned()
16569                        } else {
16570                            format!("{tab_kind} for {target}")
16571                        }
16572                    })
16573                    .context("buffer title")?;
16574
16575                let opened = workspace
16576                    .update_in(cx, |workspace, window, cx| {
16577                        Self::open_locations_in_multibuffer(
16578                            workspace,
16579                            locations,
16580                            title,
16581                            split,
16582                            MultibufferSelectionMode::First,
16583                            window,
16584                            cx,
16585                        )
16586                    })
16587                    .is_ok();
16588
16589                anyhow::Ok(Navigated::from_bool(opened))
16590            } else if num_locations == 0 {
16591                // If there is one url or file, open it directly
16592                match first_url_or_file {
16593                    Some(Either::Left(url)) => {
16594                        cx.update(|_, cx| cx.open_url(&url))?;
16595                        Ok(Navigated::Yes)
16596                    }
16597                    Some(Either::Right(path)) => {
16598                        let Some(workspace) = workspace else {
16599                            return Ok(Navigated::No);
16600                        };
16601
16602                        workspace
16603                            .update_in(cx, |workspace, window, cx| {
16604                                workspace.open_resolved_path(path, window, cx)
16605                            })?
16606                            .await?;
16607                        Ok(Navigated::Yes)
16608                    }
16609                    None => Ok(Navigated::No),
16610                }
16611            } else {
16612                let Some(workspace) = workspace else {
16613                    return Ok(Navigated::No);
16614                };
16615
16616                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16617                let target_range = target_ranges.first().unwrap().clone();
16618
16619                editor.update_in(cx, |editor, window, cx| {
16620                    let range = target_range.to_point(target_buffer.read(cx));
16621                    let range = editor.range_for_match(&range);
16622                    let range = collapse_multiline_range(range);
16623
16624                    if !split
16625                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16626                    {
16627                        editor.go_to_singleton_buffer_range(range, window, cx);
16628                    } else {
16629                        let pane = workspace.read(cx).active_pane().clone();
16630                        window.defer(cx, move |window, cx| {
16631                            let target_editor: Entity<Self> =
16632                                workspace.update(cx, |workspace, cx| {
16633                                    let pane = if split {
16634                                        workspace.adjacent_pane(window, cx)
16635                                    } else {
16636                                        workspace.active_pane().clone()
16637                                    };
16638
16639                                    workspace.open_project_item(
16640                                        pane,
16641                                        target_buffer.clone(),
16642                                        true,
16643                                        true,
16644                                        window,
16645                                        cx,
16646                                    )
16647                                });
16648                            target_editor.update(cx, |target_editor, cx| {
16649                                // When selecting a definition in a different buffer, disable the nav history
16650                                // to avoid creating a history entry at the previous cursor location.
16651                                pane.update(cx, |pane, _| pane.disable_history());
16652                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16653                                pane.update(cx, |pane, _| pane.enable_history());
16654                            });
16655                        });
16656                    }
16657                    Navigated::Yes
16658                })
16659            }
16660        })
16661    }
16662
16663    fn compute_target_location(
16664        &self,
16665        lsp_location: lsp::Location,
16666        server_id: LanguageServerId,
16667        window: &mut Window,
16668        cx: &mut Context<Self>,
16669    ) -> Task<anyhow::Result<Option<Location>>> {
16670        let Some(project) = self.project.clone() else {
16671            return Task::ready(Ok(None));
16672        };
16673
16674        cx.spawn_in(window, async move |editor, cx| {
16675            let location_task = editor.update(cx, |_, cx| {
16676                project.update(cx, |project, cx| {
16677                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16678                })
16679            })?;
16680            let location = Some({
16681                let target_buffer_handle = location_task.await.context("open local buffer")?;
16682                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16683                    let target_start = target_buffer
16684                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16685                    let target_end = target_buffer
16686                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16687                    target_buffer.anchor_after(target_start)
16688                        ..target_buffer.anchor_before(target_end)
16689                })?;
16690                Location {
16691                    buffer: target_buffer_handle,
16692                    range,
16693                }
16694            });
16695            Ok(location)
16696        })
16697    }
16698
16699    pub fn find_all_references(
16700        &mut self,
16701        _: &FindAllReferences,
16702        window: &mut Window,
16703        cx: &mut Context<Self>,
16704    ) -> Option<Task<Result<Navigated>>> {
16705        let selection = self.selections.newest::<usize>(cx);
16706        let multi_buffer = self.buffer.read(cx);
16707        let head = selection.head();
16708
16709        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16710        let head_anchor = multi_buffer_snapshot.anchor_at(
16711            head,
16712            if head < selection.tail() {
16713                Bias::Right
16714            } else {
16715                Bias::Left
16716            },
16717        );
16718
16719        match self
16720            .find_all_references_task_sources
16721            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16722        {
16723            Ok(_) => {
16724                log::info!(
16725                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16726                );
16727                return None;
16728            }
16729            Err(i) => {
16730                self.find_all_references_task_sources.insert(i, head_anchor);
16731            }
16732        }
16733
16734        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16735        let workspace = self.workspace()?;
16736        let project = workspace.read(cx).project().clone();
16737        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16738        Some(cx.spawn_in(window, async move |editor, cx| {
16739            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16740                if let Ok(i) = editor
16741                    .find_all_references_task_sources
16742                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16743                {
16744                    editor.find_all_references_task_sources.remove(i);
16745                }
16746            });
16747
16748            let Some(locations) = references.await? else {
16749                return anyhow::Ok(Navigated::No);
16750            };
16751            let mut locations = cx.update(|_, cx| {
16752                locations
16753                    .into_iter()
16754                    .map(|location| {
16755                        let buffer = location.buffer.read(cx);
16756                        (location.buffer, location.range.to_point(buffer))
16757                    })
16758                    .into_group_map()
16759            })?;
16760            if locations.is_empty() {
16761                return anyhow::Ok(Navigated::No);
16762            }
16763            for ranges in locations.values_mut() {
16764                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16765                ranges.dedup();
16766            }
16767
16768            workspace.update_in(cx, |workspace, window, cx| {
16769                let target = locations
16770                    .iter()
16771                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16772                    .map(|(buffer, location)| {
16773                        buffer
16774                            .read(cx)
16775                            .text_for_range(location.clone())
16776                            .collect::<String>()
16777                    })
16778                    .filter(|text| !text.contains('\n'))
16779                    .unique()
16780                    .take(3)
16781                    .join(", ");
16782                let title = if target.is_empty() {
16783                    "References".to_owned()
16784                } else {
16785                    format!("References to {target}")
16786                };
16787                Self::open_locations_in_multibuffer(
16788                    workspace,
16789                    locations,
16790                    title,
16791                    false,
16792                    MultibufferSelectionMode::First,
16793                    window,
16794                    cx,
16795                );
16796                Navigated::Yes
16797            })
16798        }))
16799    }
16800
16801    /// Opens a multibuffer with the given project locations in it
16802    pub fn open_locations_in_multibuffer(
16803        workspace: &mut Workspace,
16804        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16805        title: String,
16806        split: bool,
16807        multibuffer_selection_mode: MultibufferSelectionMode,
16808        window: &mut Window,
16809        cx: &mut Context<Workspace>,
16810    ) {
16811        if locations.is_empty() {
16812            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16813            return;
16814        }
16815
16816        let capability = workspace.project().read(cx).capability();
16817        let mut ranges = <Vec<Range<Anchor>>>::new();
16818
16819        // a key to find existing multibuffer editors with the same set of locations
16820        // to prevent us from opening more and more multibuffer tabs for searches and the like
16821        let mut key = (title.clone(), vec![]);
16822        let excerpt_buffer = cx.new(|cx| {
16823            let key = &mut key.1;
16824            let mut multibuffer = MultiBuffer::new(capability);
16825            for (buffer, mut ranges_for_buffer) in locations {
16826                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16827                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16828                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16829                    PathKey::for_buffer(&buffer, cx),
16830                    buffer.clone(),
16831                    ranges_for_buffer,
16832                    multibuffer_context_lines(cx),
16833                    cx,
16834                );
16835                ranges.extend(new_ranges)
16836            }
16837
16838            multibuffer.with_title(title)
16839        });
16840        let existing = workspace.active_pane().update(cx, |pane, cx| {
16841            pane.items()
16842                .filter_map(|item| item.downcast::<Editor>())
16843                .find(|editor| {
16844                    editor
16845                        .read(cx)
16846                        .lookup_key
16847                        .as_ref()
16848                        .and_then(|it| {
16849                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16850                        })
16851                        .is_some_and(|it| *it == key)
16852                })
16853        });
16854        let editor = existing.unwrap_or_else(|| {
16855            cx.new(|cx| {
16856                let mut editor = Editor::for_multibuffer(
16857                    excerpt_buffer,
16858                    Some(workspace.project().clone()),
16859                    window,
16860                    cx,
16861                );
16862                editor.lookup_key = Some(Box::new(key));
16863                editor
16864            })
16865        });
16866        editor.update(cx, |editor, cx| {
16867            match multibuffer_selection_mode {
16868                MultibufferSelectionMode::First => {
16869                    if let Some(first_range) = ranges.first() {
16870                        editor.change_selections(
16871                            SelectionEffects::no_scroll(),
16872                            window,
16873                            cx,
16874                            |selections| {
16875                                selections.clear_disjoint();
16876                                selections
16877                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16878                            },
16879                        );
16880                    }
16881                    editor.highlight_background::<Self>(
16882                        &ranges,
16883                        |theme| theme.colors().editor_highlighted_line_background,
16884                        cx,
16885                    );
16886                }
16887                MultibufferSelectionMode::All => {
16888                    editor.change_selections(
16889                        SelectionEffects::no_scroll(),
16890                        window,
16891                        cx,
16892                        |selections| {
16893                            selections.clear_disjoint();
16894                            selections.select_anchor_ranges(ranges);
16895                        },
16896                    );
16897                }
16898            }
16899            editor.register_buffers_with_language_servers(cx);
16900        });
16901
16902        let item = Box::new(editor);
16903        let item_id = item.item_id();
16904
16905        if split {
16906            let pane = workspace.adjacent_pane(window, cx);
16907            workspace.add_item(pane, item, None, true, true, window, cx);
16908        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16909            let (preview_item_id, preview_item_idx) =
16910                workspace.active_pane().read_with(cx, |pane, _| {
16911                    (pane.preview_item_id(), pane.preview_item_idx())
16912                });
16913
16914            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16915
16916            if let Some(preview_item_id) = preview_item_id {
16917                workspace.active_pane().update(cx, |pane, cx| {
16918                    pane.remove_item(preview_item_id, false, false, window, cx);
16919                });
16920            }
16921        } else {
16922            workspace.add_item_to_active_pane(item, None, true, window, cx);
16923        }
16924        workspace.active_pane().update(cx, |pane, cx| {
16925            pane.set_preview_item_id(Some(item_id), cx);
16926        });
16927    }
16928
16929    pub fn rename(
16930        &mut self,
16931        _: &Rename,
16932        window: &mut Window,
16933        cx: &mut Context<Self>,
16934    ) -> Option<Task<Result<()>>> {
16935        use language::ToOffset as _;
16936
16937        let provider = self.semantics_provider.clone()?;
16938        let selection = self.selections.newest_anchor().clone();
16939        let (cursor_buffer, cursor_buffer_position) = self
16940            .buffer
16941            .read(cx)
16942            .text_anchor_for_position(selection.head(), cx)?;
16943        let (tail_buffer, cursor_buffer_position_end) = self
16944            .buffer
16945            .read(cx)
16946            .text_anchor_for_position(selection.tail(), cx)?;
16947        if tail_buffer != cursor_buffer {
16948            return None;
16949        }
16950
16951        let snapshot = cursor_buffer.read(cx).snapshot();
16952        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16953        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16954        let prepare_rename = provider
16955            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16956            .unwrap_or_else(|| Task::ready(Ok(None)));
16957        drop(snapshot);
16958
16959        Some(cx.spawn_in(window, async move |this, cx| {
16960            let rename_range = if let Some(range) = prepare_rename.await? {
16961                Some(range)
16962            } else {
16963                this.update(cx, |this, cx| {
16964                    let buffer = this.buffer.read(cx).snapshot(cx);
16965                    let mut buffer_highlights = this
16966                        .document_highlights_for_position(selection.head(), &buffer)
16967                        .filter(|highlight| {
16968                            highlight.start.excerpt_id == selection.head().excerpt_id
16969                                && highlight.end.excerpt_id == selection.head().excerpt_id
16970                        });
16971                    buffer_highlights
16972                        .next()
16973                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16974                })?
16975            };
16976            if let Some(rename_range) = rename_range {
16977                this.update_in(cx, |this, window, cx| {
16978                    let snapshot = cursor_buffer.read(cx).snapshot();
16979                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16980                    let cursor_offset_in_rename_range =
16981                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16982                    let cursor_offset_in_rename_range_end =
16983                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16984
16985                    this.take_rename(false, window, cx);
16986                    let buffer = this.buffer.read(cx).read(cx);
16987                    let cursor_offset = selection.head().to_offset(&buffer);
16988                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16989                    let rename_end = rename_start + rename_buffer_range.len();
16990                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16991                    let mut old_highlight_id = None;
16992                    let old_name: Arc<str> = buffer
16993                        .chunks(rename_start..rename_end, true)
16994                        .map(|chunk| {
16995                            if old_highlight_id.is_none() {
16996                                old_highlight_id = chunk.syntax_highlight_id;
16997                            }
16998                            chunk.text
16999                        })
17000                        .collect::<String>()
17001                        .into();
17002
17003                    drop(buffer);
17004
17005                    // Position the selection in the rename editor so that it matches the current selection.
17006                    this.show_local_selections = false;
17007                    let rename_editor = cx.new(|cx| {
17008                        let mut editor = Editor::single_line(window, cx);
17009                        editor.buffer.update(cx, |buffer, cx| {
17010                            buffer.edit([(0..0, old_name.clone())], None, cx)
17011                        });
17012                        let rename_selection_range = match cursor_offset_in_rename_range
17013                            .cmp(&cursor_offset_in_rename_range_end)
17014                        {
17015                            Ordering::Equal => {
17016                                editor.select_all(&SelectAll, window, cx);
17017                                return editor;
17018                            }
17019                            Ordering::Less => {
17020                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17021                            }
17022                            Ordering::Greater => {
17023                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17024                            }
17025                        };
17026                        if rename_selection_range.end > old_name.len() {
17027                            editor.select_all(&SelectAll, window, cx);
17028                        } else {
17029                            editor.change_selections(Default::default(), window, cx, |s| {
17030                                s.select_ranges([rename_selection_range]);
17031                            });
17032                        }
17033                        editor
17034                    });
17035                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17036                        if e == &EditorEvent::Focused {
17037                            cx.emit(EditorEvent::FocusedIn)
17038                        }
17039                    })
17040                    .detach();
17041
17042                    let write_highlights =
17043                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17044                    let read_highlights =
17045                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17046                    let ranges = write_highlights
17047                        .iter()
17048                        .flat_map(|(_, ranges)| ranges.iter())
17049                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17050                        .cloned()
17051                        .collect();
17052
17053                    this.highlight_text::<Rename>(
17054                        ranges,
17055                        HighlightStyle {
17056                            fade_out: Some(0.6),
17057                            ..Default::default()
17058                        },
17059                        cx,
17060                    );
17061                    let rename_focus_handle = rename_editor.focus_handle(cx);
17062                    window.focus(&rename_focus_handle);
17063                    let block_id = this.insert_blocks(
17064                        [BlockProperties {
17065                            style: BlockStyle::Flex,
17066                            placement: BlockPlacement::Below(range.start),
17067                            height: Some(1),
17068                            render: Arc::new({
17069                                let rename_editor = rename_editor.clone();
17070                                move |cx: &mut BlockContext| {
17071                                    let mut text_style = cx.editor_style.text.clone();
17072                                    if let Some(highlight_style) = old_highlight_id
17073                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17074                                    {
17075                                        text_style = text_style.highlight(highlight_style);
17076                                    }
17077                                    div()
17078                                        .block_mouse_except_scroll()
17079                                        .pl(cx.anchor_x)
17080                                        .child(EditorElement::new(
17081                                            &rename_editor,
17082                                            EditorStyle {
17083                                                background: cx.theme().system().transparent,
17084                                                local_player: cx.editor_style.local_player,
17085                                                text: text_style,
17086                                                scrollbar_width: cx.editor_style.scrollbar_width,
17087                                                syntax: cx.editor_style.syntax.clone(),
17088                                                status: cx.editor_style.status.clone(),
17089                                                inlay_hints_style: HighlightStyle {
17090                                                    font_weight: Some(FontWeight::BOLD),
17091                                                    ..make_inlay_hints_style(cx.app)
17092                                                },
17093                                                edit_prediction_styles: make_suggestion_styles(
17094                                                    cx.app,
17095                                                ),
17096                                                ..EditorStyle::default()
17097                                            },
17098                                        ))
17099                                        .into_any_element()
17100                                }
17101                            }),
17102                            priority: 0,
17103                        }],
17104                        Some(Autoscroll::fit()),
17105                        cx,
17106                    )[0];
17107                    this.pending_rename = Some(RenameState {
17108                        range,
17109                        old_name,
17110                        editor: rename_editor,
17111                        block_id,
17112                    });
17113                })?;
17114            }
17115
17116            Ok(())
17117        }))
17118    }
17119
17120    pub fn confirm_rename(
17121        &mut self,
17122        _: &ConfirmRename,
17123        window: &mut Window,
17124        cx: &mut Context<Self>,
17125    ) -> Option<Task<Result<()>>> {
17126        let rename = self.take_rename(false, window, cx)?;
17127        let workspace = self.workspace()?.downgrade();
17128        let (buffer, start) = self
17129            .buffer
17130            .read(cx)
17131            .text_anchor_for_position(rename.range.start, cx)?;
17132        let (end_buffer, _) = self
17133            .buffer
17134            .read(cx)
17135            .text_anchor_for_position(rename.range.end, cx)?;
17136        if buffer != end_buffer {
17137            return None;
17138        }
17139
17140        let old_name = rename.old_name;
17141        let new_name = rename.editor.read(cx).text(cx);
17142
17143        let rename = self.semantics_provider.as_ref()?.perform_rename(
17144            &buffer,
17145            start,
17146            new_name.clone(),
17147            cx,
17148        )?;
17149
17150        Some(cx.spawn_in(window, async move |editor, cx| {
17151            let project_transaction = rename.await?;
17152            Self::open_project_transaction(
17153                &editor,
17154                workspace,
17155                project_transaction,
17156                format!("Rename: {}{}", old_name, new_name),
17157                cx,
17158            )
17159            .await?;
17160
17161            editor.update(cx, |editor, cx| {
17162                editor.refresh_document_highlights(cx);
17163            })?;
17164            Ok(())
17165        }))
17166    }
17167
17168    fn take_rename(
17169        &mut self,
17170        moving_cursor: bool,
17171        window: &mut Window,
17172        cx: &mut Context<Self>,
17173    ) -> Option<RenameState> {
17174        let rename = self.pending_rename.take()?;
17175        if rename.editor.focus_handle(cx).is_focused(window) {
17176            window.focus(&self.focus_handle);
17177        }
17178
17179        self.remove_blocks(
17180            [rename.block_id].into_iter().collect(),
17181            Some(Autoscroll::fit()),
17182            cx,
17183        );
17184        self.clear_highlights::<Rename>(cx);
17185        self.show_local_selections = true;
17186
17187        if moving_cursor {
17188            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17189                editor.selections.newest::<usize>(cx).head()
17190            });
17191
17192            // Update the selection to match the position of the selection inside
17193            // the rename editor.
17194            let snapshot = self.buffer.read(cx).read(cx);
17195            let rename_range = rename.range.to_offset(&snapshot);
17196            let cursor_in_editor = snapshot
17197                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17198                .min(rename_range.end);
17199            drop(snapshot);
17200
17201            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17202                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17203            });
17204        } else {
17205            self.refresh_document_highlights(cx);
17206        }
17207
17208        Some(rename)
17209    }
17210
17211    pub fn pending_rename(&self) -> Option<&RenameState> {
17212        self.pending_rename.as_ref()
17213    }
17214
17215    fn format(
17216        &mut self,
17217        _: &Format,
17218        window: &mut Window,
17219        cx: &mut Context<Self>,
17220    ) -> Option<Task<Result<()>>> {
17221        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17222
17223        let project = match &self.project {
17224            Some(project) => project.clone(),
17225            None => return None,
17226        };
17227
17228        Some(self.perform_format(
17229            project,
17230            FormatTrigger::Manual,
17231            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17232            window,
17233            cx,
17234        ))
17235    }
17236
17237    fn format_selections(
17238        &mut self,
17239        _: &FormatSelections,
17240        window: &mut Window,
17241        cx: &mut Context<Self>,
17242    ) -> Option<Task<Result<()>>> {
17243        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17244
17245        let project = match &self.project {
17246            Some(project) => project.clone(),
17247            None => return None,
17248        };
17249
17250        let ranges = self
17251            .selections
17252            .all_adjusted(cx)
17253            .into_iter()
17254            .map(|selection| selection.range())
17255            .collect_vec();
17256
17257        Some(self.perform_format(
17258            project,
17259            FormatTrigger::Manual,
17260            FormatTarget::Ranges(ranges),
17261            window,
17262            cx,
17263        ))
17264    }
17265
17266    fn perform_format(
17267        &mut self,
17268        project: Entity<Project>,
17269        trigger: FormatTrigger,
17270        target: FormatTarget,
17271        window: &mut Window,
17272        cx: &mut Context<Self>,
17273    ) -> Task<Result<()>> {
17274        let buffer = self.buffer.clone();
17275        let (buffers, target) = match target {
17276            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17277            FormatTarget::Ranges(selection_ranges) => {
17278                let multi_buffer = buffer.read(cx);
17279                let snapshot = multi_buffer.read(cx);
17280                let mut buffers = HashSet::default();
17281                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17282                    BTreeMap::new();
17283                for selection_range in selection_ranges {
17284                    for (buffer, buffer_range, _) in
17285                        snapshot.range_to_buffer_ranges(selection_range)
17286                    {
17287                        let buffer_id = buffer.remote_id();
17288                        let start = buffer.anchor_before(buffer_range.start);
17289                        let end = buffer.anchor_after(buffer_range.end);
17290                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17291                        buffer_id_to_ranges
17292                            .entry(buffer_id)
17293                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17294                            .or_insert_with(|| vec![start..end]);
17295                    }
17296                }
17297                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17298            }
17299        };
17300
17301        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17302        let selections_prev = transaction_id_prev
17303            .and_then(|transaction_id_prev| {
17304                // default to selections as they were after the last edit, if we have them,
17305                // instead of how they are now.
17306                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17307                // will take you back to where you made the last edit, instead of staying where you scrolled
17308                self.selection_history
17309                    .transaction(transaction_id_prev)
17310                    .map(|t| t.0.clone())
17311            })
17312            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17313
17314        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17315        let format = project.update(cx, |project, cx| {
17316            project.format(buffers, target, true, trigger, cx)
17317        });
17318
17319        cx.spawn_in(window, async move |editor, cx| {
17320            let transaction = futures::select_biased! {
17321                transaction = format.log_err().fuse() => transaction,
17322                () = timeout => {
17323                    log::warn!("timed out waiting for formatting");
17324                    None
17325                }
17326            };
17327
17328            buffer
17329                .update(cx, |buffer, cx| {
17330                    if let Some(transaction) = transaction
17331                        && !buffer.is_singleton()
17332                    {
17333                        buffer.push_transaction(&transaction.0, cx);
17334                    }
17335                    cx.notify();
17336                })
17337                .ok();
17338
17339            if let Some(transaction_id_now) =
17340                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17341            {
17342                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17343                if has_new_transaction {
17344                    _ = editor.update(cx, |editor, _| {
17345                        editor
17346                            .selection_history
17347                            .insert_transaction(transaction_id_now, selections_prev);
17348                    });
17349                }
17350            }
17351
17352            Ok(())
17353        })
17354    }
17355
17356    fn organize_imports(
17357        &mut self,
17358        _: &OrganizeImports,
17359        window: &mut Window,
17360        cx: &mut Context<Self>,
17361    ) -> Option<Task<Result<()>>> {
17362        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17363        let project = match &self.project {
17364            Some(project) => project.clone(),
17365            None => return None,
17366        };
17367        Some(self.perform_code_action_kind(
17368            project,
17369            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17370            window,
17371            cx,
17372        ))
17373    }
17374
17375    fn perform_code_action_kind(
17376        &mut self,
17377        project: Entity<Project>,
17378        kind: CodeActionKind,
17379        window: &mut Window,
17380        cx: &mut Context<Self>,
17381    ) -> Task<Result<()>> {
17382        let buffer = self.buffer.clone();
17383        let buffers = buffer.read(cx).all_buffers();
17384        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17385        let apply_action = project.update(cx, |project, cx| {
17386            project.apply_code_action_kind(buffers, kind, true, cx)
17387        });
17388        cx.spawn_in(window, async move |_, cx| {
17389            let transaction = futures::select_biased! {
17390                () = timeout => {
17391                    log::warn!("timed out waiting for executing code action");
17392                    None
17393                }
17394                transaction = apply_action.log_err().fuse() => transaction,
17395            };
17396            buffer
17397                .update(cx, |buffer, cx| {
17398                    // check if we need this
17399                    if let Some(transaction) = transaction
17400                        && !buffer.is_singleton()
17401                    {
17402                        buffer.push_transaction(&transaction.0, cx);
17403                    }
17404                    cx.notify();
17405                })
17406                .ok();
17407            Ok(())
17408        })
17409    }
17410
17411    pub fn restart_language_server(
17412        &mut self,
17413        _: &RestartLanguageServer,
17414        _: &mut Window,
17415        cx: &mut Context<Self>,
17416    ) {
17417        if let Some(project) = self.project.clone() {
17418            self.buffer.update(cx, |multi_buffer, cx| {
17419                project.update(cx, |project, cx| {
17420                    project.restart_language_servers_for_buffers(
17421                        multi_buffer.all_buffers().into_iter().collect(),
17422                        HashSet::default(),
17423                        cx,
17424                    );
17425                });
17426            })
17427        }
17428    }
17429
17430    pub fn stop_language_server(
17431        &mut self,
17432        _: &StopLanguageServer,
17433        _: &mut Window,
17434        cx: &mut Context<Self>,
17435    ) {
17436        if let Some(project) = self.project.clone() {
17437            self.buffer.update(cx, |multi_buffer, cx| {
17438                project.update(cx, |project, cx| {
17439                    project.stop_language_servers_for_buffers(
17440                        multi_buffer.all_buffers().into_iter().collect(),
17441                        HashSet::default(),
17442                        cx,
17443                    );
17444                    cx.emit(project::Event::RefreshInlayHints);
17445                });
17446            });
17447        }
17448    }
17449
17450    fn cancel_language_server_work(
17451        workspace: &mut Workspace,
17452        _: &actions::CancelLanguageServerWork,
17453        _: &mut Window,
17454        cx: &mut Context<Workspace>,
17455    ) {
17456        let project = workspace.project();
17457        let buffers = workspace
17458            .active_item(cx)
17459            .and_then(|item| item.act_as::<Editor>(cx))
17460            .map_or(HashSet::default(), |editor| {
17461                editor.read(cx).buffer.read(cx).all_buffers()
17462            });
17463        project.update(cx, |project, cx| {
17464            project.cancel_language_server_work_for_buffers(buffers, cx);
17465        });
17466    }
17467
17468    fn show_character_palette(
17469        &mut self,
17470        _: &ShowCharacterPalette,
17471        window: &mut Window,
17472        _: &mut Context<Self>,
17473    ) {
17474        window.show_character_palette();
17475    }
17476
17477    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17478        if !self.diagnostics_enabled() {
17479            return;
17480        }
17481
17482        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17483            let buffer = self.buffer.read(cx).snapshot(cx);
17484            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17485            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17486            let is_valid = buffer
17487                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17488                .any(|entry| {
17489                    entry.diagnostic.is_primary
17490                        && !entry.range.is_empty()
17491                        && entry.range.start == primary_range_start
17492                        && entry.diagnostic.message == active_diagnostics.active_message
17493                });
17494
17495            if !is_valid {
17496                self.dismiss_diagnostics(cx);
17497            }
17498        }
17499    }
17500
17501    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17502        match &self.active_diagnostics {
17503            ActiveDiagnostic::Group(group) => Some(group),
17504            _ => None,
17505        }
17506    }
17507
17508    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17509        if !self.diagnostics_enabled() {
17510            return;
17511        }
17512        self.dismiss_diagnostics(cx);
17513        self.active_diagnostics = ActiveDiagnostic::All;
17514    }
17515
17516    fn activate_diagnostics(
17517        &mut self,
17518        buffer_id: BufferId,
17519        diagnostic: DiagnosticEntryRef<'_, usize>,
17520        window: &mut Window,
17521        cx: &mut Context<Self>,
17522    ) {
17523        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17524            return;
17525        }
17526        self.dismiss_diagnostics(cx);
17527        let snapshot = self.snapshot(window, cx);
17528        let buffer = self.buffer.read(cx).snapshot(cx);
17529        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17530            return;
17531        };
17532
17533        let diagnostic_group = buffer
17534            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17535            .collect::<Vec<_>>();
17536
17537        let blocks =
17538            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17539
17540        let blocks = self.display_map.update(cx, |display_map, cx| {
17541            display_map.insert_blocks(blocks, cx).into_iter().collect()
17542        });
17543        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17544            active_range: buffer.anchor_before(diagnostic.range.start)
17545                ..buffer.anchor_after(diagnostic.range.end),
17546            active_message: diagnostic.diagnostic.message.clone(),
17547            group_id: diagnostic.diagnostic.group_id,
17548            blocks,
17549        });
17550        cx.notify();
17551    }
17552
17553    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17554        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17555            return;
17556        };
17557
17558        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17559        if let ActiveDiagnostic::Group(group) = prev {
17560            self.display_map.update(cx, |display_map, cx| {
17561                display_map.remove_blocks(group.blocks, cx);
17562            });
17563            cx.notify();
17564        }
17565    }
17566
17567    /// Disable inline diagnostics rendering for this editor.
17568    pub fn disable_inline_diagnostics(&mut self) {
17569        self.inline_diagnostics_enabled = false;
17570        self.inline_diagnostics_update = Task::ready(());
17571        self.inline_diagnostics.clear();
17572    }
17573
17574    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17575        self.diagnostics_enabled = false;
17576        self.dismiss_diagnostics(cx);
17577        self.inline_diagnostics_update = Task::ready(());
17578        self.inline_diagnostics.clear();
17579    }
17580
17581    pub fn disable_word_completions(&mut self) {
17582        self.word_completions_enabled = false;
17583    }
17584
17585    pub fn diagnostics_enabled(&self) -> bool {
17586        self.diagnostics_enabled && self.mode.is_full()
17587    }
17588
17589    pub fn inline_diagnostics_enabled(&self) -> bool {
17590        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17591    }
17592
17593    pub fn show_inline_diagnostics(&self) -> bool {
17594        self.show_inline_diagnostics
17595    }
17596
17597    pub fn toggle_inline_diagnostics(
17598        &mut self,
17599        _: &ToggleInlineDiagnostics,
17600        window: &mut Window,
17601        cx: &mut Context<Editor>,
17602    ) {
17603        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17604        self.refresh_inline_diagnostics(false, window, cx);
17605    }
17606
17607    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17608        self.diagnostics_max_severity = severity;
17609        self.display_map.update(cx, |display_map, _| {
17610            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17611        });
17612    }
17613
17614    pub fn toggle_diagnostics(
17615        &mut self,
17616        _: &ToggleDiagnostics,
17617        window: &mut Window,
17618        cx: &mut Context<Editor>,
17619    ) {
17620        if !self.diagnostics_enabled() {
17621            return;
17622        }
17623
17624        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17625            EditorSettings::get_global(cx)
17626                .diagnostics_max_severity
17627                .filter(|severity| severity != &DiagnosticSeverity::Off)
17628                .unwrap_or(DiagnosticSeverity::Hint)
17629        } else {
17630            DiagnosticSeverity::Off
17631        };
17632        self.set_max_diagnostics_severity(new_severity, cx);
17633        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17634            self.active_diagnostics = ActiveDiagnostic::None;
17635            self.inline_diagnostics_update = Task::ready(());
17636            self.inline_diagnostics.clear();
17637        } else {
17638            self.refresh_inline_diagnostics(false, window, cx);
17639        }
17640
17641        cx.notify();
17642    }
17643
17644    pub fn toggle_minimap(
17645        &mut self,
17646        _: &ToggleMinimap,
17647        window: &mut Window,
17648        cx: &mut Context<Editor>,
17649    ) {
17650        if self.supports_minimap(cx) {
17651            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17652        }
17653    }
17654
17655    fn refresh_inline_diagnostics(
17656        &mut self,
17657        debounce: bool,
17658        window: &mut Window,
17659        cx: &mut Context<Self>,
17660    ) {
17661        let max_severity = ProjectSettings::get_global(cx)
17662            .diagnostics
17663            .inline
17664            .max_severity
17665            .unwrap_or(self.diagnostics_max_severity);
17666
17667        if !self.inline_diagnostics_enabled()
17668            || !self.show_inline_diagnostics
17669            || max_severity == DiagnosticSeverity::Off
17670        {
17671            self.inline_diagnostics_update = Task::ready(());
17672            self.inline_diagnostics.clear();
17673            return;
17674        }
17675
17676        let debounce_ms = ProjectSettings::get_global(cx)
17677            .diagnostics
17678            .inline
17679            .update_debounce_ms;
17680        let debounce = if debounce && debounce_ms > 0 {
17681            Some(Duration::from_millis(debounce_ms))
17682        } else {
17683            None
17684        };
17685        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17686            if let Some(debounce) = debounce {
17687                cx.background_executor().timer(debounce).await;
17688            }
17689            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17690                editor
17691                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17692                    .ok()
17693            }) else {
17694                return;
17695            };
17696
17697            let new_inline_diagnostics = cx
17698                .background_spawn(async move {
17699                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17700                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17701                        let message = diagnostic_entry
17702                            .diagnostic
17703                            .message
17704                            .split_once('\n')
17705                            .map(|(line, _)| line)
17706                            .map(SharedString::new)
17707                            .unwrap_or_else(|| {
17708                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17709                            });
17710                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17711                        let (Ok(i) | Err(i)) = inline_diagnostics
17712                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17713                        inline_diagnostics.insert(
17714                            i,
17715                            (
17716                                start_anchor,
17717                                InlineDiagnostic {
17718                                    message,
17719                                    group_id: diagnostic_entry.diagnostic.group_id,
17720                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17721                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17722                                    severity: diagnostic_entry.diagnostic.severity,
17723                                },
17724                            ),
17725                        );
17726                    }
17727                    inline_diagnostics
17728                })
17729                .await;
17730
17731            editor
17732                .update(cx, |editor, cx| {
17733                    editor.inline_diagnostics = new_inline_diagnostics;
17734                    cx.notify();
17735                })
17736                .ok();
17737        });
17738    }
17739
17740    fn pull_diagnostics(
17741        &mut self,
17742        buffer_id: Option<BufferId>,
17743        window: &Window,
17744        cx: &mut Context<Self>,
17745    ) -> Option<()> {
17746        if !self.mode().is_full() {
17747            return None;
17748        }
17749        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17750            .diagnostics
17751            .lsp_pull_diagnostics;
17752        if !pull_diagnostics_settings.enabled {
17753            return None;
17754        }
17755        let project = self.project()?.downgrade();
17756        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17757        let mut buffers = self.buffer.read(cx).all_buffers();
17758        if let Some(buffer_id) = buffer_id {
17759            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17760        }
17761
17762        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17763            cx.background_executor().timer(debounce).await;
17764
17765            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17766                buffers
17767                    .into_iter()
17768                    .filter_map(|buffer| {
17769                        project
17770                            .update(cx, |project, cx| {
17771                                project.lsp_store().update(cx, |lsp_store, cx| {
17772                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17773                                })
17774                            })
17775                            .ok()
17776                    })
17777                    .collect::<FuturesUnordered<_>>()
17778            }) else {
17779                return;
17780            };
17781
17782            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17783                match pull_task {
17784                    Ok(()) => {
17785                        if editor
17786                            .update_in(cx, |editor, window, cx| {
17787                                editor.update_diagnostics_state(window, cx);
17788                            })
17789                            .is_err()
17790                        {
17791                            return;
17792                        }
17793                    }
17794                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17795                }
17796            }
17797        });
17798
17799        Some(())
17800    }
17801
17802    pub fn set_selections_from_remote(
17803        &mut self,
17804        selections: Vec<Selection<Anchor>>,
17805        pending_selection: Option<Selection<Anchor>>,
17806        window: &mut Window,
17807        cx: &mut Context<Self>,
17808    ) {
17809        let old_cursor_position = self.selections.newest_anchor().head();
17810        self.selections.change_with(cx, |s| {
17811            s.select_anchors(selections);
17812            if let Some(pending_selection) = pending_selection {
17813                s.set_pending(pending_selection, SelectMode::Character);
17814            } else {
17815                s.clear_pending();
17816            }
17817        });
17818        self.selections_did_change(
17819            false,
17820            &old_cursor_position,
17821            SelectionEffects::default(),
17822            window,
17823            cx,
17824        );
17825    }
17826
17827    pub fn transact(
17828        &mut self,
17829        window: &mut Window,
17830        cx: &mut Context<Self>,
17831        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17832    ) -> Option<TransactionId> {
17833        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17834            this.start_transaction_at(Instant::now(), window, cx);
17835            update(this, window, cx);
17836            this.end_transaction_at(Instant::now(), cx)
17837        })
17838    }
17839
17840    pub fn start_transaction_at(
17841        &mut self,
17842        now: Instant,
17843        window: &mut Window,
17844        cx: &mut Context<Self>,
17845    ) -> Option<TransactionId> {
17846        self.end_selection(window, cx);
17847        if let Some(tx_id) = self
17848            .buffer
17849            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17850        {
17851            self.selection_history
17852                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17853            cx.emit(EditorEvent::TransactionBegun {
17854                transaction_id: tx_id,
17855            });
17856            Some(tx_id)
17857        } else {
17858            None
17859        }
17860    }
17861
17862    pub fn end_transaction_at(
17863        &mut self,
17864        now: Instant,
17865        cx: &mut Context<Self>,
17866    ) -> Option<TransactionId> {
17867        if let Some(transaction_id) = self
17868            .buffer
17869            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17870        {
17871            if let Some((_, end_selections)) =
17872                self.selection_history.transaction_mut(transaction_id)
17873            {
17874                *end_selections = Some(self.selections.disjoint_anchors_arc());
17875            } else {
17876                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17877            }
17878
17879            cx.emit(EditorEvent::Edited { transaction_id });
17880            Some(transaction_id)
17881        } else {
17882            None
17883        }
17884    }
17885
17886    pub fn modify_transaction_selection_history(
17887        &mut self,
17888        transaction_id: TransactionId,
17889        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17890    ) -> bool {
17891        self.selection_history
17892            .transaction_mut(transaction_id)
17893            .map(modify)
17894            .is_some()
17895    }
17896
17897    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17898        if self.selection_mark_mode {
17899            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17900                s.move_with(|_, sel| {
17901                    sel.collapse_to(sel.head(), SelectionGoal::None);
17902                });
17903            })
17904        }
17905        self.selection_mark_mode = true;
17906        cx.notify();
17907    }
17908
17909    pub fn swap_selection_ends(
17910        &mut self,
17911        _: &actions::SwapSelectionEnds,
17912        window: &mut Window,
17913        cx: &mut Context<Self>,
17914    ) {
17915        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17916            s.move_with(|_, sel| {
17917                if sel.start != sel.end {
17918                    sel.reversed = !sel.reversed
17919                }
17920            });
17921        });
17922        self.request_autoscroll(Autoscroll::newest(), cx);
17923        cx.notify();
17924    }
17925
17926    pub fn toggle_focus(
17927        workspace: &mut Workspace,
17928        _: &actions::ToggleFocus,
17929        window: &mut Window,
17930        cx: &mut Context<Workspace>,
17931    ) {
17932        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17933            return;
17934        };
17935        workspace.activate_item(&item, true, true, window, cx);
17936    }
17937
17938    pub fn toggle_fold(
17939        &mut self,
17940        _: &actions::ToggleFold,
17941        window: &mut Window,
17942        cx: &mut Context<Self>,
17943    ) {
17944        if self.is_singleton(cx) {
17945            let selection = self.selections.newest::<Point>(cx);
17946
17947            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17948            let range = if selection.is_empty() {
17949                let point = selection.head().to_display_point(&display_map);
17950                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17951                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17952                    .to_point(&display_map);
17953                start..end
17954            } else {
17955                selection.range()
17956            };
17957            if display_map.folds_in_range(range).next().is_some() {
17958                self.unfold_lines(&Default::default(), window, cx)
17959            } else {
17960                self.fold(&Default::default(), window, cx)
17961            }
17962        } else {
17963            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17964            let buffer_ids: HashSet<_> = self
17965                .selections
17966                .disjoint_anchor_ranges()
17967                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17968                .collect();
17969
17970            let should_unfold = buffer_ids
17971                .iter()
17972                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17973
17974            for buffer_id in buffer_ids {
17975                if should_unfold {
17976                    self.unfold_buffer(buffer_id, cx);
17977                } else {
17978                    self.fold_buffer(buffer_id, cx);
17979                }
17980            }
17981        }
17982    }
17983
17984    pub fn toggle_fold_recursive(
17985        &mut self,
17986        _: &actions::ToggleFoldRecursive,
17987        window: &mut Window,
17988        cx: &mut Context<Self>,
17989    ) {
17990        let selection = self.selections.newest::<Point>(cx);
17991
17992        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17993        let range = if selection.is_empty() {
17994            let point = selection.head().to_display_point(&display_map);
17995            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17996            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17997                .to_point(&display_map);
17998            start..end
17999        } else {
18000            selection.range()
18001        };
18002        if display_map.folds_in_range(range).next().is_some() {
18003            self.unfold_recursive(&Default::default(), window, cx)
18004        } else {
18005            self.fold_recursive(&Default::default(), window, cx)
18006        }
18007    }
18008
18009    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18010        if self.is_singleton(cx) {
18011            let mut to_fold = Vec::new();
18012            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18013            let selections = self.selections.all_adjusted(cx);
18014
18015            for selection in selections {
18016                let range = selection.range().sorted();
18017                let buffer_start_row = range.start.row;
18018
18019                if range.start.row != range.end.row {
18020                    let mut found = false;
18021                    let mut row = range.start.row;
18022                    while row <= range.end.row {
18023                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18024                        {
18025                            found = true;
18026                            row = crease.range().end.row + 1;
18027                            to_fold.push(crease);
18028                        } else {
18029                            row += 1
18030                        }
18031                    }
18032                    if found {
18033                        continue;
18034                    }
18035                }
18036
18037                for row in (0..=range.start.row).rev() {
18038                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18039                        && crease.range().end.row >= buffer_start_row
18040                    {
18041                        to_fold.push(crease);
18042                        if row <= range.start.row {
18043                            break;
18044                        }
18045                    }
18046                }
18047            }
18048
18049            self.fold_creases(to_fold, true, window, cx);
18050        } else {
18051            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18052            let buffer_ids = self
18053                .selections
18054                .disjoint_anchor_ranges()
18055                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18056                .collect::<HashSet<_>>();
18057            for buffer_id in buffer_ids {
18058                self.fold_buffer(buffer_id, cx);
18059            }
18060        }
18061    }
18062
18063    pub fn toggle_fold_all(
18064        &mut self,
18065        _: &actions::ToggleFoldAll,
18066        window: &mut Window,
18067        cx: &mut Context<Self>,
18068    ) {
18069        if self.buffer.read(cx).is_singleton() {
18070            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18071            let has_folds = display_map
18072                .folds_in_range(0..display_map.buffer_snapshot.len())
18073                .next()
18074                .is_some();
18075
18076            if has_folds {
18077                self.unfold_all(&actions::UnfoldAll, window, cx);
18078            } else {
18079                self.fold_all(&actions::FoldAll, window, cx);
18080            }
18081        } else {
18082            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18083            let should_unfold = buffer_ids
18084                .iter()
18085                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18086
18087            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18088                editor
18089                    .update_in(cx, |editor, _, cx| {
18090                        for buffer_id in buffer_ids {
18091                            if should_unfold {
18092                                editor.unfold_buffer(buffer_id, cx);
18093                            } else {
18094                                editor.fold_buffer(buffer_id, cx);
18095                            }
18096                        }
18097                    })
18098                    .ok();
18099            });
18100        }
18101    }
18102
18103    fn fold_at_level(
18104        &mut self,
18105        fold_at: &FoldAtLevel,
18106        window: &mut Window,
18107        cx: &mut Context<Self>,
18108    ) {
18109        if !self.buffer.read(cx).is_singleton() {
18110            return;
18111        }
18112
18113        let fold_at_level = fold_at.0;
18114        let snapshot = self.buffer.read(cx).snapshot(cx);
18115        let mut to_fold = Vec::new();
18116        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18117
18118        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18119            while start_row < end_row {
18120                match self
18121                    .snapshot(window, cx)
18122                    .crease_for_buffer_row(MultiBufferRow(start_row))
18123                {
18124                    Some(crease) => {
18125                        let nested_start_row = crease.range().start.row + 1;
18126                        let nested_end_row = crease.range().end.row;
18127
18128                        if current_level < fold_at_level {
18129                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18130                        } else if current_level == fold_at_level {
18131                            to_fold.push(crease);
18132                        }
18133
18134                        start_row = nested_end_row + 1;
18135                    }
18136                    None => start_row += 1,
18137                }
18138            }
18139        }
18140
18141        self.fold_creases(to_fold, true, window, cx);
18142    }
18143
18144    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18145        if self.buffer.read(cx).is_singleton() {
18146            let mut fold_ranges = Vec::new();
18147            let snapshot = self.buffer.read(cx).snapshot(cx);
18148
18149            for row in 0..snapshot.max_row().0 {
18150                if let Some(foldable_range) = self
18151                    .snapshot(window, cx)
18152                    .crease_for_buffer_row(MultiBufferRow(row))
18153                {
18154                    fold_ranges.push(foldable_range);
18155                }
18156            }
18157
18158            self.fold_creases(fold_ranges, true, window, cx);
18159        } else {
18160            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18161                editor
18162                    .update_in(cx, |editor, _, cx| {
18163                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18164                            editor.fold_buffer(buffer_id, cx);
18165                        }
18166                    })
18167                    .ok();
18168            });
18169        }
18170    }
18171
18172    pub fn fold_function_bodies(
18173        &mut self,
18174        _: &actions::FoldFunctionBodies,
18175        window: &mut Window,
18176        cx: &mut Context<Self>,
18177    ) {
18178        let snapshot = self.buffer.read(cx).snapshot(cx);
18179
18180        let ranges = snapshot
18181            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18182            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18183            .collect::<Vec<_>>();
18184
18185        let creases = ranges
18186            .into_iter()
18187            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18188            .collect();
18189
18190        self.fold_creases(creases, true, window, cx);
18191    }
18192
18193    pub fn fold_recursive(
18194        &mut self,
18195        _: &actions::FoldRecursive,
18196        window: &mut Window,
18197        cx: &mut Context<Self>,
18198    ) {
18199        let mut to_fold = Vec::new();
18200        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18201        let selections = self.selections.all_adjusted(cx);
18202
18203        for selection in selections {
18204            let range = selection.range().sorted();
18205            let buffer_start_row = range.start.row;
18206
18207            if range.start.row != range.end.row {
18208                let mut found = false;
18209                for row in range.start.row..=range.end.row {
18210                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18211                        found = true;
18212                        to_fold.push(crease);
18213                    }
18214                }
18215                if found {
18216                    continue;
18217                }
18218            }
18219
18220            for row in (0..=range.start.row).rev() {
18221                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18222                    if crease.range().end.row >= buffer_start_row {
18223                        to_fold.push(crease);
18224                    } else {
18225                        break;
18226                    }
18227                }
18228            }
18229        }
18230
18231        self.fold_creases(to_fold, true, window, cx);
18232    }
18233
18234    pub fn fold_at(
18235        &mut self,
18236        buffer_row: MultiBufferRow,
18237        window: &mut Window,
18238        cx: &mut Context<Self>,
18239    ) {
18240        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18241
18242        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18243            let autoscroll = self
18244                .selections
18245                .all::<Point>(cx)
18246                .iter()
18247                .any(|selection| crease.range().overlaps(&selection.range()));
18248
18249            self.fold_creases(vec![crease], autoscroll, window, cx);
18250        }
18251    }
18252
18253    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18254        if self.is_singleton(cx) {
18255            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18256            let buffer = &display_map.buffer_snapshot;
18257            let selections = self.selections.all::<Point>(cx);
18258            let ranges = selections
18259                .iter()
18260                .map(|s| {
18261                    let range = s.display_range(&display_map).sorted();
18262                    let mut start = range.start.to_point(&display_map);
18263                    let mut end = range.end.to_point(&display_map);
18264                    start.column = 0;
18265                    end.column = buffer.line_len(MultiBufferRow(end.row));
18266                    start..end
18267                })
18268                .collect::<Vec<_>>();
18269
18270            self.unfold_ranges(&ranges, true, true, cx);
18271        } else {
18272            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18273            let buffer_ids = self
18274                .selections
18275                .disjoint_anchor_ranges()
18276                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18277                .collect::<HashSet<_>>();
18278            for buffer_id in buffer_ids {
18279                self.unfold_buffer(buffer_id, cx);
18280            }
18281        }
18282    }
18283
18284    pub fn unfold_recursive(
18285        &mut self,
18286        _: &UnfoldRecursive,
18287        _window: &mut Window,
18288        cx: &mut Context<Self>,
18289    ) {
18290        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18291        let selections = self.selections.all::<Point>(cx);
18292        let ranges = selections
18293            .iter()
18294            .map(|s| {
18295                let mut range = s.display_range(&display_map).sorted();
18296                *range.start.column_mut() = 0;
18297                *range.end.column_mut() = display_map.line_len(range.end.row());
18298                let start = range.start.to_point(&display_map);
18299                let end = range.end.to_point(&display_map);
18300                start..end
18301            })
18302            .collect::<Vec<_>>();
18303
18304        self.unfold_ranges(&ranges, true, true, cx);
18305    }
18306
18307    pub fn unfold_at(
18308        &mut self,
18309        buffer_row: MultiBufferRow,
18310        _window: &mut Window,
18311        cx: &mut Context<Self>,
18312    ) {
18313        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18314
18315        let intersection_range = Point::new(buffer_row.0, 0)
18316            ..Point::new(
18317                buffer_row.0,
18318                display_map.buffer_snapshot.line_len(buffer_row),
18319            );
18320
18321        let autoscroll = self
18322            .selections
18323            .all::<Point>(cx)
18324            .iter()
18325            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18326
18327        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18328    }
18329
18330    pub fn unfold_all(
18331        &mut self,
18332        _: &actions::UnfoldAll,
18333        _window: &mut Window,
18334        cx: &mut Context<Self>,
18335    ) {
18336        if self.buffer.read(cx).is_singleton() {
18337            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18338            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18339        } else {
18340            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18341                editor
18342                    .update(cx, |editor, cx| {
18343                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18344                            editor.unfold_buffer(buffer_id, cx);
18345                        }
18346                    })
18347                    .ok();
18348            });
18349        }
18350    }
18351
18352    pub fn fold_selected_ranges(
18353        &mut self,
18354        _: &FoldSelectedRanges,
18355        window: &mut Window,
18356        cx: &mut Context<Self>,
18357    ) {
18358        let selections = self.selections.all_adjusted(cx);
18359        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18360        let ranges = selections
18361            .into_iter()
18362            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18363            .collect::<Vec<_>>();
18364        self.fold_creases(ranges, true, window, cx);
18365    }
18366
18367    pub fn fold_ranges<T: ToOffset + Clone>(
18368        &mut self,
18369        ranges: Vec<Range<T>>,
18370        auto_scroll: bool,
18371        window: &mut Window,
18372        cx: &mut Context<Self>,
18373    ) {
18374        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18375        let ranges = ranges
18376            .into_iter()
18377            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18378            .collect::<Vec<_>>();
18379        self.fold_creases(ranges, auto_scroll, window, cx);
18380    }
18381
18382    pub fn fold_creases<T: ToOffset + Clone>(
18383        &mut self,
18384        creases: Vec<Crease<T>>,
18385        auto_scroll: bool,
18386        _window: &mut Window,
18387        cx: &mut Context<Self>,
18388    ) {
18389        if creases.is_empty() {
18390            return;
18391        }
18392
18393        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18394
18395        if auto_scroll {
18396            self.request_autoscroll(Autoscroll::fit(), cx);
18397        }
18398
18399        cx.notify();
18400
18401        self.scrollbar_marker_state.dirty = true;
18402        self.folds_did_change(cx);
18403    }
18404
18405    /// Removes any folds whose ranges intersect any of the given ranges.
18406    pub fn unfold_ranges<T: ToOffset + Clone>(
18407        &mut self,
18408        ranges: &[Range<T>],
18409        inclusive: bool,
18410        auto_scroll: bool,
18411        cx: &mut Context<Self>,
18412    ) {
18413        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18414            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18415        });
18416        self.folds_did_change(cx);
18417    }
18418
18419    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18420        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18421            return;
18422        }
18423        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18424        self.display_map.update(cx, |display_map, cx| {
18425            display_map.fold_buffers([buffer_id], cx)
18426        });
18427        cx.emit(EditorEvent::BufferFoldToggled {
18428            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18429            folded: true,
18430        });
18431        cx.notify();
18432    }
18433
18434    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18435        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18436            return;
18437        }
18438        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18439        self.display_map.update(cx, |display_map, cx| {
18440            display_map.unfold_buffers([buffer_id], cx);
18441        });
18442        cx.emit(EditorEvent::BufferFoldToggled {
18443            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18444            folded: false,
18445        });
18446        cx.notify();
18447    }
18448
18449    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18450        self.display_map.read(cx).is_buffer_folded(buffer)
18451    }
18452
18453    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18454        self.display_map.read(cx).folded_buffers()
18455    }
18456
18457    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18458        self.display_map.update(cx, |display_map, cx| {
18459            display_map.disable_header_for_buffer(buffer_id, cx);
18460        });
18461        cx.notify();
18462    }
18463
18464    /// Removes any folds with the given ranges.
18465    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18466        &mut self,
18467        ranges: &[Range<T>],
18468        type_id: TypeId,
18469        auto_scroll: bool,
18470        cx: &mut Context<Self>,
18471    ) {
18472        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18473            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18474        });
18475        self.folds_did_change(cx);
18476    }
18477
18478    fn remove_folds_with<T: ToOffset + Clone>(
18479        &mut self,
18480        ranges: &[Range<T>],
18481        auto_scroll: bool,
18482        cx: &mut Context<Self>,
18483        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18484    ) {
18485        if ranges.is_empty() {
18486            return;
18487        }
18488
18489        let mut buffers_affected = HashSet::default();
18490        let multi_buffer = self.buffer().read(cx);
18491        for range in ranges {
18492            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18493                buffers_affected.insert(buffer.read(cx).remote_id());
18494            };
18495        }
18496
18497        self.display_map.update(cx, update);
18498
18499        if auto_scroll {
18500            self.request_autoscroll(Autoscroll::fit(), cx);
18501        }
18502
18503        cx.notify();
18504        self.scrollbar_marker_state.dirty = true;
18505        self.active_indent_guides_state.dirty = true;
18506    }
18507
18508    pub fn update_renderer_widths(
18509        &mut self,
18510        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18511        cx: &mut Context<Self>,
18512    ) -> bool {
18513        self.display_map
18514            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18515    }
18516
18517    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18518        self.display_map.read(cx).fold_placeholder.clone()
18519    }
18520
18521    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18522        self.buffer.update(cx, |buffer, cx| {
18523            buffer.set_all_diff_hunks_expanded(cx);
18524        });
18525    }
18526
18527    pub fn expand_all_diff_hunks(
18528        &mut self,
18529        _: &ExpandAllDiffHunks,
18530        _window: &mut Window,
18531        cx: &mut Context<Self>,
18532    ) {
18533        self.buffer.update(cx, |buffer, cx| {
18534            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18535        });
18536    }
18537
18538    pub fn toggle_selected_diff_hunks(
18539        &mut self,
18540        _: &ToggleSelectedDiffHunks,
18541        _window: &mut Window,
18542        cx: &mut Context<Self>,
18543    ) {
18544        let ranges: Vec<_> = self
18545            .selections
18546            .disjoint_anchors()
18547            .iter()
18548            .map(|s| s.range())
18549            .collect();
18550        self.toggle_diff_hunks_in_ranges(ranges, cx);
18551    }
18552
18553    pub fn diff_hunks_in_ranges<'a>(
18554        &'a self,
18555        ranges: &'a [Range<Anchor>],
18556        buffer: &'a MultiBufferSnapshot,
18557    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18558        ranges.iter().flat_map(move |range| {
18559            let end_excerpt_id = range.end.excerpt_id;
18560            let range = range.to_point(buffer);
18561            let mut peek_end = range.end;
18562            if range.end.row < buffer.max_row().0 {
18563                peek_end = Point::new(range.end.row + 1, 0);
18564            }
18565            buffer
18566                .diff_hunks_in_range(range.start..peek_end)
18567                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18568        })
18569    }
18570
18571    pub fn has_stageable_diff_hunks_in_ranges(
18572        &self,
18573        ranges: &[Range<Anchor>],
18574        snapshot: &MultiBufferSnapshot,
18575    ) -> bool {
18576        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18577        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18578    }
18579
18580    pub fn toggle_staged_selected_diff_hunks(
18581        &mut self,
18582        _: &::git::ToggleStaged,
18583        _: &mut Window,
18584        cx: &mut Context<Self>,
18585    ) {
18586        let snapshot = self.buffer.read(cx).snapshot(cx);
18587        let ranges: Vec<_> = self
18588            .selections
18589            .disjoint_anchors()
18590            .iter()
18591            .map(|s| s.range())
18592            .collect();
18593        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18594        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18595    }
18596
18597    pub fn set_render_diff_hunk_controls(
18598        &mut self,
18599        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18600        cx: &mut Context<Self>,
18601    ) {
18602        self.render_diff_hunk_controls = render_diff_hunk_controls;
18603        cx.notify();
18604    }
18605
18606    pub fn stage_and_next(
18607        &mut self,
18608        _: &::git::StageAndNext,
18609        window: &mut Window,
18610        cx: &mut Context<Self>,
18611    ) {
18612        self.do_stage_or_unstage_and_next(true, window, cx);
18613    }
18614
18615    pub fn unstage_and_next(
18616        &mut self,
18617        _: &::git::UnstageAndNext,
18618        window: &mut Window,
18619        cx: &mut Context<Self>,
18620    ) {
18621        self.do_stage_or_unstage_and_next(false, window, cx);
18622    }
18623
18624    pub fn stage_or_unstage_diff_hunks(
18625        &mut self,
18626        stage: bool,
18627        ranges: Vec<Range<Anchor>>,
18628        cx: &mut Context<Self>,
18629    ) {
18630        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18631        cx.spawn(async move |this, cx| {
18632            task.await?;
18633            this.update(cx, |this, cx| {
18634                let snapshot = this.buffer.read(cx).snapshot(cx);
18635                let chunk_by = this
18636                    .diff_hunks_in_ranges(&ranges, &snapshot)
18637                    .chunk_by(|hunk| hunk.buffer_id);
18638                for (buffer_id, hunks) in &chunk_by {
18639                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18640                }
18641            })
18642        })
18643        .detach_and_log_err(cx);
18644    }
18645
18646    fn save_buffers_for_ranges_if_needed(
18647        &mut self,
18648        ranges: &[Range<Anchor>],
18649        cx: &mut Context<Editor>,
18650    ) -> Task<Result<()>> {
18651        let multibuffer = self.buffer.read(cx);
18652        let snapshot = multibuffer.read(cx);
18653        let buffer_ids: HashSet<_> = ranges
18654            .iter()
18655            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18656            .collect();
18657        drop(snapshot);
18658
18659        let mut buffers = HashSet::default();
18660        for buffer_id in buffer_ids {
18661            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18662                let buffer = buffer_entity.read(cx);
18663                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18664                {
18665                    buffers.insert(buffer_entity);
18666                }
18667            }
18668        }
18669
18670        if let Some(project) = &self.project {
18671            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18672        } else {
18673            Task::ready(Ok(()))
18674        }
18675    }
18676
18677    fn do_stage_or_unstage_and_next(
18678        &mut self,
18679        stage: bool,
18680        window: &mut Window,
18681        cx: &mut Context<Self>,
18682    ) {
18683        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18684
18685        if ranges.iter().any(|range| range.start != range.end) {
18686            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18687            return;
18688        }
18689
18690        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18691        let snapshot = self.snapshot(window, cx);
18692        let position = self.selections.newest::<Point>(cx).head();
18693        let mut row = snapshot
18694            .buffer_snapshot
18695            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18696            .find(|hunk| hunk.row_range.start.0 > position.row)
18697            .map(|hunk| hunk.row_range.start);
18698
18699        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18700        // Outside of the project diff editor, wrap around to the beginning.
18701        if !all_diff_hunks_expanded {
18702            row = row.or_else(|| {
18703                snapshot
18704                    .buffer_snapshot
18705                    .diff_hunks_in_range(Point::zero()..position)
18706                    .find(|hunk| hunk.row_range.end.0 < position.row)
18707                    .map(|hunk| hunk.row_range.start)
18708            });
18709        }
18710
18711        if let Some(row) = row {
18712            let destination = Point::new(row.0, 0);
18713            let autoscroll = Autoscroll::center();
18714
18715            self.unfold_ranges(&[destination..destination], false, false, cx);
18716            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18717                s.select_ranges([destination..destination]);
18718            });
18719        }
18720    }
18721
18722    fn do_stage_or_unstage(
18723        &self,
18724        stage: bool,
18725        buffer_id: BufferId,
18726        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18727        cx: &mut App,
18728    ) -> Option<()> {
18729        let project = self.project()?;
18730        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18731        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18732        let buffer_snapshot = buffer.read(cx).snapshot();
18733        let file_exists = buffer_snapshot
18734            .file()
18735            .is_some_and(|file| file.disk_state().exists());
18736        diff.update(cx, |diff, cx| {
18737            diff.stage_or_unstage_hunks(
18738                stage,
18739                &hunks
18740                    .map(|hunk| buffer_diff::DiffHunk {
18741                        buffer_range: hunk.buffer_range,
18742                        diff_base_byte_range: hunk.diff_base_byte_range,
18743                        secondary_status: hunk.secondary_status,
18744                        range: Point::zero()..Point::zero(), // unused
18745                    })
18746                    .collect::<Vec<_>>(),
18747                &buffer_snapshot,
18748                file_exists,
18749                cx,
18750            )
18751        });
18752        None
18753    }
18754
18755    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18756        let ranges: Vec<_> = self
18757            .selections
18758            .disjoint_anchors()
18759            .iter()
18760            .map(|s| s.range())
18761            .collect();
18762        self.buffer
18763            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18764    }
18765
18766    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18767        self.buffer.update(cx, |buffer, cx| {
18768            let ranges = vec![Anchor::min()..Anchor::max()];
18769            if !buffer.all_diff_hunks_expanded()
18770                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18771            {
18772                buffer.collapse_diff_hunks(ranges, cx);
18773                true
18774            } else {
18775                false
18776            }
18777        })
18778    }
18779
18780    fn toggle_diff_hunks_in_ranges(
18781        &mut self,
18782        ranges: Vec<Range<Anchor>>,
18783        cx: &mut Context<Editor>,
18784    ) {
18785        self.buffer.update(cx, |buffer, cx| {
18786            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18787            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18788        })
18789    }
18790
18791    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18792        self.buffer.update(cx, |buffer, cx| {
18793            let snapshot = buffer.snapshot(cx);
18794            let excerpt_id = range.end.excerpt_id;
18795            let point_range = range.to_point(&snapshot);
18796            let expand = !buffer.single_hunk_is_expanded(range, cx);
18797            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18798        })
18799    }
18800
18801    pub(crate) fn apply_all_diff_hunks(
18802        &mut self,
18803        _: &ApplyAllDiffHunks,
18804        window: &mut Window,
18805        cx: &mut Context<Self>,
18806    ) {
18807        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18808
18809        let buffers = self.buffer.read(cx).all_buffers();
18810        for branch_buffer in buffers {
18811            branch_buffer.update(cx, |branch_buffer, cx| {
18812                branch_buffer.merge_into_base(Vec::new(), cx);
18813            });
18814        }
18815
18816        if let Some(project) = self.project.clone() {
18817            self.save(
18818                SaveOptions {
18819                    format: true,
18820                    autosave: false,
18821                },
18822                project,
18823                window,
18824                cx,
18825            )
18826            .detach_and_log_err(cx);
18827        }
18828    }
18829
18830    pub(crate) fn apply_selected_diff_hunks(
18831        &mut self,
18832        _: &ApplyDiffHunk,
18833        window: &mut Window,
18834        cx: &mut Context<Self>,
18835    ) {
18836        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18837        let snapshot = self.snapshot(window, cx);
18838        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18839        let mut ranges_by_buffer = HashMap::default();
18840        self.transact(window, cx, |editor, _window, cx| {
18841            for hunk in hunks {
18842                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18843                    ranges_by_buffer
18844                        .entry(buffer.clone())
18845                        .or_insert_with(Vec::new)
18846                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18847                }
18848            }
18849
18850            for (buffer, ranges) in ranges_by_buffer {
18851                buffer.update(cx, |buffer, cx| {
18852                    buffer.merge_into_base(ranges, cx);
18853                });
18854            }
18855        });
18856
18857        if let Some(project) = self.project.clone() {
18858            self.save(
18859                SaveOptions {
18860                    format: true,
18861                    autosave: false,
18862                },
18863                project,
18864                window,
18865                cx,
18866            )
18867            .detach_and_log_err(cx);
18868        }
18869    }
18870
18871    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18872        if hovered != self.gutter_hovered {
18873            self.gutter_hovered = hovered;
18874            cx.notify();
18875        }
18876    }
18877
18878    pub fn insert_blocks(
18879        &mut self,
18880        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18881        autoscroll: Option<Autoscroll>,
18882        cx: &mut Context<Self>,
18883    ) -> Vec<CustomBlockId> {
18884        let blocks = self
18885            .display_map
18886            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18887        if let Some(autoscroll) = autoscroll {
18888            self.request_autoscroll(autoscroll, cx);
18889        }
18890        cx.notify();
18891        blocks
18892    }
18893
18894    pub fn resize_blocks(
18895        &mut self,
18896        heights: HashMap<CustomBlockId, u32>,
18897        autoscroll: Option<Autoscroll>,
18898        cx: &mut Context<Self>,
18899    ) {
18900        self.display_map
18901            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18902        if let Some(autoscroll) = autoscroll {
18903            self.request_autoscroll(autoscroll, cx);
18904        }
18905        cx.notify();
18906    }
18907
18908    pub fn replace_blocks(
18909        &mut self,
18910        renderers: HashMap<CustomBlockId, RenderBlock>,
18911        autoscroll: Option<Autoscroll>,
18912        cx: &mut Context<Self>,
18913    ) {
18914        self.display_map
18915            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18916        if let Some(autoscroll) = autoscroll {
18917            self.request_autoscroll(autoscroll, cx);
18918        }
18919        cx.notify();
18920    }
18921
18922    pub fn remove_blocks(
18923        &mut self,
18924        block_ids: HashSet<CustomBlockId>,
18925        autoscroll: Option<Autoscroll>,
18926        cx: &mut Context<Self>,
18927    ) {
18928        self.display_map.update(cx, |display_map, cx| {
18929            display_map.remove_blocks(block_ids, cx)
18930        });
18931        if let Some(autoscroll) = autoscroll {
18932            self.request_autoscroll(autoscroll, cx);
18933        }
18934        cx.notify();
18935    }
18936
18937    pub fn row_for_block(
18938        &self,
18939        block_id: CustomBlockId,
18940        cx: &mut Context<Self>,
18941    ) -> Option<DisplayRow> {
18942        self.display_map
18943            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18944    }
18945
18946    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18947        self.focused_block = Some(focused_block);
18948    }
18949
18950    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18951        self.focused_block.take()
18952    }
18953
18954    pub fn insert_creases(
18955        &mut self,
18956        creases: impl IntoIterator<Item = Crease<Anchor>>,
18957        cx: &mut Context<Self>,
18958    ) -> Vec<CreaseId> {
18959        self.display_map
18960            .update(cx, |map, cx| map.insert_creases(creases, cx))
18961    }
18962
18963    pub fn remove_creases(
18964        &mut self,
18965        ids: impl IntoIterator<Item = CreaseId>,
18966        cx: &mut Context<Self>,
18967    ) -> Vec<(CreaseId, Range<Anchor>)> {
18968        self.display_map
18969            .update(cx, |map, cx| map.remove_creases(ids, cx))
18970    }
18971
18972    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18973        self.display_map
18974            .update(cx, |map, cx| map.snapshot(cx))
18975            .longest_row()
18976    }
18977
18978    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18979        self.display_map
18980            .update(cx, |map, cx| map.snapshot(cx))
18981            .max_point()
18982    }
18983
18984    pub fn text(&self, cx: &App) -> String {
18985        self.buffer.read(cx).read(cx).text()
18986    }
18987
18988    pub fn is_empty(&self, cx: &App) -> bool {
18989        self.buffer.read(cx).read(cx).is_empty()
18990    }
18991
18992    pub fn text_option(&self, cx: &App) -> Option<String> {
18993        let text = self.text(cx);
18994        let text = text.trim();
18995
18996        if text.is_empty() {
18997            return None;
18998        }
18999
19000        Some(text.to_string())
19001    }
19002
19003    pub fn set_text(
19004        &mut self,
19005        text: impl Into<Arc<str>>,
19006        window: &mut Window,
19007        cx: &mut Context<Self>,
19008    ) {
19009        self.transact(window, cx, |this, _, cx| {
19010            this.buffer
19011                .read(cx)
19012                .as_singleton()
19013                .expect("you can only call set_text on editors for singleton buffers")
19014                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19015        });
19016    }
19017
19018    pub fn display_text(&self, cx: &mut App) -> String {
19019        self.display_map
19020            .update(cx, |map, cx| map.snapshot(cx))
19021            .text()
19022    }
19023
19024    fn create_minimap(
19025        &self,
19026        minimap_settings: MinimapSettings,
19027        window: &mut Window,
19028        cx: &mut Context<Self>,
19029    ) -> Option<Entity<Self>> {
19030        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
19031            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19032    }
19033
19034    fn initialize_new_minimap(
19035        &self,
19036        minimap_settings: MinimapSettings,
19037        window: &mut Window,
19038        cx: &mut Context<Self>,
19039    ) -> Entity<Self> {
19040        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19041
19042        let mut minimap = Editor::new_internal(
19043            EditorMode::Minimap {
19044                parent: cx.weak_entity(),
19045            },
19046            self.buffer.clone(),
19047            None,
19048            Some(self.display_map.clone()),
19049            window,
19050            cx,
19051        );
19052        minimap.scroll_manager.clone_state(&self.scroll_manager);
19053        minimap.set_text_style_refinement(TextStyleRefinement {
19054            font_size: Some(MINIMAP_FONT_SIZE),
19055            font_weight: Some(MINIMAP_FONT_WEIGHT),
19056            ..Default::default()
19057        });
19058        minimap.update_minimap_configuration(minimap_settings, cx);
19059        cx.new(|_| minimap)
19060    }
19061
19062    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19063        let current_line_highlight = minimap_settings
19064            .current_line_highlight
19065            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19066        self.set_current_line_highlight(Some(current_line_highlight));
19067    }
19068
19069    pub fn minimap(&self) -> Option<&Entity<Self>> {
19070        self.minimap
19071            .as_ref()
19072            .filter(|_| self.minimap_visibility.visible())
19073    }
19074
19075    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19076        let mut wrap_guides = smallvec![];
19077
19078        if self.show_wrap_guides == Some(false) {
19079            return wrap_guides;
19080        }
19081
19082        let settings = self.buffer.read(cx).language_settings(cx);
19083        if settings.show_wrap_guides {
19084            match self.soft_wrap_mode(cx) {
19085                SoftWrap::Column(soft_wrap) => {
19086                    wrap_guides.push((soft_wrap as usize, true));
19087                }
19088                SoftWrap::Bounded(soft_wrap) => {
19089                    wrap_guides.push((soft_wrap as usize, true));
19090                }
19091                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19092            }
19093            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19094        }
19095
19096        wrap_guides
19097    }
19098
19099    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19100        let settings = self.buffer.read(cx).language_settings(cx);
19101        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19102        match mode {
19103            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19104                SoftWrap::None
19105            }
19106            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19107            language_settings::SoftWrap::PreferredLineLength => {
19108                SoftWrap::Column(settings.preferred_line_length)
19109            }
19110            language_settings::SoftWrap::Bounded => {
19111                SoftWrap::Bounded(settings.preferred_line_length)
19112            }
19113        }
19114    }
19115
19116    pub fn set_soft_wrap_mode(
19117        &mut self,
19118        mode: language_settings::SoftWrap,
19119
19120        cx: &mut Context<Self>,
19121    ) {
19122        self.soft_wrap_mode_override = Some(mode);
19123        cx.notify();
19124    }
19125
19126    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19127        self.hard_wrap = hard_wrap;
19128        cx.notify();
19129    }
19130
19131    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19132        self.text_style_refinement = Some(style);
19133    }
19134
19135    /// called by the Element so we know what style we were most recently rendered with.
19136    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19137        // We intentionally do not inform the display map about the minimap style
19138        // so that wrapping is not recalculated and stays consistent for the editor
19139        // and its linked minimap.
19140        if !self.mode.is_minimap() {
19141            let font = style.text.font();
19142            let font_size = style.text.font_size.to_pixels(window.rem_size());
19143            let display_map = self
19144                .placeholder_display_map
19145                .as_ref()
19146                .filter(|_| self.is_empty(cx))
19147                .unwrap_or(&self.display_map);
19148
19149            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19150        }
19151        self.style = Some(style);
19152    }
19153
19154    pub fn style(&self) -> Option<&EditorStyle> {
19155        self.style.as_ref()
19156    }
19157
19158    // Called by the element. This method is not designed to be called outside of the editor
19159    // element's layout code because it does not notify when rewrapping is computed synchronously.
19160    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19161        if self.is_empty(cx) {
19162            self.placeholder_display_map
19163                .as_ref()
19164                .map_or(false, |display_map| {
19165                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19166                })
19167        } else {
19168            self.display_map
19169                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19170        }
19171    }
19172
19173    pub fn set_soft_wrap(&mut self) {
19174        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19175    }
19176
19177    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19178        if self.soft_wrap_mode_override.is_some() {
19179            self.soft_wrap_mode_override.take();
19180        } else {
19181            let soft_wrap = match self.soft_wrap_mode(cx) {
19182                SoftWrap::GitDiff => return,
19183                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19184                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19185                    language_settings::SoftWrap::None
19186                }
19187            };
19188            self.soft_wrap_mode_override = Some(soft_wrap);
19189        }
19190        cx.notify();
19191    }
19192
19193    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19194        let Some(workspace) = self.workspace() else {
19195            return;
19196        };
19197        let fs = workspace.read(cx).app_state().fs.clone();
19198        let current_show = TabBarSettings::get_global(cx).show;
19199        update_settings_file(fs, cx, move |setting, _| {
19200            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19201        });
19202    }
19203
19204    pub fn toggle_indent_guides(
19205        &mut self,
19206        _: &ToggleIndentGuides,
19207        _: &mut Window,
19208        cx: &mut Context<Self>,
19209    ) {
19210        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19211            self.buffer
19212                .read(cx)
19213                .language_settings(cx)
19214                .indent_guides
19215                .enabled
19216        });
19217        self.show_indent_guides = Some(!currently_enabled);
19218        cx.notify();
19219    }
19220
19221    fn should_show_indent_guides(&self) -> Option<bool> {
19222        self.show_indent_guides
19223    }
19224
19225    pub fn toggle_line_numbers(
19226        &mut self,
19227        _: &ToggleLineNumbers,
19228        _: &mut Window,
19229        cx: &mut Context<Self>,
19230    ) {
19231        let mut editor_settings = EditorSettings::get_global(cx).clone();
19232        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19233        EditorSettings::override_global(editor_settings, cx);
19234    }
19235
19236    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19237        if let Some(show_line_numbers) = self.show_line_numbers {
19238            return show_line_numbers;
19239        }
19240        EditorSettings::get_global(cx).gutter.line_numbers
19241    }
19242
19243    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19244        self.use_relative_line_numbers
19245            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19246    }
19247
19248    pub fn toggle_relative_line_numbers(
19249        &mut self,
19250        _: &ToggleRelativeLineNumbers,
19251        _: &mut Window,
19252        cx: &mut Context<Self>,
19253    ) {
19254        let is_relative = self.should_use_relative_line_numbers(cx);
19255        self.set_relative_line_number(Some(!is_relative), cx)
19256    }
19257
19258    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19259        self.use_relative_line_numbers = is_relative;
19260        cx.notify();
19261    }
19262
19263    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19264        self.show_gutter = show_gutter;
19265        cx.notify();
19266    }
19267
19268    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19269        self.show_scrollbars = ScrollbarAxes {
19270            horizontal: show,
19271            vertical: show,
19272        };
19273        cx.notify();
19274    }
19275
19276    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19277        self.show_scrollbars.vertical = show;
19278        cx.notify();
19279    }
19280
19281    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19282        self.show_scrollbars.horizontal = show;
19283        cx.notify();
19284    }
19285
19286    pub fn set_minimap_visibility(
19287        &mut self,
19288        minimap_visibility: MinimapVisibility,
19289        window: &mut Window,
19290        cx: &mut Context<Self>,
19291    ) {
19292        if self.minimap_visibility != minimap_visibility {
19293            if minimap_visibility.visible() && self.minimap.is_none() {
19294                let minimap_settings = EditorSettings::get_global(cx).minimap;
19295                self.minimap =
19296                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19297            }
19298            self.minimap_visibility = minimap_visibility;
19299            cx.notify();
19300        }
19301    }
19302
19303    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19304        self.set_show_scrollbars(false, cx);
19305        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19306    }
19307
19308    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19309        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19310    }
19311
19312    /// Normally the text in full mode and auto height editors is padded on the
19313    /// left side by roughly half a character width for improved hit testing.
19314    ///
19315    /// Use this method to disable this for cases where this is not wanted (e.g.
19316    /// if you want to align the editor text with some other text above or below)
19317    /// or if you want to add this padding to single-line editors.
19318    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19319        self.offset_content = offset_content;
19320        cx.notify();
19321    }
19322
19323    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19324        self.show_line_numbers = Some(show_line_numbers);
19325        cx.notify();
19326    }
19327
19328    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19329        self.disable_expand_excerpt_buttons = true;
19330        cx.notify();
19331    }
19332
19333    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19334        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19335        cx.notify();
19336    }
19337
19338    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19339        self.show_code_actions = Some(show_code_actions);
19340        cx.notify();
19341    }
19342
19343    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19344        self.show_runnables = Some(show_runnables);
19345        cx.notify();
19346    }
19347
19348    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19349        self.show_breakpoints = Some(show_breakpoints);
19350        cx.notify();
19351    }
19352
19353    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19354        if self.display_map.read(cx).masked != masked {
19355            self.display_map.update(cx, |map, _| map.masked = masked);
19356        }
19357        cx.notify()
19358    }
19359
19360    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19361        self.show_wrap_guides = Some(show_wrap_guides);
19362        cx.notify();
19363    }
19364
19365    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19366        self.show_indent_guides = Some(show_indent_guides);
19367        cx.notify();
19368    }
19369
19370    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19371        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19372            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19373                && let Some(dir) = file.abs_path(cx).parent()
19374            {
19375                return Some(dir.to_owned());
19376            }
19377        }
19378
19379        None
19380    }
19381
19382    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19383        self.active_excerpt(cx)?
19384            .1
19385            .read(cx)
19386            .file()
19387            .and_then(|f| f.as_local())
19388    }
19389
19390    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19391        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19392            let buffer = buffer.read(cx);
19393            if let Some(project_path) = buffer.project_path(cx) {
19394                let project = self.project()?.read(cx);
19395                project.absolute_path(&project_path, cx)
19396            } else {
19397                buffer
19398                    .file()
19399                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19400            }
19401        })
19402    }
19403
19404    pub fn reveal_in_finder(
19405        &mut self,
19406        _: &RevealInFileManager,
19407        _window: &mut Window,
19408        cx: &mut Context<Self>,
19409    ) {
19410        if let Some(target) = self.target_file(cx) {
19411            cx.reveal_path(&target.abs_path(cx));
19412        }
19413    }
19414
19415    pub fn copy_path(
19416        &mut self,
19417        _: &zed_actions::workspace::CopyPath,
19418        _window: &mut Window,
19419        cx: &mut Context<Self>,
19420    ) {
19421        if let Some(path) = self.target_file_abs_path(cx)
19422            && let Some(path) = path.to_str()
19423        {
19424            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19425        } else {
19426            cx.propagate();
19427        }
19428    }
19429
19430    pub fn copy_relative_path(
19431        &mut self,
19432        _: &zed_actions::workspace::CopyRelativePath,
19433        _window: &mut Window,
19434        cx: &mut Context<Self>,
19435    ) {
19436        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19437            let project = self.project()?.read(cx);
19438            let path = buffer.read(cx).file()?.path();
19439            let path = path.display(project.path_style(cx));
19440            Some(path)
19441        }) {
19442            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19443        } else {
19444            cx.propagate();
19445        }
19446    }
19447
19448    /// Returns the project path for the editor's buffer, if any buffer is
19449    /// opened in the editor.
19450    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19451        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19452            buffer.read(cx).project_path(cx)
19453        } else {
19454            None
19455        }
19456    }
19457
19458    // Returns true if the editor handled a go-to-line request
19459    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19460        maybe!({
19461            let breakpoint_store = self.breakpoint_store.as_ref()?;
19462
19463            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19464            else {
19465                self.clear_row_highlights::<ActiveDebugLine>();
19466                return None;
19467            };
19468
19469            let position = active_stack_frame.position;
19470            let buffer_id = position.buffer_id?;
19471            let snapshot = self
19472                .project
19473                .as_ref()?
19474                .read(cx)
19475                .buffer_for_id(buffer_id, cx)?
19476                .read(cx)
19477                .snapshot();
19478
19479            let mut handled = false;
19480            for (id, ExcerptRange { context, .. }) in
19481                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19482            {
19483                if context.start.cmp(&position, &snapshot).is_ge()
19484                    || context.end.cmp(&position, &snapshot).is_lt()
19485                {
19486                    continue;
19487                }
19488                let snapshot = self.buffer.read(cx).snapshot(cx);
19489                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19490
19491                handled = true;
19492                self.clear_row_highlights::<ActiveDebugLine>();
19493
19494                self.go_to_line::<ActiveDebugLine>(
19495                    multibuffer_anchor,
19496                    Some(cx.theme().colors().editor_debugger_active_line_background),
19497                    window,
19498                    cx,
19499                );
19500
19501                cx.notify();
19502            }
19503
19504            handled.then_some(())
19505        })
19506        .is_some()
19507    }
19508
19509    pub fn copy_file_name_without_extension(
19510        &mut self,
19511        _: &CopyFileNameWithoutExtension,
19512        _: &mut Window,
19513        cx: &mut Context<Self>,
19514    ) {
19515        if let Some(file) = self.target_file(cx)
19516            && let Some(file_stem) = file.path().file_stem()
19517        {
19518            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19519        }
19520    }
19521
19522    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19523        if let Some(file) = self.target_file(cx)
19524            && let Some(name) = file.path().file_name()
19525        {
19526            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19527        }
19528    }
19529
19530    pub fn toggle_git_blame(
19531        &mut self,
19532        _: &::git::Blame,
19533        window: &mut Window,
19534        cx: &mut Context<Self>,
19535    ) {
19536        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19537
19538        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19539            self.start_git_blame(true, window, cx);
19540        }
19541
19542        cx.notify();
19543    }
19544
19545    pub fn toggle_git_blame_inline(
19546        &mut self,
19547        _: &ToggleGitBlameInline,
19548        window: &mut Window,
19549        cx: &mut Context<Self>,
19550    ) {
19551        self.toggle_git_blame_inline_internal(true, window, cx);
19552        cx.notify();
19553    }
19554
19555    pub fn open_git_blame_commit(
19556        &mut self,
19557        _: &OpenGitBlameCommit,
19558        window: &mut Window,
19559        cx: &mut Context<Self>,
19560    ) {
19561        self.open_git_blame_commit_internal(window, cx);
19562    }
19563
19564    fn open_git_blame_commit_internal(
19565        &mut self,
19566        window: &mut Window,
19567        cx: &mut Context<Self>,
19568    ) -> Option<()> {
19569        let blame = self.blame.as_ref()?;
19570        let snapshot = self.snapshot(window, cx);
19571        let cursor = self.selections.newest::<Point>(cx).head();
19572        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19573        let (_, blame_entry) = blame
19574            .update(cx, |blame, cx| {
19575                blame
19576                    .blame_for_rows(
19577                        &[RowInfo {
19578                            buffer_id: Some(buffer.remote_id()),
19579                            buffer_row: Some(point.row),
19580                            ..Default::default()
19581                        }],
19582                        cx,
19583                    )
19584                    .next()
19585            })
19586            .flatten()?;
19587        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19588        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19589        let workspace = self.workspace()?.downgrade();
19590        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19591        None
19592    }
19593
19594    pub fn git_blame_inline_enabled(&self) -> bool {
19595        self.git_blame_inline_enabled
19596    }
19597
19598    pub fn toggle_selection_menu(
19599        &mut self,
19600        _: &ToggleSelectionMenu,
19601        _: &mut Window,
19602        cx: &mut Context<Self>,
19603    ) {
19604        self.show_selection_menu = self
19605            .show_selection_menu
19606            .map(|show_selections_menu| !show_selections_menu)
19607            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19608
19609        cx.notify();
19610    }
19611
19612    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19613        self.show_selection_menu
19614            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19615    }
19616
19617    fn start_git_blame(
19618        &mut self,
19619        user_triggered: bool,
19620        window: &mut Window,
19621        cx: &mut Context<Self>,
19622    ) {
19623        if let Some(project) = self.project() {
19624            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19625                && buffer.read(cx).file().is_none()
19626            {
19627                return;
19628            }
19629
19630            let focused = self.focus_handle(cx).contains_focused(window, cx);
19631
19632            let project = project.clone();
19633            let blame = cx
19634                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19635            self.blame_subscription =
19636                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19637            self.blame = Some(blame);
19638        }
19639    }
19640
19641    fn toggle_git_blame_inline_internal(
19642        &mut self,
19643        user_triggered: bool,
19644        window: &mut Window,
19645        cx: &mut Context<Self>,
19646    ) {
19647        if self.git_blame_inline_enabled {
19648            self.git_blame_inline_enabled = false;
19649            self.show_git_blame_inline = false;
19650            self.show_git_blame_inline_delay_task.take();
19651        } else {
19652            self.git_blame_inline_enabled = true;
19653            self.start_git_blame_inline(user_triggered, window, cx);
19654        }
19655
19656        cx.notify();
19657    }
19658
19659    fn start_git_blame_inline(
19660        &mut self,
19661        user_triggered: bool,
19662        window: &mut Window,
19663        cx: &mut Context<Self>,
19664    ) {
19665        self.start_git_blame(user_triggered, window, cx);
19666
19667        if ProjectSettings::get_global(cx)
19668            .git
19669            .inline_blame_delay()
19670            .is_some()
19671        {
19672            self.start_inline_blame_timer(window, cx);
19673        } else {
19674            self.show_git_blame_inline = true
19675        }
19676    }
19677
19678    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19679        self.blame.as_ref()
19680    }
19681
19682    pub fn show_git_blame_gutter(&self) -> bool {
19683        self.show_git_blame_gutter
19684    }
19685
19686    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19687        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19688    }
19689
19690    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19691        self.show_git_blame_inline
19692            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19693            && !self.newest_selection_head_on_empty_line(cx)
19694            && self.has_blame_entries(cx)
19695    }
19696
19697    fn has_blame_entries(&self, cx: &App) -> bool {
19698        self.blame()
19699            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19700    }
19701
19702    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19703        let cursor_anchor = self.selections.newest_anchor().head();
19704
19705        let snapshot = self.buffer.read(cx).snapshot(cx);
19706        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19707
19708        snapshot.line_len(buffer_row) == 0
19709    }
19710
19711    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19712        let buffer_and_selection = maybe!({
19713            let selection = self.selections.newest::<Point>(cx);
19714            let selection_range = selection.range();
19715
19716            let multi_buffer = self.buffer().read(cx);
19717            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19718            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19719
19720            let (buffer, range, _) = if selection.reversed {
19721                buffer_ranges.first()
19722            } else {
19723                buffer_ranges.last()
19724            }?;
19725
19726            let selection = text::ToPoint::to_point(&range.start, buffer).row
19727                ..text::ToPoint::to_point(&range.end, buffer).row;
19728            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19729        });
19730
19731        let Some((buffer, selection)) = buffer_and_selection else {
19732            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19733        };
19734
19735        let Some(project) = self.project() else {
19736            return Task::ready(Err(anyhow!("editor does not have project")));
19737        };
19738
19739        project.update(cx, |project, cx| {
19740            project.get_permalink_to_line(&buffer, selection, cx)
19741        })
19742    }
19743
19744    pub fn copy_permalink_to_line(
19745        &mut self,
19746        _: &CopyPermalinkToLine,
19747        window: &mut Window,
19748        cx: &mut Context<Self>,
19749    ) {
19750        let permalink_task = self.get_permalink_to_line(cx);
19751        let workspace = self.workspace();
19752
19753        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19754            Ok(permalink) => {
19755                cx.update(|_, cx| {
19756                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19757                })
19758                .ok();
19759            }
19760            Err(err) => {
19761                let message = format!("Failed to copy permalink: {err}");
19762
19763                anyhow::Result::<()>::Err(err).log_err();
19764
19765                if let Some(workspace) = workspace {
19766                    workspace
19767                        .update_in(cx, |workspace, _, cx| {
19768                            struct CopyPermalinkToLine;
19769
19770                            workspace.show_toast(
19771                                Toast::new(
19772                                    NotificationId::unique::<CopyPermalinkToLine>(),
19773                                    message,
19774                                ),
19775                                cx,
19776                            )
19777                        })
19778                        .ok();
19779                }
19780            }
19781        })
19782        .detach();
19783    }
19784
19785    pub fn copy_file_location(
19786        &mut self,
19787        _: &CopyFileLocation,
19788        _: &mut Window,
19789        cx: &mut Context<Self>,
19790    ) {
19791        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19792        if let Some(file) = self.target_file(cx) {
19793            let path = file.path().display(file.path_style(cx));
19794            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19795        }
19796    }
19797
19798    pub fn open_permalink_to_line(
19799        &mut self,
19800        _: &OpenPermalinkToLine,
19801        window: &mut Window,
19802        cx: &mut Context<Self>,
19803    ) {
19804        let permalink_task = self.get_permalink_to_line(cx);
19805        let workspace = self.workspace();
19806
19807        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19808            Ok(permalink) => {
19809                cx.update(|_, cx| {
19810                    cx.open_url(permalink.as_ref());
19811                })
19812                .ok();
19813            }
19814            Err(err) => {
19815                let message = format!("Failed to open permalink: {err}");
19816
19817                anyhow::Result::<()>::Err(err).log_err();
19818
19819                if let Some(workspace) = workspace {
19820                    workspace
19821                        .update(cx, |workspace, cx| {
19822                            struct OpenPermalinkToLine;
19823
19824                            workspace.show_toast(
19825                                Toast::new(
19826                                    NotificationId::unique::<OpenPermalinkToLine>(),
19827                                    message,
19828                                ),
19829                                cx,
19830                            )
19831                        })
19832                        .ok();
19833                }
19834            }
19835        })
19836        .detach();
19837    }
19838
19839    pub fn insert_uuid_v4(
19840        &mut self,
19841        _: &InsertUuidV4,
19842        window: &mut Window,
19843        cx: &mut Context<Self>,
19844    ) {
19845        self.insert_uuid(UuidVersion::V4, window, cx);
19846    }
19847
19848    pub fn insert_uuid_v7(
19849        &mut self,
19850        _: &InsertUuidV7,
19851        window: &mut Window,
19852        cx: &mut Context<Self>,
19853    ) {
19854        self.insert_uuid(UuidVersion::V7, window, cx);
19855    }
19856
19857    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19858        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19859        self.transact(window, cx, |this, window, cx| {
19860            let edits = this
19861                .selections
19862                .all::<Point>(cx)
19863                .into_iter()
19864                .map(|selection| {
19865                    let uuid = match version {
19866                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19867                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19868                    };
19869
19870                    (selection.range(), uuid.to_string())
19871                });
19872            this.edit(edits, cx);
19873            this.refresh_edit_prediction(true, false, window, cx);
19874        });
19875    }
19876
19877    pub fn open_selections_in_multibuffer(
19878        &mut self,
19879        _: &OpenSelectionsInMultibuffer,
19880        window: &mut Window,
19881        cx: &mut Context<Self>,
19882    ) {
19883        let multibuffer = self.buffer.read(cx);
19884
19885        let Some(buffer) = multibuffer.as_singleton() else {
19886            return;
19887        };
19888
19889        let Some(workspace) = self.workspace() else {
19890            return;
19891        };
19892
19893        let title = multibuffer.title(cx).to_string();
19894
19895        let locations = self
19896            .selections
19897            .all_anchors(cx)
19898            .iter()
19899            .map(|selection| {
19900                (
19901                    buffer.clone(),
19902                    (selection.start.text_anchor..selection.end.text_anchor)
19903                        .to_point(buffer.read(cx)),
19904                )
19905            })
19906            .into_group_map();
19907
19908        cx.spawn_in(window, async move |_, cx| {
19909            workspace.update_in(cx, |workspace, window, cx| {
19910                Self::open_locations_in_multibuffer(
19911                    workspace,
19912                    locations,
19913                    format!("Selections for '{title}'"),
19914                    false,
19915                    MultibufferSelectionMode::All,
19916                    window,
19917                    cx,
19918                );
19919            })
19920        })
19921        .detach();
19922    }
19923
19924    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19925    /// last highlight added will be used.
19926    ///
19927    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19928    pub fn highlight_rows<T: 'static>(
19929        &mut self,
19930        range: Range<Anchor>,
19931        color: Hsla,
19932        options: RowHighlightOptions,
19933        cx: &mut Context<Self>,
19934    ) {
19935        let snapshot = self.buffer().read(cx).snapshot(cx);
19936        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19937        let ix = row_highlights.binary_search_by(|highlight| {
19938            Ordering::Equal
19939                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19940                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19941        });
19942
19943        if let Err(mut ix) = ix {
19944            let index = post_inc(&mut self.highlight_order);
19945
19946            // If this range intersects with the preceding highlight, then merge it with
19947            // the preceding highlight. Otherwise insert a new highlight.
19948            let mut merged = false;
19949            if ix > 0 {
19950                let prev_highlight = &mut row_highlights[ix - 1];
19951                if prev_highlight
19952                    .range
19953                    .end
19954                    .cmp(&range.start, &snapshot)
19955                    .is_ge()
19956                {
19957                    ix -= 1;
19958                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19959                        prev_highlight.range.end = range.end;
19960                    }
19961                    merged = true;
19962                    prev_highlight.index = index;
19963                    prev_highlight.color = color;
19964                    prev_highlight.options = options;
19965                }
19966            }
19967
19968            if !merged {
19969                row_highlights.insert(
19970                    ix,
19971                    RowHighlight {
19972                        range,
19973                        index,
19974                        color,
19975                        options,
19976                        type_id: TypeId::of::<T>(),
19977                    },
19978                );
19979            }
19980
19981            // If any of the following highlights intersect with this one, merge them.
19982            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19983                let highlight = &row_highlights[ix];
19984                if next_highlight
19985                    .range
19986                    .start
19987                    .cmp(&highlight.range.end, &snapshot)
19988                    .is_le()
19989                {
19990                    if next_highlight
19991                        .range
19992                        .end
19993                        .cmp(&highlight.range.end, &snapshot)
19994                        .is_gt()
19995                    {
19996                        row_highlights[ix].range.end = next_highlight.range.end;
19997                    }
19998                    row_highlights.remove(ix + 1);
19999                } else {
20000                    break;
20001                }
20002            }
20003        }
20004    }
20005
20006    /// Remove any highlighted row ranges of the given type that intersect the
20007    /// given ranges.
20008    pub fn remove_highlighted_rows<T: 'static>(
20009        &mut self,
20010        ranges_to_remove: Vec<Range<Anchor>>,
20011        cx: &mut Context<Self>,
20012    ) {
20013        let snapshot = self.buffer().read(cx).snapshot(cx);
20014        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20015        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20016        row_highlights.retain(|highlight| {
20017            while let Some(range_to_remove) = ranges_to_remove.peek() {
20018                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20019                    Ordering::Less | Ordering::Equal => {
20020                        ranges_to_remove.next();
20021                    }
20022                    Ordering::Greater => {
20023                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20024                            Ordering::Less | Ordering::Equal => {
20025                                return false;
20026                            }
20027                            Ordering::Greater => break,
20028                        }
20029                    }
20030                }
20031            }
20032
20033            true
20034        })
20035    }
20036
20037    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20038    pub fn clear_row_highlights<T: 'static>(&mut self) {
20039        self.highlighted_rows.remove(&TypeId::of::<T>());
20040    }
20041
20042    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20043    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20044        self.highlighted_rows
20045            .get(&TypeId::of::<T>())
20046            .map_or(&[] as &[_], |vec| vec.as_slice())
20047            .iter()
20048            .map(|highlight| (highlight.range.clone(), highlight.color))
20049    }
20050
20051    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20052    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20053    /// Allows to ignore certain kinds of highlights.
20054    pub fn highlighted_display_rows(
20055        &self,
20056        window: &mut Window,
20057        cx: &mut App,
20058    ) -> BTreeMap<DisplayRow, LineHighlight> {
20059        let snapshot = self.snapshot(window, cx);
20060        let mut used_highlight_orders = HashMap::default();
20061        self.highlighted_rows
20062            .iter()
20063            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20064            .fold(
20065                BTreeMap::<DisplayRow, LineHighlight>::new(),
20066                |mut unique_rows, highlight| {
20067                    let start = highlight.range.start.to_display_point(&snapshot);
20068                    let end = highlight.range.end.to_display_point(&snapshot);
20069                    let start_row = start.row().0;
20070                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20071                        && end.column() == 0
20072                    {
20073                        end.row().0.saturating_sub(1)
20074                    } else {
20075                        end.row().0
20076                    };
20077                    for row in start_row..=end_row {
20078                        let used_index =
20079                            used_highlight_orders.entry(row).or_insert(highlight.index);
20080                        if highlight.index >= *used_index {
20081                            *used_index = highlight.index;
20082                            unique_rows.insert(
20083                                DisplayRow(row),
20084                                LineHighlight {
20085                                    include_gutter: highlight.options.include_gutter,
20086                                    border: None,
20087                                    background: highlight.color.into(),
20088                                    type_id: Some(highlight.type_id),
20089                                },
20090                            );
20091                        }
20092                    }
20093                    unique_rows
20094                },
20095            )
20096    }
20097
20098    pub fn highlighted_display_row_for_autoscroll(
20099        &self,
20100        snapshot: &DisplaySnapshot,
20101    ) -> Option<DisplayRow> {
20102        self.highlighted_rows
20103            .values()
20104            .flat_map(|highlighted_rows| highlighted_rows.iter())
20105            .filter_map(|highlight| {
20106                if highlight.options.autoscroll {
20107                    Some(highlight.range.start.to_display_point(snapshot).row())
20108                } else {
20109                    None
20110                }
20111            })
20112            .min()
20113    }
20114
20115    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20116        self.highlight_background::<SearchWithinRange>(
20117            ranges,
20118            |colors| colors.colors().editor_document_highlight_read_background,
20119            cx,
20120        )
20121    }
20122
20123    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20124        self.breadcrumb_header = Some(new_header);
20125    }
20126
20127    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20128        self.clear_background_highlights::<SearchWithinRange>(cx);
20129    }
20130
20131    pub fn highlight_background<T: 'static>(
20132        &mut self,
20133        ranges: &[Range<Anchor>],
20134        color_fetcher: fn(&Theme) -> Hsla,
20135        cx: &mut Context<Self>,
20136    ) {
20137        self.background_highlights.insert(
20138            HighlightKey::Type(TypeId::of::<T>()),
20139            (color_fetcher, Arc::from(ranges)),
20140        );
20141        self.scrollbar_marker_state.dirty = true;
20142        cx.notify();
20143    }
20144
20145    pub fn highlight_background_key<T: 'static>(
20146        &mut self,
20147        key: usize,
20148        ranges: &[Range<Anchor>],
20149        color_fetcher: fn(&Theme) -> Hsla,
20150        cx: &mut Context<Self>,
20151    ) {
20152        self.background_highlights.insert(
20153            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20154            (color_fetcher, Arc::from(ranges)),
20155        );
20156        self.scrollbar_marker_state.dirty = true;
20157        cx.notify();
20158    }
20159
20160    pub fn clear_background_highlights<T: 'static>(
20161        &mut self,
20162        cx: &mut Context<Self>,
20163    ) -> Option<BackgroundHighlight> {
20164        let text_highlights = self
20165            .background_highlights
20166            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20167        if !text_highlights.1.is_empty() {
20168            self.scrollbar_marker_state.dirty = true;
20169            cx.notify();
20170        }
20171        Some(text_highlights)
20172    }
20173
20174    pub fn highlight_gutter<T: 'static>(
20175        &mut self,
20176        ranges: impl Into<Vec<Range<Anchor>>>,
20177        color_fetcher: fn(&App) -> Hsla,
20178        cx: &mut Context<Self>,
20179    ) {
20180        self.gutter_highlights
20181            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20182        cx.notify();
20183    }
20184
20185    pub fn clear_gutter_highlights<T: 'static>(
20186        &mut self,
20187        cx: &mut Context<Self>,
20188    ) -> Option<GutterHighlight> {
20189        cx.notify();
20190        self.gutter_highlights.remove(&TypeId::of::<T>())
20191    }
20192
20193    pub fn insert_gutter_highlight<T: 'static>(
20194        &mut self,
20195        range: Range<Anchor>,
20196        color_fetcher: fn(&App) -> Hsla,
20197        cx: &mut Context<Self>,
20198    ) {
20199        let snapshot = self.buffer().read(cx).snapshot(cx);
20200        let mut highlights = self
20201            .gutter_highlights
20202            .remove(&TypeId::of::<T>())
20203            .map(|(_, highlights)| highlights)
20204            .unwrap_or_default();
20205        let ix = highlights.binary_search_by(|highlight| {
20206            Ordering::Equal
20207                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20208                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20209        });
20210        if let Err(ix) = ix {
20211            highlights.insert(ix, range);
20212        }
20213        self.gutter_highlights
20214            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20215    }
20216
20217    pub fn remove_gutter_highlights<T: 'static>(
20218        &mut self,
20219        ranges_to_remove: Vec<Range<Anchor>>,
20220        cx: &mut Context<Self>,
20221    ) {
20222        let snapshot = self.buffer().read(cx).snapshot(cx);
20223        let Some((color_fetcher, mut gutter_highlights)) =
20224            self.gutter_highlights.remove(&TypeId::of::<T>())
20225        else {
20226            return;
20227        };
20228        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20229        gutter_highlights.retain(|highlight| {
20230            while let Some(range_to_remove) = ranges_to_remove.peek() {
20231                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20232                    Ordering::Less | Ordering::Equal => {
20233                        ranges_to_remove.next();
20234                    }
20235                    Ordering::Greater => {
20236                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20237                            Ordering::Less | Ordering::Equal => {
20238                                return false;
20239                            }
20240                            Ordering::Greater => break,
20241                        }
20242                    }
20243                }
20244            }
20245
20246            true
20247        });
20248        self.gutter_highlights
20249            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20250    }
20251
20252    #[cfg(feature = "test-support")]
20253    pub fn all_text_highlights(
20254        &self,
20255        window: &mut Window,
20256        cx: &mut Context<Self>,
20257    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20258        let snapshot = self.snapshot(window, cx);
20259        self.display_map.update(cx, |display_map, _| {
20260            display_map
20261                .all_text_highlights()
20262                .map(|highlight| {
20263                    let (style, ranges) = highlight.as_ref();
20264                    (
20265                        *style,
20266                        ranges
20267                            .iter()
20268                            .map(|range| range.clone().to_display_points(&snapshot))
20269                            .collect(),
20270                    )
20271                })
20272                .collect()
20273        })
20274    }
20275
20276    #[cfg(feature = "test-support")]
20277    pub fn all_text_background_highlights(
20278        &self,
20279        window: &mut Window,
20280        cx: &mut Context<Self>,
20281    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20282        let snapshot = self.snapshot(window, cx);
20283        let buffer = &snapshot.buffer_snapshot;
20284        let start = buffer.anchor_before(0);
20285        let end = buffer.anchor_after(buffer.len());
20286        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20287    }
20288
20289    #[cfg(any(test, feature = "test-support"))]
20290    pub fn sorted_background_highlights_in_range(
20291        &self,
20292        search_range: Range<Anchor>,
20293        display_snapshot: &DisplaySnapshot,
20294        theme: &Theme,
20295    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20296        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20297        res.sort_by(|a, b| {
20298            a.0.start
20299                .cmp(&b.0.start)
20300                .then_with(|| a.0.end.cmp(&b.0.end))
20301                .then_with(|| a.1.cmp(&b.1))
20302        });
20303        res
20304    }
20305
20306    #[cfg(feature = "test-support")]
20307    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20308        let snapshot = self.buffer().read(cx).snapshot(cx);
20309
20310        let highlights = self
20311            .background_highlights
20312            .get(&HighlightKey::Type(TypeId::of::<
20313                items::BufferSearchHighlights,
20314            >()));
20315
20316        if let Some((_color, ranges)) = highlights {
20317            ranges
20318                .iter()
20319                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20320                .collect_vec()
20321        } else {
20322            vec![]
20323        }
20324    }
20325
20326    fn document_highlights_for_position<'a>(
20327        &'a self,
20328        position: Anchor,
20329        buffer: &'a MultiBufferSnapshot,
20330    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20331        let read_highlights = self
20332            .background_highlights
20333            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20334            .map(|h| &h.1);
20335        let write_highlights = self
20336            .background_highlights
20337            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20338            .map(|h| &h.1);
20339        let left_position = position.bias_left(buffer);
20340        let right_position = position.bias_right(buffer);
20341        read_highlights
20342            .into_iter()
20343            .chain(write_highlights)
20344            .flat_map(move |ranges| {
20345                let start_ix = match ranges.binary_search_by(|probe| {
20346                    let cmp = probe.end.cmp(&left_position, buffer);
20347                    if cmp.is_ge() {
20348                        Ordering::Greater
20349                    } else {
20350                        Ordering::Less
20351                    }
20352                }) {
20353                    Ok(i) | Err(i) => i,
20354                };
20355
20356                ranges[start_ix..]
20357                    .iter()
20358                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20359            })
20360    }
20361
20362    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20363        self.background_highlights
20364            .get(&HighlightKey::Type(TypeId::of::<T>()))
20365            .is_some_and(|(_, highlights)| !highlights.is_empty())
20366    }
20367
20368    /// Returns all background highlights for a given range.
20369    ///
20370    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20371    pub fn background_highlights_in_range(
20372        &self,
20373        search_range: Range<Anchor>,
20374        display_snapshot: &DisplaySnapshot,
20375        theme: &Theme,
20376    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20377        let mut results = Vec::new();
20378        for (color_fetcher, ranges) in self.background_highlights.values() {
20379            let color = color_fetcher(theme);
20380            let start_ix = match ranges.binary_search_by(|probe| {
20381                let cmp = probe
20382                    .end
20383                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20384                if cmp.is_gt() {
20385                    Ordering::Greater
20386                } else {
20387                    Ordering::Less
20388                }
20389            }) {
20390                Ok(i) | Err(i) => i,
20391            };
20392            for range in &ranges[start_ix..] {
20393                if range
20394                    .start
20395                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20396                    .is_ge()
20397                {
20398                    break;
20399                }
20400
20401                let start = range.start.to_display_point(display_snapshot);
20402                let end = range.end.to_display_point(display_snapshot);
20403                results.push((start..end, color))
20404            }
20405        }
20406        results
20407    }
20408
20409    pub fn gutter_highlights_in_range(
20410        &self,
20411        search_range: Range<Anchor>,
20412        display_snapshot: &DisplaySnapshot,
20413        cx: &App,
20414    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20415        let mut results = Vec::new();
20416        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20417            let color = color_fetcher(cx);
20418            let start_ix = match ranges.binary_search_by(|probe| {
20419                let cmp = probe
20420                    .end
20421                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20422                if cmp.is_gt() {
20423                    Ordering::Greater
20424                } else {
20425                    Ordering::Less
20426                }
20427            }) {
20428                Ok(i) | Err(i) => i,
20429            };
20430            for range in &ranges[start_ix..] {
20431                if range
20432                    .start
20433                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20434                    .is_ge()
20435                {
20436                    break;
20437                }
20438
20439                let start = range.start.to_display_point(display_snapshot);
20440                let end = range.end.to_display_point(display_snapshot);
20441                results.push((start..end, color))
20442            }
20443        }
20444        results
20445    }
20446
20447    /// Get the text ranges corresponding to the redaction query
20448    pub fn redacted_ranges(
20449        &self,
20450        search_range: Range<Anchor>,
20451        display_snapshot: &DisplaySnapshot,
20452        cx: &App,
20453    ) -> Vec<Range<DisplayPoint>> {
20454        display_snapshot
20455            .buffer_snapshot
20456            .redacted_ranges(search_range, |file| {
20457                if let Some(file) = file {
20458                    file.is_private()
20459                        && EditorSettings::get(
20460                            Some(SettingsLocation {
20461                                worktree_id: file.worktree_id(cx),
20462                                path: file.path().as_ref(),
20463                            }),
20464                            cx,
20465                        )
20466                        .redact_private_values
20467                } else {
20468                    false
20469                }
20470            })
20471            .map(|range| {
20472                range.start.to_display_point(display_snapshot)
20473                    ..range.end.to_display_point(display_snapshot)
20474            })
20475            .collect()
20476    }
20477
20478    pub fn highlight_text_key<T: 'static>(
20479        &mut self,
20480        key: usize,
20481        ranges: Vec<Range<Anchor>>,
20482        style: HighlightStyle,
20483        cx: &mut Context<Self>,
20484    ) {
20485        self.display_map.update(cx, |map, _| {
20486            map.highlight_text(
20487                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20488                ranges,
20489                style,
20490            );
20491        });
20492        cx.notify();
20493    }
20494
20495    pub fn highlight_text<T: 'static>(
20496        &mut self,
20497        ranges: Vec<Range<Anchor>>,
20498        style: HighlightStyle,
20499        cx: &mut Context<Self>,
20500    ) {
20501        self.display_map.update(cx, |map, _| {
20502            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20503        });
20504        cx.notify();
20505    }
20506
20507    pub(crate) fn highlight_inlays<T: 'static>(
20508        &mut self,
20509        highlights: Vec<InlayHighlight>,
20510        style: HighlightStyle,
20511        cx: &mut Context<Self>,
20512    ) {
20513        self.display_map.update(cx, |map, _| {
20514            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20515        });
20516        cx.notify();
20517    }
20518
20519    pub fn text_highlights<'a, T: 'static>(
20520        &'a self,
20521        cx: &'a App,
20522    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20523        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20524    }
20525
20526    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20527        let cleared = self
20528            .display_map
20529            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20530        if cleared {
20531            cx.notify();
20532        }
20533    }
20534
20535    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20536        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20537            && self.focus_handle.is_focused(window)
20538    }
20539
20540    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20541        self.show_cursor_when_unfocused = is_enabled;
20542        cx.notify();
20543    }
20544
20545    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20546        cx.notify();
20547    }
20548
20549    fn on_debug_session_event(
20550        &mut self,
20551        _session: Entity<Session>,
20552        event: &SessionEvent,
20553        cx: &mut Context<Self>,
20554    ) {
20555        if let SessionEvent::InvalidateInlineValue = event {
20556            self.refresh_inline_values(cx);
20557        }
20558    }
20559
20560    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20561        let Some(project) = self.project.clone() else {
20562            return;
20563        };
20564
20565        if !self.inline_value_cache.enabled {
20566            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20567            self.splice_inlays(&inlays, Vec::new(), cx);
20568            return;
20569        }
20570
20571        let current_execution_position = self
20572            .highlighted_rows
20573            .get(&TypeId::of::<ActiveDebugLine>())
20574            .and_then(|lines| lines.last().map(|line| line.range.end));
20575
20576        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20577            let inline_values = editor
20578                .update(cx, |editor, cx| {
20579                    let Some(current_execution_position) = current_execution_position else {
20580                        return Some(Task::ready(Ok(Vec::new())));
20581                    };
20582
20583                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20584                        let snapshot = buffer.snapshot(cx);
20585
20586                        let excerpt = snapshot.excerpt_containing(
20587                            current_execution_position..current_execution_position,
20588                        )?;
20589
20590                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20591                    })?;
20592
20593                    let range =
20594                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20595
20596                    project.inline_values(buffer, range, cx)
20597                })
20598                .ok()
20599                .flatten()?
20600                .await
20601                .context("refreshing debugger inlays")
20602                .log_err()?;
20603
20604            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20605
20606            for (buffer_id, inline_value) in inline_values
20607                .into_iter()
20608                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20609            {
20610                buffer_inline_values
20611                    .entry(buffer_id)
20612                    .or_default()
20613                    .push(inline_value);
20614            }
20615
20616            editor
20617                .update(cx, |editor, cx| {
20618                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20619                    let mut new_inlays = Vec::default();
20620
20621                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20622                        let buffer_id = buffer_snapshot.remote_id();
20623                        buffer_inline_values
20624                            .get(&buffer_id)
20625                            .into_iter()
20626                            .flatten()
20627                            .for_each(|hint| {
20628                                let inlay = Inlay::debugger(
20629                                    post_inc(&mut editor.next_inlay_id),
20630                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20631                                    hint.text(),
20632                                );
20633                                if !inlay.text().chars().contains(&'\n') {
20634                                    new_inlays.push(inlay);
20635                                }
20636                            });
20637                    }
20638
20639                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20640                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20641
20642                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20643                })
20644                .ok()?;
20645            Some(())
20646        });
20647    }
20648
20649    fn on_buffer_event(
20650        &mut self,
20651        multibuffer: &Entity<MultiBuffer>,
20652        event: &multi_buffer::Event,
20653        window: &mut Window,
20654        cx: &mut Context<Self>,
20655    ) {
20656        match event {
20657            multi_buffer::Event::Edited {
20658                singleton_buffer_edited,
20659                edited_buffer,
20660            } => {
20661                self.scrollbar_marker_state.dirty = true;
20662                self.active_indent_guides_state.dirty = true;
20663                self.refresh_active_diagnostics(cx);
20664                self.refresh_code_actions(window, cx);
20665                self.refresh_selected_text_highlights(true, window, cx);
20666                self.refresh_single_line_folds(window, cx);
20667                refresh_matching_bracket_highlights(self, window, cx);
20668                if self.has_active_edit_prediction() {
20669                    self.update_visible_edit_prediction(window, cx);
20670                }
20671                if let Some(project) = self.project.as_ref()
20672                    && let Some(edited_buffer) = edited_buffer
20673                {
20674                    project.update(cx, |project, cx| {
20675                        self.registered_buffers
20676                            .entry(edited_buffer.read(cx).remote_id())
20677                            .or_insert_with(|| {
20678                                project.register_buffer_with_language_servers(edited_buffer, cx)
20679                            });
20680                    });
20681                }
20682                cx.emit(EditorEvent::BufferEdited);
20683                cx.emit(SearchEvent::MatchesInvalidated);
20684
20685                if let Some(buffer) = edited_buffer {
20686                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20687                }
20688
20689                if *singleton_buffer_edited {
20690                    if let Some(buffer) = edited_buffer
20691                        && buffer.read(cx).file().is_none()
20692                    {
20693                        cx.emit(EditorEvent::TitleChanged);
20694                    }
20695                    if let Some(project) = &self.project {
20696                        #[allow(clippy::mutable_key_type)]
20697                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20698                            multibuffer
20699                                .all_buffers()
20700                                .into_iter()
20701                                .filter_map(|buffer| {
20702                                    buffer.update(cx, |buffer, cx| {
20703                                        let language = buffer.language()?;
20704                                        let should_discard = project.update(cx, |project, cx| {
20705                                            project.is_local()
20706                                                && !project.has_language_servers_for(buffer, cx)
20707                                        });
20708                                        should_discard.not().then_some(language.clone())
20709                                    })
20710                                })
20711                                .collect::<HashSet<_>>()
20712                        });
20713                        if !languages_affected.is_empty() {
20714                            self.refresh_inlay_hints(
20715                                InlayHintRefreshReason::BufferEdited(languages_affected),
20716                                cx,
20717                            );
20718                        }
20719                    }
20720                }
20721
20722                let Some(project) = &self.project else { return };
20723                let (telemetry, is_via_ssh) = {
20724                    let project = project.read(cx);
20725                    let telemetry = project.client().telemetry().clone();
20726                    let is_via_ssh = project.is_via_remote_server();
20727                    (telemetry, is_via_ssh)
20728                };
20729                refresh_linked_ranges(self, window, cx);
20730                telemetry.log_edit_event("editor", is_via_ssh);
20731            }
20732            multi_buffer::Event::ExcerptsAdded {
20733                buffer,
20734                predecessor,
20735                excerpts,
20736            } => {
20737                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20738                let buffer_id = buffer.read(cx).remote_id();
20739                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20740                    && let Some(project) = &self.project
20741                {
20742                    update_uncommitted_diff_for_buffer(
20743                        cx.entity(),
20744                        project,
20745                        [buffer.clone()],
20746                        self.buffer.clone(),
20747                        cx,
20748                    )
20749                    .detach();
20750                }
20751                if self.active_diagnostics != ActiveDiagnostic::All {
20752                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20753                }
20754                cx.emit(EditorEvent::ExcerptsAdded {
20755                    buffer: buffer.clone(),
20756                    predecessor: *predecessor,
20757                    excerpts: excerpts.clone(),
20758                });
20759                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20760            }
20761            multi_buffer::Event::ExcerptsRemoved {
20762                ids,
20763                removed_buffer_ids,
20764            } => {
20765                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20766                let buffer = self.buffer.read(cx);
20767                self.registered_buffers
20768                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20769                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20770                cx.emit(EditorEvent::ExcerptsRemoved {
20771                    ids: ids.clone(),
20772                    removed_buffer_ids: removed_buffer_ids.clone(),
20773                });
20774            }
20775            multi_buffer::Event::ExcerptsEdited {
20776                excerpt_ids,
20777                buffer_ids,
20778            } => {
20779                self.display_map.update(cx, |map, cx| {
20780                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20781                });
20782                cx.emit(EditorEvent::ExcerptsEdited {
20783                    ids: excerpt_ids.clone(),
20784                });
20785            }
20786            multi_buffer::Event::ExcerptsExpanded { ids } => {
20787                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20788                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20789            }
20790            multi_buffer::Event::Reparsed(buffer_id) => {
20791                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20792                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20793
20794                cx.emit(EditorEvent::Reparsed(*buffer_id));
20795            }
20796            multi_buffer::Event::DiffHunksToggled => {
20797                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20798            }
20799            multi_buffer::Event::LanguageChanged(buffer_id) => {
20800                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20801                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20802                cx.emit(EditorEvent::Reparsed(*buffer_id));
20803                cx.notify();
20804            }
20805            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20806            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20807            multi_buffer::Event::FileHandleChanged
20808            | multi_buffer::Event::Reloaded
20809            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20810            multi_buffer::Event::DiagnosticsUpdated => {
20811                self.update_diagnostics_state(window, cx);
20812            }
20813            _ => {}
20814        };
20815    }
20816
20817    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20818        if !self.diagnostics_enabled() {
20819            return;
20820        }
20821        self.refresh_active_diagnostics(cx);
20822        self.refresh_inline_diagnostics(true, window, cx);
20823        self.scrollbar_marker_state.dirty = true;
20824        cx.notify();
20825    }
20826
20827    pub fn start_temporary_diff_override(&mut self) {
20828        self.load_diff_task.take();
20829        self.temporary_diff_override = true;
20830    }
20831
20832    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20833        self.temporary_diff_override = false;
20834        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20835        self.buffer.update(cx, |buffer, cx| {
20836            buffer.set_all_diff_hunks_collapsed(cx);
20837        });
20838
20839        if let Some(project) = self.project.clone() {
20840            self.load_diff_task = Some(
20841                update_uncommitted_diff_for_buffer(
20842                    cx.entity(),
20843                    &project,
20844                    self.buffer.read(cx).all_buffers(),
20845                    self.buffer.clone(),
20846                    cx,
20847                )
20848                .shared(),
20849            );
20850        }
20851    }
20852
20853    fn on_display_map_changed(
20854        &mut self,
20855        _: Entity<DisplayMap>,
20856        _: &mut Window,
20857        cx: &mut Context<Self>,
20858    ) {
20859        cx.notify();
20860    }
20861
20862    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20863        if self.diagnostics_enabled() {
20864            let new_severity = EditorSettings::get_global(cx)
20865                .diagnostics_max_severity
20866                .unwrap_or(DiagnosticSeverity::Hint);
20867            self.set_max_diagnostics_severity(new_severity, cx);
20868        }
20869        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20870        self.update_edit_prediction_settings(cx);
20871        self.refresh_edit_prediction(true, false, window, cx);
20872        self.refresh_inline_values(cx);
20873        self.refresh_inlay_hints(
20874            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20875                self.selections.newest_anchor().head(),
20876                &self.buffer.read(cx).snapshot(cx),
20877                cx,
20878            )),
20879            cx,
20880        );
20881
20882        let old_cursor_shape = self.cursor_shape;
20883        let old_show_breadcrumbs = self.show_breadcrumbs;
20884
20885        {
20886            let editor_settings = EditorSettings::get_global(cx);
20887            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20888            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20889            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20890            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20891        }
20892
20893        if old_cursor_shape != self.cursor_shape {
20894            cx.emit(EditorEvent::CursorShapeChanged);
20895        }
20896
20897        if old_show_breadcrumbs != self.show_breadcrumbs {
20898            cx.emit(EditorEvent::BreadcrumbsChanged);
20899        }
20900
20901        let project_settings = ProjectSettings::get_global(cx);
20902        self.serialize_dirty_buffers =
20903            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20904
20905        if self.mode.is_full() {
20906            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20907            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20908            if self.show_inline_diagnostics != show_inline_diagnostics {
20909                self.show_inline_diagnostics = show_inline_diagnostics;
20910                self.refresh_inline_diagnostics(false, window, cx);
20911            }
20912
20913            if self.git_blame_inline_enabled != inline_blame_enabled {
20914                self.toggle_git_blame_inline_internal(false, window, cx);
20915            }
20916
20917            let minimap_settings = EditorSettings::get_global(cx).minimap;
20918            if self.minimap_visibility != MinimapVisibility::Disabled {
20919                if self.minimap_visibility.settings_visibility()
20920                    != minimap_settings.minimap_enabled()
20921                {
20922                    self.set_minimap_visibility(
20923                        MinimapVisibility::for_mode(self.mode(), cx),
20924                        window,
20925                        cx,
20926                    );
20927                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20928                    minimap_entity.update(cx, |minimap_editor, cx| {
20929                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20930                    })
20931                }
20932            }
20933        }
20934
20935        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20936            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20937        }) {
20938            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20939                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20940            }
20941            self.refresh_colors(false, None, window, cx);
20942        }
20943
20944        cx.notify();
20945    }
20946
20947    pub fn set_searchable(&mut self, searchable: bool) {
20948        self.searchable = searchable;
20949    }
20950
20951    pub fn searchable(&self) -> bool {
20952        self.searchable
20953    }
20954
20955    fn open_proposed_changes_editor(
20956        &mut self,
20957        _: &OpenProposedChangesEditor,
20958        window: &mut Window,
20959        cx: &mut Context<Self>,
20960    ) {
20961        let Some(workspace) = self.workspace() else {
20962            cx.propagate();
20963            return;
20964        };
20965
20966        let selections = self.selections.all::<usize>(cx);
20967        let multi_buffer = self.buffer.read(cx);
20968        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20969        let mut new_selections_by_buffer = HashMap::default();
20970        for selection in selections {
20971            for (buffer, range, _) in
20972                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20973            {
20974                let mut range = range.to_point(buffer);
20975                range.start.column = 0;
20976                range.end.column = buffer.line_len(range.end.row);
20977                new_selections_by_buffer
20978                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20979                    .or_insert(Vec::new())
20980                    .push(range)
20981            }
20982        }
20983
20984        let proposed_changes_buffers = new_selections_by_buffer
20985            .into_iter()
20986            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20987            .collect::<Vec<_>>();
20988        let proposed_changes_editor = cx.new(|cx| {
20989            ProposedChangesEditor::new(
20990                "Proposed changes",
20991                proposed_changes_buffers,
20992                self.project.clone(),
20993                window,
20994                cx,
20995            )
20996        });
20997
20998        window.defer(cx, move |window, cx| {
20999            workspace.update(cx, |workspace, cx| {
21000                workspace.active_pane().update(cx, |pane, cx| {
21001                    pane.add_item(
21002                        Box::new(proposed_changes_editor),
21003                        true,
21004                        true,
21005                        None,
21006                        window,
21007                        cx,
21008                    );
21009                });
21010            });
21011        });
21012    }
21013
21014    pub fn open_excerpts_in_split(
21015        &mut self,
21016        _: &OpenExcerptsSplit,
21017        window: &mut Window,
21018        cx: &mut Context<Self>,
21019    ) {
21020        self.open_excerpts_common(None, true, window, cx)
21021    }
21022
21023    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21024        self.open_excerpts_common(None, false, window, cx)
21025    }
21026
21027    fn open_excerpts_common(
21028        &mut self,
21029        jump_data: Option<JumpData>,
21030        split: bool,
21031        window: &mut Window,
21032        cx: &mut Context<Self>,
21033    ) {
21034        let Some(workspace) = self.workspace() else {
21035            cx.propagate();
21036            return;
21037        };
21038
21039        if self.buffer.read(cx).is_singleton() {
21040            cx.propagate();
21041            return;
21042        }
21043
21044        let mut new_selections_by_buffer = HashMap::default();
21045        match &jump_data {
21046            Some(JumpData::MultiBufferPoint {
21047                excerpt_id,
21048                position,
21049                anchor,
21050                line_offset_from_top,
21051            }) => {
21052                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21053                if let Some(buffer) = multi_buffer_snapshot
21054                    .buffer_id_for_excerpt(*excerpt_id)
21055                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21056                {
21057                    let buffer_snapshot = buffer.read(cx).snapshot();
21058                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21059                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21060                    } else {
21061                        buffer_snapshot.clip_point(*position, Bias::Left)
21062                    };
21063                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21064                    new_selections_by_buffer.insert(
21065                        buffer,
21066                        (
21067                            vec![jump_to_offset..jump_to_offset],
21068                            Some(*line_offset_from_top),
21069                        ),
21070                    );
21071                }
21072            }
21073            Some(JumpData::MultiBufferRow {
21074                row,
21075                line_offset_from_top,
21076            }) => {
21077                let point = MultiBufferPoint::new(row.0, 0);
21078                if let Some((buffer, buffer_point, _)) =
21079                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21080                {
21081                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21082                    new_selections_by_buffer
21083                        .entry(buffer)
21084                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21085                        .0
21086                        .push(buffer_offset..buffer_offset)
21087                }
21088            }
21089            None => {
21090                let selections = self.selections.all::<usize>(cx);
21091                let multi_buffer = self.buffer.read(cx);
21092                for selection in selections {
21093                    for (snapshot, range, _, anchor) in multi_buffer
21094                        .snapshot(cx)
21095                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21096                    {
21097                        if let Some(anchor) = anchor {
21098                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21099                            else {
21100                                continue;
21101                            };
21102                            let offset = text::ToOffset::to_offset(
21103                                &anchor.text_anchor,
21104                                &buffer_handle.read(cx).snapshot(),
21105                            );
21106                            let range = offset..offset;
21107                            new_selections_by_buffer
21108                                .entry(buffer_handle)
21109                                .or_insert((Vec::new(), None))
21110                                .0
21111                                .push(range)
21112                        } else {
21113                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21114                            else {
21115                                continue;
21116                            };
21117                            new_selections_by_buffer
21118                                .entry(buffer_handle)
21119                                .or_insert((Vec::new(), None))
21120                                .0
21121                                .push(range)
21122                        }
21123                    }
21124                }
21125            }
21126        }
21127
21128        new_selections_by_buffer
21129            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21130
21131        if new_selections_by_buffer.is_empty() {
21132            return;
21133        }
21134
21135        // We defer the pane interaction because we ourselves are a workspace item
21136        // and activating a new item causes the pane to call a method on us reentrantly,
21137        // which panics if we're on the stack.
21138        window.defer(cx, move |window, cx| {
21139            workspace.update(cx, |workspace, cx| {
21140                let pane = if split {
21141                    workspace.adjacent_pane(window, cx)
21142                } else {
21143                    workspace.active_pane().clone()
21144                };
21145
21146                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21147                    let editor = buffer
21148                        .read(cx)
21149                        .file()
21150                        .is_none()
21151                        .then(|| {
21152                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21153                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21154                            // Instead, we try to activate the existing editor in the pane first.
21155                            let (editor, pane_item_index) =
21156                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21157                                    let editor = item.downcast::<Editor>()?;
21158                                    let singleton_buffer =
21159                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21160                                    if singleton_buffer == buffer {
21161                                        Some((editor, i))
21162                                    } else {
21163                                        None
21164                                    }
21165                                })?;
21166                            pane.update(cx, |pane, cx| {
21167                                pane.activate_item(pane_item_index, true, true, window, cx)
21168                            });
21169                            Some(editor)
21170                        })
21171                        .flatten()
21172                        .unwrap_or_else(|| {
21173                            workspace.open_project_item::<Self>(
21174                                pane.clone(),
21175                                buffer,
21176                                true,
21177                                true,
21178                                window,
21179                                cx,
21180                            )
21181                        });
21182
21183                    editor.update(cx, |editor, cx| {
21184                        let autoscroll = match scroll_offset {
21185                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21186                            None => Autoscroll::newest(),
21187                        };
21188                        let nav_history = editor.nav_history.take();
21189                        editor.change_selections(
21190                            SelectionEffects::scroll(autoscroll),
21191                            window,
21192                            cx,
21193                            |s| {
21194                                s.select_ranges(ranges);
21195                            },
21196                        );
21197                        editor.nav_history = nav_history;
21198                    });
21199                }
21200            })
21201        });
21202    }
21203
21204    // For now, don't allow opening excerpts in buffers that aren't backed by
21205    // regular project files.
21206    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21207        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21208    }
21209
21210    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21211        let snapshot = self.buffer.read(cx).read(cx);
21212        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21213        Some(
21214            ranges
21215                .iter()
21216                .map(move |range| {
21217                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21218                })
21219                .collect(),
21220        )
21221    }
21222
21223    fn selection_replacement_ranges(
21224        &self,
21225        range: Range<OffsetUtf16>,
21226        cx: &mut App,
21227    ) -> Vec<Range<OffsetUtf16>> {
21228        let selections = self.selections.all::<OffsetUtf16>(cx);
21229        let newest_selection = selections
21230            .iter()
21231            .max_by_key(|selection| selection.id)
21232            .unwrap();
21233        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21234        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21235        let snapshot = self.buffer.read(cx).read(cx);
21236        selections
21237            .into_iter()
21238            .map(|mut selection| {
21239                selection.start.0 =
21240                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21241                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21242                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21243                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21244            })
21245            .collect()
21246    }
21247
21248    fn report_editor_event(
21249        &self,
21250        reported_event: ReportEditorEvent,
21251        file_extension: Option<String>,
21252        cx: &App,
21253    ) {
21254        if cfg!(any(test, feature = "test-support")) {
21255            return;
21256        }
21257
21258        let Some(project) = &self.project else { return };
21259
21260        // If None, we are in a file without an extension
21261        let file = self
21262            .buffer
21263            .read(cx)
21264            .as_singleton()
21265            .and_then(|b| b.read(cx).file());
21266        let file_extension = file_extension.or(file
21267            .as_ref()
21268            .and_then(|file| Path::new(file.file_name(cx)).extension())
21269            .and_then(|e| e.to_str())
21270            .map(|a| a.to_string()));
21271
21272        let vim_mode = vim_enabled(cx);
21273
21274        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21275        let copilot_enabled = edit_predictions_provider
21276            == language::language_settings::EditPredictionProvider::Copilot;
21277        let copilot_enabled_for_language = self
21278            .buffer
21279            .read(cx)
21280            .language_settings(cx)
21281            .show_edit_predictions;
21282
21283        let project = project.read(cx);
21284        let event_type = reported_event.event_type();
21285
21286        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21287            telemetry::event!(
21288                event_type,
21289                type = if auto_saved {"autosave"} else {"manual"},
21290                file_extension,
21291                vim_mode,
21292                copilot_enabled,
21293                copilot_enabled_for_language,
21294                edit_predictions_provider,
21295                is_via_ssh = project.is_via_remote_server(),
21296            );
21297        } else {
21298            telemetry::event!(
21299                event_type,
21300                file_extension,
21301                vim_mode,
21302                copilot_enabled,
21303                copilot_enabled_for_language,
21304                edit_predictions_provider,
21305                is_via_ssh = project.is_via_remote_server(),
21306            );
21307        };
21308    }
21309
21310    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21311    /// with each line being an array of {text, highlight} objects.
21312    fn copy_highlight_json(
21313        &mut self,
21314        _: &CopyHighlightJson,
21315        window: &mut Window,
21316        cx: &mut Context<Self>,
21317    ) {
21318        #[derive(Serialize)]
21319        struct Chunk<'a> {
21320            text: String,
21321            highlight: Option<&'a str>,
21322        }
21323
21324        let snapshot = self.buffer.read(cx).snapshot(cx);
21325        let range = self
21326            .selected_text_range(false, window, cx)
21327            .and_then(|selection| {
21328                if selection.range.is_empty() {
21329                    None
21330                } else {
21331                    Some(selection.range)
21332                }
21333            })
21334            .unwrap_or_else(|| 0..snapshot.len());
21335
21336        let chunks = snapshot.chunks(range, true);
21337        let mut lines = Vec::new();
21338        let mut line: VecDeque<Chunk> = VecDeque::new();
21339
21340        let Some(style) = self.style.as_ref() else {
21341            return;
21342        };
21343
21344        for chunk in chunks {
21345            let highlight = chunk
21346                .syntax_highlight_id
21347                .and_then(|id| id.name(&style.syntax));
21348            let mut chunk_lines = chunk.text.split('\n').peekable();
21349            while let Some(text) = chunk_lines.next() {
21350                let mut merged_with_last_token = false;
21351                if let Some(last_token) = line.back_mut()
21352                    && last_token.highlight == highlight
21353                {
21354                    last_token.text.push_str(text);
21355                    merged_with_last_token = true;
21356                }
21357
21358                if !merged_with_last_token {
21359                    line.push_back(Chunk {
21360                        text: text.into(),
21361                        highlight,
21362                    });
21363                }
21364
21365                if chunk_lines.peek().is_some() {
21366                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21367                        line.pop_front();
21368                    }
21369                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21370                        line.pop_back();
21371                    }
21372
21373                    lines.push(mem::take(&mut line));
21374                }
21375            }
21376        }
21377
21378        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21379            return;
21380        };
21381        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21382    }
21383
21384    pub fn open_context_menu(
21385        &mut self,
21386        _: &OpenContextMenu,
21387        window: &mut Window,
21388        cx: &mut Context<Self>,
21389    ) {
21390        self.request_autoscroll(Autoscroll::newest(), cx);
21391        let position = self.selections.newest_display(cx).start;
21392        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21393    }
21394
21395    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21396        &self.inlay_hint_cache
21397    }
21398
21399    pub fn replay_insert_event(
21400        &mut self,
21401        text: &str,
21402        relative_utf16_range: Option<Range<isize>>,
21403        window: &mut Window,
21404        cx: &mut Context<Self>,
21405    ) {
21406        if !self.input_enabled {
21407            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21408            return;
21409        }
21410        if let Some(relative_utf16_range) = relative_utf16_range {
21411            let selections = self.selections.all::<OffsetUtf16>(cx);
21412            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21413                let new_ranges = selections.into_iter().map(|range| {
21414                    let start = OffsetUtf16(
21415                        range
21416                            .head()
21417                            .0
21418                            .saturating_add_signed(relative_utf16_range.start),
21419                    );
21420                    let end = OffsetUtf16(
21421                        range
21422                            .head()
21423                            .0
21424                            .saturating_add_signed(relative_utf16_range.end),
21425                    );
21426                    start..end
21427                });
21428                s.select_ranges(new_ranges);
21429            });
21430        }
21431
21432        self.handle_input(text, window, cx);
21433    }
21434
21435    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21436        let Some(provider) = self.semantics_provider.as_ref() else {
21437            return false;
21438        };
21439
21440        let mut supports = false;
21441        self.buffer().update(cx, |this, cx| {
21442            this.for_each_buffer(|buffer| {
21443                supports |= provider.supports_inlay_hints(buffer, cx);
21444            });
21445        });
21446
21447        supports
21448    }
21449
21450    pub fn is_focused(&self, window: &Window) -> bool {
21451        self.focus_handle.is_focused(window)
21452    }
21453
21454    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21455        cx.emit(EditorEvent::Focused);
21456
21457        if let Some(descendant) = self
21458            .last_focused_descendant
21459            .take()
21460            .and_then(|descendant| descendant.upgrade())
21461        {
21462            window.focus(&descendant);
21463        } else {
21464            if let Some(blame) = self.blame.as_ref() {
21465                blame.update(cx, GitBlame::focus)
21466            }
21467
21468            self.blink_manager.update(cx, BlinkManager::enable);
21469            self.show_cursor_names(window, cx);
21470            self.buffer.update(cx, |buffer, cx| {
21471                buffer.finalize_last_transaction(cx);
21472                if self.leader_id.is_none() {
21473                    buffer.set_active_selections(
21474                        &self.selections.disjoint_anchors_arc(),
21475                        self.selections.line_mode(),
21476                        self.cursor_shape,
21477                        cx,
21478                    );
21479                }
21480            });
21481        }
21482    }
21483
21484    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21485        cx.emit(EditorEvent::FocusedIn)
21486    }
21487
21488    fn handle_focus_out(
21489        &mut self,
21490        event: FocusOutEvent,
21491        _window: &mut Window,
21492        cx: &mut Context<Self>,
21493    ) {
21494        if event.blurred != self.focus_handle {
21495            self.last_focused_descendant = Some(event.blurred);
21496        }
21497        self.selection_drag_state = SelectionDragState::None;
21498        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21499    }
21500
21501    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21502        self.blink_manager.update(cx, BlinkManager::disable);
21503        self.buffer
21504            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21505
21506        if let Some(blame) = self.blame.as_ref() {
21507            blame.update(cx, GitBlame::blur)
21508        }
21509        if !self.hover_state.focused(window, cx) {
21510            hide_hover(self, cx);
21511        }
21512        if !self
21513            .context_menu
21514            .borrow()
21515            .as_ref()
21516            .is_some_and(|context_menu| context_menu.focused(window, cx))
21517        {
21518            self.hide_context_menu(window, cx);
21519        }
21520        self.take_active_edit_prediction(cx);
21521        cx.emit(EditorEvent::Blurred);
21522        cx.notify();
21523    }
21524
21525    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21526        let mut pending: String = window
21527            .pending_input_keystrokes()
21528            .into_iter()
21529            .flatten()
21530            .filter_map(|keystroke| {
21531                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21532                    keystroke.key_char.clone()
21533                } else {
21534                    None
21535                }
21536            })
21537            .collect();
21538
21539        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21540            pending = "".to_string();
21541        }
21542
21543        let existing_pending = self
21544            .text_highlights::<PendingInput>(cx)
21545            .map(|(_, ranges)| ranges.to_vec());
21546        if existing_pending.is_none() && pending.is_empty() {
21547            return;
21548        }
21549        let transaction =
21550            self.transact(window, cx, |this, window, cx| {
21551                let selections = this.selections.all::<usize>(cx);
21552                let edits = selections
21553                    .iter()
21554                    .map(|selection| (selection.end..selection.end, pending.clone()));
21555                this.edit(edits, cx);
21556                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21557                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21558                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21559                    }));
21560                });
21561                if let Some(existing_ranges) = existing_pending {
21562                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21563                    this.edit(edits, cx);
21564                }
21565            });
21566
21567        let snapshot = self.snapshot(window, cx);
21568        let ranges = self
21569            .selections
21570            .all::<usize>(cx)
21571            .into_iter()
21572            .map(|selection| {
21573                snapshot.buffer_snapshot.anchor_after(selection.end)
21574                    ..snapshot
21575                        .buffer_snapshot
21576                        .anchor_before(selection.end + pending.len())
21577            })
21578            .collect();
21579
21580        if pending.is_empty() {
21581            self.clear_highlights::<PendingInput>(cx);
21582        } else {
21583            self.highlight_text::<PendingInput>(
21584                ranges,
21585                HighlightStyle {
21586                    underline: Some(UnderlineStyle {
21587                        thickness: px(1.),
21588                        color: None,
21589                        wavy: false,
21590                    }),
21591                    ..Default::default()
21592                },
21593                cx,
21594            );
21595        }
21596
21597        self.ime_transaction = self.ime_transaction.or(transaction);
21598        if let Some(transaction) = self.ime_transaction {
21599            self.buffer.update(cx, |buffer, cx| {
21600                buffer.group_until_transaction(transaction, cx);
21601            });
21602        }
21603
21604        if self.text_highlights::<PendingInput>(cx).is_none() {
21605            self.ime_transaction.take();
21606        }
21607    }
21608
21609    pub fn register_action_renderer(
21610        &mut self,
21611        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21612    ) -> Subscription {
21613        let id = self.next_editor_action_id.post_inc();
21614        self.editor_actions
21615            .borrow_mut()
21616            .insert(id, Box::new(listener));
21617
21618        let editor_actions = self.editor_actions.clone();
21619        Subscription::new(move || {
21620            editor_actions.borrow_mut().remove(&id);
21621        })
21622    }
21623
21624    pub fn register_action<A: Action>(
21625        &mut self,
21626        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21627    ) -> Subscription {
21628        let id = self.next_editor_action_id.post_inc();
21629        let listener = Arc::new(listener);
21630        self.editor_actions.borrow_mut().insert(
21631            id,
21632            Box::new(move |_, window, _| {
21633                let listener = listener.clone();
21634                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21635                    let action = action.downcast_ref().unwrap();
21636                    if phase == DispatchPhase::Bubble {
21637                        listener(action, window, cx)
21638                    }
21639                })
21640            }),
21641        );
21642
21643        let editor_actions = self.editor_actions.clone();
21644        Subscription::new(move || {
21645            editor_actions.borrow_mut().remove(&id);
21646        })
21647    }
21648
21649    pub fn file_header_size(&self) -> u32 {
21650        FILE_HEADER_HEIGHT
21651    }
21652
21653    pub fn restore(
21654        &mut self,
21655        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21656        window: &mut Window,
21657        cx: &mut Context<Self>,
21658    ) {
21659        let workspace = self.workspace();
21660        let project = self.project();
21661        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21662            let mut tasks = Vec::new();
21663            for (buffer_id, changes) in revert_changes {
21664                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21665                    buffer.update(cx, |buffer, cx| {
21666                        buffer.edit(
21667                            changes
21668                                .into_iter()
21669                                .map(|(range, text)| (range, text.to_string())),
21670                            None,
21671                            cx,
21672                        );
21673                    });
21674
21675                    if let Some(project) =
21676                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21677                    {
21678                        project.update(cx, |project, cx| {
21679                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21680                        })
21681                    }
21682                }
21683            }
21684            tasks
21685        });
21686        cx.spawn_in(window, async move |_, cx| {
21687            for (buffer, task) in save_tasks {
21688                let result = task.await;
21689                if result.is_err() {
21690                    let Some(path) = buffer
21691                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21692                        .ok()
21693                    else {
21694                        continue;
21695                    };
21696                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21697                        let Some(task) = cx
21698                            .update_window_entity(workspace, |workspace, window, cx| {
21699                                workspace
21700                                    .open_path_preview(path, None, false, false, false, window, cx)
21701                            })
21702                            .ok()
21703                        else {
21704                            continue;
21705                        };
21706                        task.await.log_err();
21707                    }
21708                }
21709            }
21710        })
21711        .detach();
21712        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21713            selections.refresh()
21714        });
21715    }
21716
21717    pub fn to_pixel_point(
21718        &self,
21719        source: multi_buffer::Anchor,
21720        editor_snapshot: &EditorSnapshot,
21721        window: &mut Window,
21722    ) -> Option<gpui::Point<Pixels>> {
21723        let source_point = source.to_display_point(editor_snapshot);
21724        self.display_to_pixel_point(source_point, editor_snapshot, window)
21725    }
21726
21727    pub fn display_to_pixel_point(
21728        &self,
21729        source: DisplayPoint,
21730        editor_snapshot: &EditorSnapshot,
21731        window: &mut Window,
21732    ) -> Option<gpui::Point<Pixels>> {
21733        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21734        let text_layout_details = self.text_layout_details(window);
21735        let scroll_top = text_layout_details
21736            .scroll_anchor
21737            .scroll_position(editor_snapshot)
21738            .y;
21739
21740        if source.row().as_f32() < scroll_top.floor() {
21741            return None;
21742        }
21743        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21744        let source_y = line_height * (source.row().as_f32() - scroll_top);
21745        Some(gpui::Point::new(source_x, source_y))
21746    }
21747
21748    pub fn has_visible_completions_menu(&self) -> bool {
21749        !self.edit_prediction_preview_is_active()
21750            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21751                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21752            })
21753    }
21754
21755    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21756        if self.mode.is_minimap() {
21757            return;
21758        }
21759        self.addons
21760            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21761    }
21762
21763    pub fn unregister_addon<T: Addon>(&mut self) {
21764        self.addons.remove(&std::any::TypeId::of::<T>());
21765    }
21766
21767    pub fn addon<T: Addon>(&self) -> Option<&T> {
21768        let type_id = std::any::TypeId::of::<T>();
21769        self.addons
21770            .get(&type_id)
21771            .and_then(|item| item.to_any().downcast_ref::<T>())
21772    }
21773
21774    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21775        let type_id = std::any::TypeId::of::<T>();
21776        self.addons
21777            .get_mut(&type_id)
21778            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21779    }
21780
21781    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21782        let text_layout_details = self.text_layout_details(window);
21783        let style = &text_layout_details.editor_style;
21784        let font_id = window.text_system().resolve_font(&style.text.font());
21785        let font_size = style.text.font_size.to_pixels(window.rem_size());
21786        let line_height = style.text.line_height_in_pixels(window.rem_size());
21787        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21788        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21789
21790        CharacterDimensions {
21791            em_width,
21792            em_advance,
21793            line_height,
21794        }
21795    }
21796
21797    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21798        self.load_diff_task.clone()
21799    }
21800
21801    fn read_metadata_from_db(
21802        &mut self,
21803        item_id: u64,
21804        workspace_id: WorkspaceId,
21805        window: &mut Window,
21806        cx: &mut Context<Editor>,
21807    ) {
21808        if self.is_singleton(cx)
21809            && !self.mode.is_minimap()
21810            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21811        {
21812            let buffer_snapshot = OnceCell::new();
21813
21814            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21815                && !folds.is_empty()
21816            {
21817                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21818                self.fold_ranges(
21819                    folds
21820                        .into_iter()
21821                        .map(|(start, end)| {
21822                            snapshot.clip_offset(start, Bias::Left)
21823                                ..snapshot.clip_offset(end, Bias::Right)
21824                        })
21825                        .collect(),
21826                    false,
21827                    window,
21828                    cx,
21829                );
21830            }
21831
21832            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21833                && !selections.is_empty()
21834            {
21835                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21836                // skip adding the initial selection to selection history
21837                self.selection_history.mode = SelectionHistoryMode::Skipping;
21838                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21839                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21840                        snapshot.clip_offset(start, Bias::Left)
21841                            ..snapshot.clip_offset(end, Bias::Right)
21842                    }));
21843                });
21844                self.selection_history.mode = SelectionHistoryMode::Normal;
21845            };
21846        }
21847
21848        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21849    }
21850
21851    fn update_lsp_data(
21852        &mut self,
21853        ignore_cache: bool,
21854        for_buffer: Option<BufferId>,
21855        window: &mut Window,
21856        cx: &mut Context<'_, Self>,
21857    ) {
21858        self.pull_diagnostics(for_buffer, window, cx);
21859        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21860    }
21861}
21862
21863fn edit_for_markdown_paste<'a>(
21864    buffer: &MultiBufferSnapshot,
21865    range: Range<usize>,
21866    to_insert: &'a str,
21867    url: Option<url::Url>,
21868) -> (Range<usize>, Cow<'a, str>) {
21869    if url.is_none() {
21870        return (range, Cow::Borrowed(to_insert));
21871    };
21872
21873    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21874
21875    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21876        Cow::Borrowed(to_insert)
21877    } else {
21878        Cow::Owned(format!("[{old_text}]({to_insert})"))
21879    };
21880    (range, new_text)
21881}
21882
21883fn vim_enabled(cx: &App) -> bool {
21884    vim_mode_setting::VimModeSetting::try_get(cx)
21885        .map(|vim_mode| vim_mode.0)
21886        .unwrap_or(false)
21887}
21888
21889fn process_completion_for_edit(
21890    completion: &Completion,
21891    intent: CompletionIntent,
21892    buffer: &Entity<Buffer>,
21893    cursor_position: &text::Anchor,
21894    cx: &mut Context<Editor>,
21895) -> CompletionEdit {
21896    let buffer = buffer.read(cx);
21897    let buffer_snapshot = buffer.snapshot();
21898    let (snippet, new_text) = if completion.is_snippet() {
21899        let mut snippet_source = completion.new_text.clone();
21900        // Workaround for typescript language server issues so that methods don't expand within
21901        // strings and functions with type expressions. The previous point is used because the query
21902        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21903        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
21904        let previous_point = if previous_point.column > 0 {
21905            cursor_position.to_previous_offset(&buffer_snapshot)
21906        } else {
21907            cursor_position.to_offset(&buffer_snapshot)
21908        };
21909        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21910            && scope.prefers_label_for_snippet_in_completion()
21911            && let Some(label) = completion.label()
21912            && matches!(
21913                completion.kind(),
21914                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21915            )
21916        {
21917            snippet_source = label;
21918        }
21919        match Snippet::parse(&snippet_source).log_err() {
21920            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21921            None => (None, completion.new_text.clone()),
21922        }
21923    } else {
21924        (None, completion.new_text.clone())
21925    };
21926
21927    let mut range_to_replace = {
21928        let replace_range = &completion.replace_range;
21929        if let CompletionSource::Lsp {
21930            insert_range: Some(insert_range),
21931            ..
21932        } = &completion.source
21933        {
21934            debug_assert_eq!(
21935                insert_range.start, replace_range.start,
21936                "insert_range and replace_range should start at the same position"
21937            );
21938            debug_assert!(
21939                insert_range
21940                    .start
21941                    .cmp(cursor_position, &buffer_snapshot)
21942                    .is_le(),
21943                "insert_range should start before or at cursor position"
21944            );
21945            debug_assert!(
21946                replace_range
21947                    .start
21948                    .cmp(cursor_position, &buffer_snapshot)
21949                    .is_le(),
21950                "replace_range should start before or at cursor position"
21951            );
21952
21953            let should_replace = match intent {
21954                CompletionIntent::CompleteWithInsert => false,
21955                CompletionIntent::CompleteWithReplace => true,
21956                CompletionIntent::Complete | CompletionIntent::Compose => {
21957                    let insert_mode =
21958                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21959                            .completions
21960                            .lsp_insert_mode;
21961                    match insert_mode {
21962                        LspInsertMode::Insert => false,
21963                        LspInsertMode::Replace => true,
21964                        LspInsertMode::ReplaceSubsequence => {
21965                            let mut text_to_replace = buffer.chars_for_range(
21966                                buffer.anchor_before(replace_range.start)
21967                                    ..buffer.anchor_after(replace_range.end),
21968                            );
21969                            let mut current_needle = text_to_replace.next();
21970                            for haystack_ch in completion.label.text.chars() {
21971                                if let Some(needle_ch) = current_needle
21972                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21973                                {
21974                                    current_needle = text_to_replace.next();
21975                                }
21976                            }
21977                            current_needle.is_none()
21978                        }
21979                        LspInsertMode::ReplaceSuffix => {
21980                            if replace_range
21981                                .end
21982                                .cmp(cursor_position, &buffer_snapshot)
21983                                .is_gt()
21984                            {
21985                                let range_after_cursor = *cursor_position..replace_range.end;
21986                                let text_after_cursor = buffer
21987                                    .text_for_range(
21988                                        buffer.anchor_before(range_after_cursor.start)
21989                                            ..buffer.anchor_after(range_after_cursor.end),
21990                                    )
21991                                    .collect::<String>()
21992                                    .to_ascii_lowercase();
21993                                completion
21994                                    .label
21995                                    .text
21996                                    .to_ascii_lowercase()
21997                                    .ends_with(&text_after_cursor)
21998                            } else {
21999                                true
22000                            }
22001                        }
22002                    }
22003                }
22004            };
22005
22006            if should_replace {
22007                replace_range.clone()
22008            } else {
22009                insert_range.clone()
22010            }
22011        } else {
22012            replace_range.clone()
22013        }
22014    };
22015
22016    if range_to_replace
22017        .end
22018        .cmp(cursor_position, &buffer_snapshot)
22019        .is_lt()
22020    {
22021        range_to_replace.end = *cursor_position;
22022    }
22023
22024    CompletionEdit {
22025        new_text,
22026        replace_range: range_to_replace.to_offset(buffer),
22027        snippet,
22028    }
22029}
22030
22031struct CompletionEdit {
22032    new_text: String,
22033    replace_range: Range<usize>,
22034    snippet: Option<Snippet>,
22035}
22036
22037fn insert_extra_newline_brackets(
22038    buffer: &MultiBufferSnapshot,
22039    range: Range<usize>,
22040    language: &language::LanguageScope,
22041) -> bool {
22042    let leading_whitespace_len = buffer
22043        .reversed_chars_at(range.start)
22044        .take_while(|c| c.is_whitespace() && *c != '\n')
22045        .map(|c| c.len_utf8())
22046        .sum::<usize>();
22047    let trailing_whitespace_len = buffer
22048        .chars_at(range.end)
22049        .take_while(|c| c.is_whitespace() && *c != '\n')
22050        .map(|c| c.len_utf8())
22051        .sum::<usize>();
22052    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22053
22054    language.brackets().any(|(pair, enabled)| {
22055        let pair_start = pair.start.trim_end();
22056        let pair_end = pair.end.trim_start();
22057
22058        enabled
22059            && pair.newline
22060            && buffer.contains_str_at(range.end, pair_end)
22061            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22062    })
22063}
22064
22065fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22066    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22067        [(buffer, range, _)] => (*buffer, range.clone()),
22068        _ => return false,
22069    };
22070    let pair = {
22071        let mut result: Option<BracketMatch> = None;
22072
22073        for pair in buffer
22074            .all_bracket_ranges(range.clone())
22075            .filter(move |pair| {
22076                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22077            })
22078        {
22079            let len = pair.close_range.end - pair.open_range.start;
22080
22081            if let Some(existing) = &result {
22082                let existing_len = existing.close_range.end - existing.open_range.start;
22083                if len > existing_len {
22084                    continue;
22085                }
22086            }
22087
22088            result = Some(pair);
22089        }
22090
22091        result
22092    };
22093    let Some(pair) = pair else {
22094        return false;
22095    };
22096    pair.newline_only
22097        && buffer
22098            .chars_for_range(pair.open_range.end..range.start)
22099            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22100            .all(|c| c.is_whitespace() && c != '\n')
22101}
22102
22103fn update_uncommitted_diff_for_buffer(
22104    editor: Entity<Editor>,
22105    project: &Entity<Project>,
22106    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22107    buffer: Entity<MultiBuffer>,
22108    cx: &mut App,
22109) -> Task<()> {
22110    let mut tasks = Vec::new();
22111    project.update(cx, |project, cx| {
22112        for buffer in buffers {
22113            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22114                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22115            }
22116        }
22117    });
22118    cx.spawn(async move |cx| {
22119        let diffs = future::join_all(tasks).await;
22120        if editor
22121            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22122            .unwrap_or(false)
22123        {
22124            return;
22125        }
22126
22127        buffer
22128            .update(cx, |buffer, cx| {
22129                for diff in diffs.into_iter().flatten() {
22130                    buffer.add_diff(diff, cx);
22131                }
22132            })
22133            .ok();
22134    })
22135}
22136
22137fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22138    let tab_size = tab_size.get() as usize;
22139    let mut width = offset;
22140
22141    for ch in text.chars() {
22142        width += if ch == '\t' {
22143            tab_size - (width % tab_size)
22144        } else {
22145            1
22146        };
22147    }
22148
22149    width - offset
22150}
22151
22152#[cfg(test)]
22153mod tests {
22154    use super::*;
22155
22156    #[test]
22157    fn test_string_size_with_expanded_tabs() {
22158        let nz = |val| NonZeroU32::new(val).unwrap();
22159        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22160        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22161        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22162        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22163        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22164        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22165        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22166        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22167    }
22168}
22169
22170/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22171struct WordBreakingTokenizer<'a> {
22172    input: &'a str,
22173}
22174
22175impl<'a> WordBreakingTokenizer<'a> {
22176    fn new(input: &'a str) -> Self {
22177        Self { input }
22178    }
22179}
22180
22181fn is_char_ideographic(ch: char) -> bool {
22182    use unicode_script::Script::*;
22183    use unicode_script::UnicodeScript;
22184    matches!(ch.script(), Han | Tangut | Yi)
22185}
22186
22187fn is_grapheme_ideographic(text: &str) -> bool {
22188    text.chars().any(is_char_ideographic)
22189}
22190
22191fn is_grapheme_whitespace(text: &str) -> bool {
22192    text.chars().any(|x| x.is_whitespace())
22193}
22194
22195fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22196    text.chars()
22197        .next()
22198        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22199}
22200
22201#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22202enum WordBreakToken<'a> {
22203    Word { token: &'a str, grapheme_len: usize },
22204    InlineWhitespace { token: &'a str, grapheme_len: usize },
22205    Newline,
22206}
22207
22208impl<'a> Iterator for WordBreakingTokenizer<'a> {
22209    /// Yields a span, the count of graphemes in the token, and whether it was
22210    /// whitespace. Note that it also breaks at word boundaries.
22211    type Item = WordBreakToken<'a>;
22212
22213    fn next(&mut self) -> Option<Self::Item> {
22214        use unicode_segmentation::UnicodeSegmentation;
22215        if self.input.is_empty() {
22216            return None;
22217        }
22218
22219        let mut iter = self.input.graphemes(true).peekable();
22220        let mut offset = 0;
22221        let mut grapheme_len = 0;
22222        if let Some(first_grapheme) = iter.next() {
22223            let is_newline = first_grapheme == "\n";
22224            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22225            offset += first_grapheme.len();
22226            grapheme_len += 1;
22227            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22228                if let Some(grapheme) = iter.peek().copied()
22229                    && should_stay_with_preceding_ideograph(grapheme)
22230                {
22231                    offset += grapheme.len();
22232                    grapheme_len += 1;
22233                }
22234            } else {
22235                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22236                let mut next_word_bound = words.peek().copied();
22237                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22238                    next_word_bound = words.next();
22239                }
22240                while let Some(grapheme) = iter.peek().copied() {
22241                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22242                        break;
22243                    };
22244                    if is_grapheme_whitespace(grapheme) != is_whitespace
22245                        || (grapheme == "\n") != is_newline
22246                    {
22247                        break;
22248                    };
22249                    offset += grapheme.len();
22250                    grapheme_len += 1;
22251                    iter.next();
22252                }
22253            }
22254            let token = &self.input[..offset];
22255            self.input = &self.input[offset..];
22256            if token == "\n" {
22257                Some(WordBreakToken::Newline)
22258            } else if is_whitespace {
22259                Some(WordBreakToken::InlineWhitespace {
22260                    token,
22261                    grapheme_len,
22262                })
22263            } else {
22264                Some(WordBreakToken::Word {
22265                    token,
22266                    grapheme_len,
22267                })
22268            }
22269        } else {
22270            None
22271        }
22272    }
22273}
22274
22275#[test]
22276fn test_word_breaking_tokenizer() {
22277    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22278        ("", &[]),
22279        ("  ", &[whitespace("  ", 2)]),
22280        ("Ʒ", &[word("Ʒ", 1)]),
22281        ("Ǽ", &[word("Ǽ", 1)]),
22282        ("", &[word("", 1)]),
22283        ("⋑⋑", &[word("⋑⋑", 2)]),
22284        (
22285            "原理,进而",
22286            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22287        ),
22288        (
22289            "hello world",
22290            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22291        ),
22292        (
22293            "hello, world",
22294            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22295        ),
22296        (
22297            "  hello world",
22298            &[
22299                whitespace("  ", 2),
22300                word("hello", 5),
22301                whitespace(" ", 1),
22302                word("world", 5),
22303            ],
22304        ),
22305        (
22306            "这是什么 \n 钢笔",
22307            &[
22308                word("", 1),
22309                word("", 1),
22310                word("", 1),
22311                word("", 1),
22312                whitespace(" ", 1),
22313                newline(),
22314                whitespace(" ", 1),
22315                word("", 1),
22316                word("", 1),
22317            ],
22318        ),
22319        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22320    ];
22321
22322    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22323        WordBreakToken::Word {
22324            token,
22325            grapheme_len,
22326        }
22327    }
22328
22329    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22330        WordBreakToken::InlineWhitespace {
22331            token,
22332            grapheme_len,
22333        }
22334    }
22335
22336    fn newline() -> WordBreakToken<'static> {
22337        WordBreakToken::Newline
22338    }
22339
22340    for (input, result) in tests {
22341        assert_eq!(
22342            WordBreakingTokenizer::new(input)
22343                .collect::<Vec<_>>()
22344                .as_slice(),
22345            *result,
22346        );
22347    }
22348}
22349
22350fn wrap_with_prefix(
22351    first_line_prefix: String,
22352    subsequent_lines_prefix: String,
22353    unwrapped_text: String,
22354    wrap_column: usize,
22355    tab_size: NonZeroU32,
22356    preserve_existing_whitespace: bool,
22357) -> String {
22358    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22359    let subsequent_lines_prefix_len =
22360        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22361    let mut wrapped_text = String::new();
22362    let mut current_line = first_line_prefix;
22363    let mut is_first_line = true;
22364
22365    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22366    let mut current_line_len = first_line_prefix_len;
22367    let mut in_whitespace = false;
22368    for token in tokenizer {
22369        let have_preceding_whitespace = in_whitespace;
22370        match token {
22371            WordBreakToken::Word {
22372                token,
22373                grapheme_len,
22374            } => {
22375                in_whitespace = false;
22376                let current_prefix_len = if is_first_line {
22377                    first_line_prefix_len
22378                } else {
22379                    subsequent_lines_prefix_len
22380                };
22381                if current_line_len + grapheme_len > wrap_column
22382                    && current_line_len != current_prefix_len
22383                {
22384                    wrapped_text.push_str(current_line.trim_end());
22385                    wrapped_text.push('\n');
22386                    is_first_line = false;
22387                    current_line = subsequent_lines_prefix.clone();
22388                    current_line_len = subsequent_lines_prefix_len;
22389                }
22390                current_line.push_str(token);
22391                current_line_len += grapheme_len;
22392            }
22393            WordBreakToken::InlineWhitespace {
22394                mut token,
22395                mut grapheme_len,
22396            } => {
22397                in_whitespace = true;
22398                if have_preceding_whitespace && !preserve_existing_whitespace {
22399                    continue;
22400                }
22401                if !preserve_existing_whitespace {
22402                    // Keep a single whitespace grapheme as-is
22403                    if let Some(first) =
22404                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22405                    {
22406                        token = first;
22407                    } else {
22408                        token = " ";
22409                    }
22410                    grapheme_len = 1;
22411                }
22412                let current_prefix_len = if is_first_line {
22413                    first_line_prefix_len
22414                } else {
22415                    subsequent_lines_prefix_len
22416                };
22417                if current_line_len + grapheme_len > wrap_column {
22418                    wrapped_text.push_str(current_line.trim_end());
22419                    wrapped_text.push('\n');
22420                    is_first_line = false;
22421                    current_line = subsequent_lines_prefix.clone();
22422                    current_line_len = subsequent_lines_prefix_len;
22423                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22424                    current_line.push_str(token);
22425                    current_line_len += grapheme_len;
22426                }
22427            }
22428            WordBreakToken::Newline => {
22429                in_whitespace = true;
22430                let current_prefix_len = if is_first_line {
22431                    first_line_prefix_len
22432                } else {
22433                    subsequent_lines_prefix_len
22434                };
22435                if preserve_existing_whitespace {
22436                    wrapped_text.push_str(current_line.trim_end());
22437                    wrapped_text.push('\n');
22438                    is_first_line = false;
22439                    current_line = subsequent_lines_prefix.clone();
22440                    current_line_len = subsequent_lines_prefix_len;
22441                } else if have_preceding_whitespace {
22442                    continue;
22443                } else if current_line_len + 1 > wrap_column
22444                    && current_line_len != current_prefix_len
22445                {
22446                    wrapped_text.push_str(current_line.trim_end());
22447                    wrapped_text.push('\n');
22448                    is_first_line = false;
22449                    current_line = subsequent_lines_prefix.clone();
22450                    current_line_len = subsequent_lines_prefix_len;
22451                } else if current_line_len != current_prefix_len {
22452                    current_line.push(' ');
22453                    current_line_len += 1;
22454                }
22455            }
22456        }
22457    }
22458
22459    if !current_line.is_empty() {
22460        wrapped_text.push_str(&current_line);
22461    }
22462    wrapped_text
22463}
22464
22465#[test]
22466fn test_wrap_with_prefix() {
22467    assert_eq!(
22468        wrap_with_prefix(
22469            "# ".to_string(),
22470            "# ".to_string(),
22471            "abcdefg".to_string(),
22472            4,
22473            NonZeroU32::new(4).unwrap(),
22474            false,
22475        ),
22476        "# abcdefg"
22477    );
22478    assert_eq!(
22479        wrap_with_prefix(
22480            "".to_string(),
22481            "".to_string(),
22482            "\thello world".to_string(),
22483            8,
22484            NonZeroU32::new(4).unwrap(),
22485            false,
22486        ),
22487        "hello\nworld"
22488    );
22489    assert_eq!(
22490        wrap_with_prefix(
22491            "// ".to_string(),
22492            "// ".to_string(),
22493            "xx \nyy zz aa bb cc".to_string(),
22494            12,
22495            NonZeroU32::new(4).unwrap(),
22496            false,
22497        ),
22498        "// xx yy zz\n// aa bb cc"
22499    );
22500    assert_eq!(
22501        wrap_with_prefix(
22502            String::new(),
22503            String::new(),
22504            "这是什么 \n 钢笔".to_string(),
22505            3,
22506            NonZeroU32::new(4).unwrap(),
22507            false,
22508        ),
22509        "这是什\n么 钢\n"
22510    );
22511    assert_eq!(
22512        wrap_with_prefix(
22513            String::new(),
22514            String::new(),
22515            format!("foo{}bar", '\u{2009}'), // thin space
22516            80,
22517            NonZeroU32::new(4).unwrap(),
22518            false,
22519        ),
22520        format!("foo{}bar", '\u{2009}')
22521    );
22522}
22523
22524pub trait CollaborationHub {
22525    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22526    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22527    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22528}
22529
22530impl CollaborationHub for Entity<Project> {
22531    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22532        self.read(cx).collaborators()
22533    }
22534
22535    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22536        self.read(cx).user_store().read(cx).participant_indices()
22537    }
22538
22539    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22540        let this = self.read(cx);
22541        let user_ids = this.collaborators().values().map(|c| c.user_id);
22542        this.user_store().read(cx).participant_names(user_ids, cx)
22543    }
22544}
22545
22546pub trait SemanticsProvider {
22547    fn hover(
22548        &self,
22549        buffer: &Entity<Buffer>,
22550        position: text::Anchor,
22551        cx: &mut App,
22552    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22553
22554    fn inline_values(
22555        &self,
22556        buffer_handle: Entity<Buffer>,
22557        range: Range<text::Anchor>,
22558        cx: &mut App,
22559    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22560
22561    fn inlay_hints(
22562        &self,
22563        buffer_handle: Entity<Buffer>,
22564        range: Range<text::Anchor>,
22565        cx: &mut App,
22566    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22567
22568    fn resolve_inlay_hint(
22569        &self,
22570        hint: InlayHint,
22571        buffer_handle: Entity<Buffer>,
22572        server_id: LanguageServerId,
22573        cx: &mut App,
22574    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22575
22576    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22577
22578    fn document_highlights(
22579        &self,
22580        buffer: &Entity<Buffer>,
22581        position: text::Anchor,
22582        cx: &mut App,
22583    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22584
22585    fn definitions(
22586        &self,
22587        buffer: &Entity<Buffer>,
22588        position: text::Anchor,
22589        kind: GotoDefinitionKind,
22590        cx: &mut App,
22591    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22592
22593    fn range_for_rename(
22594        &self,
22595        buffer: &Entity<Buffer>,
22596        position: text::Anchor,
22597        cx: &mut App,
22598    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22599
22600    fn perform_rename(
22601        &self,
22602        buffer: &Entity<Buffer>,
22603        position: text::Anchor,
22604        new_name: String,
22605        cx: &mut App,
22606    ) -> Option<Task<Result<ProjectTransaction>>>;
22607}
22608
22609pub trait CompletionProvider {
22610    fn completions(
22611        &self,
22612        excerpt_id: ExcerptId,
22613        buffer: &Entity<Buffer>,
22614        buffer_position: text::Anchor,
22615        trigger: CompletionContext,
22616        window: &mut Window,
22617        cx: &mut Context<Editor>,
22618    ) -> Task<Result<Vec<CompletionResponse>>>;
22619
22620    fn resolve_completions(
22621        &self,
22622        _buffer: Entity<Buffer>,
22623        _completion_indices: Vec<usize>,
22624        _completions: Rc<RefCell<Box<[Completion]>>>,
22625        _cx: &mut Context<Editor>,
22626    ) -> Task<Result<bool>> {
22627        Task::ready(Ok(false))
22628    }
22629
22630    fn apply_additional_edits_for_completion(
22631        &self,
22632        _buffer: Entity<Buffer>,
22633        _completions: Rc<RefCell<Box<[Completion]>>>,
22634        _completion_index: usize,
22635        _push_to_history: bool,
22636        _cx: &mut Context<Editor>,
22637    ) -> Task<Result<Option<language::Transaction>>> {
22638        Task::ready(Ok(None))
22639    }
22640
22641    fn is_completion_trigger(
22642        &self,
22643        buffer: &Entity<Buffer>,
22644        position: language::Anchor,
22645        text: &str,
22646        trigger_in_words: bool,
22647        menu_is_open: bool,
22648        cx: &mut Context<Editor>,
22649    ) -> bool;
22650
22651    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22652
22653    fn sort_completions(&self) -> bool {
22654        true
22655    }
22656
22657    fn filter_completions(&self) -> bool {
22658        true
22659    }
22660}
22661
22662pub trait CodeActionProvider {
22663    fn id(&self) -> Arc<str>;
22664
22665    fn code_actions(
22666        &self,
22667        buffer: &Entity<Buffer>,
22668        range: Range<text::Anchor>,
22669        window: &mut Window,
22670        cx: &mut App,
22671    ) -> Task<Result<Vec<CodeAction>>>;
22672
22673    fn apply_code_action(
22674        &self,
22675        buffer_handle: Entity<Buffer>,
22676        action: CodeAction,
22677        excerpt_id: ExcerptId,
22678        push_to_history: bool,
22679        window: &mut Window,
22680        cx: &mut App,
22681    ) -> Task<Result<ProjectTransaction>>;
22682}
22683
22684impl CodeActionProvider for Entity<Project> {
22685    fn id(&self) -> Arc<str> {
22686        "project".into()
22687    }
22688
22689    fn code_actions(
22690        &self,
22691        buffer: &Entity<Buffer>,
22692        range: Range<text::Anchor>,
22693        _window: &mut Window,
22694        cx: &mut App,
22695    ) -> Task<Result<Vec<CodeAction>>> {
22696        self.update(cx, |project, cx| {
22697            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22698            let code_actions = project.code_actions(buffer, range, None, cx);
22699            cx.background_spawn(async move {
22700                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22701                Ok(code_lens_actions
22702                    .context("code lens fetch")?
22703                    .into_iter()
22704                    .flatten()
22705                    .chain(
22706                        code_actions
22707                            .context("code action fetch")?
22708                            .into_iter()
22709                            .flatten(),
22710                    )
22711                    .collect())
22712            })
22713        })
22714    }
22715
22716    fn apply_code_action(
22717        &self,
22718        buffer_handle: Entity<Buffer>,
22719        action: CodeAction,
22720        _excerpt_id: ExcerptId,
22721        push_to_history: bool,
22722        _window: &mut Window,
22723        cx: &mut App,
22724    ) -> Task<Result<ProjectTransaction>> {
22725        self.update(cx, |project, cx| {
22726            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22727        })
22728    }
22729}
22730
22731fn snippet_completions(
22732    project: &Project,
22733    buffer: &Entity<Buffer>,
22734    buffer_position: text::Anchor,
22735    cx: &mut App,
22736) -> Task<Result<CompletionResponse>> {
22737    let languages = buffer.read(cx).languages_at(buffer_position);
22738    let snippet_store = project.snippets().read(cx);
22739
22740    let scopes: Vec<_> = languages
22741        .iter()
22742        .filter_map(|language| {
22743            let language_name = language.lsp_id();
22744            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22745
22746            if snippets.is_empty() {
22747                None
22748            } else {
22749                Some((language.default_scope(), snippets))
22750            }
22751        })
22752        .collect();
22753
22754    if scopes.is_empty() {
22755        return Task::ready(Ok(CompletionResponse {
22756            completions: vec![],
22757            display_options: CompletionDisplayOptions::default(),
22758            is_incomplete: false,
22759        }));
22760    }
22761
22762    let snapshot = buffer.read(cx).text_snapshot();
22763    let chars: String = snapshot
22764        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22765        .collect();
22766    let executor = cx.background_executor().clone();
22767
22768    cx.background_spawn(async move {
22769        let mut is_incomplete = false;
22770        let mut completions: Vec<Completion> = Vec::new();
22771        for (scope, snippets) in scopes.into_iter() {
22772            let classifier =
22773                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22774            let mut last_word = chars
22775                .chars()
22776                .take_while(|c| classifier.is_word(*c))
22777                .collect::<String>();
22778            last_word = last_word.chars().rev().collect();
22779
22780            if last_word.is_empty() {
22781                return Ok(CompletionResponse {
22782                    completions: vec![],
22783                    display_options: CompletionDisplayOptions::default(),
22784                    is_incomplete: true,
22785                });
22786            }
22787
22788            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22789            let to_lsp = |point: &text::Anchor| {
22790                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22791                point_to_lsp(end)
22792            };
22793            let lsp_end = to_lsp(&buffer_position);
22794
22795            let candidates = snippets
22796                .iter()
22797                .enumerate()
22798                .flat_map(|(ix, snippet)| {
22799                    snippet
22800                        .prefix
22801                        .iter()
22802                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22803                })
22804                .collect::<Vec<StringMatchCandidate>>();
22805
22806            const MAX_RESULTS: usize = 100;
22807            let mut matches = fuzzy::match_strings(
22808                &candidates,
22809                &last_word,
22810                last_word.chars().any(|c| c.is_uppercase()),
22811                true,
22812                MAX_RESULTS,
22813                &Default::default(),
22814                executor.clone(),
22815            )
22816            .await;
22817
22818            if matches.len() >= MAX_RESULTS {
22819                is_incomplete = true;
22820            }
22821
22822            // Remove all candidates where the query's start does not match the start of any word in the candidate
22823            if let Some(query_start) = last_word.chars().next() {
22824                matches.retain(|string_match| {
22825                    split_words(&string_match.string).any(|word| {
22826                        // Check that the first codepoint of the word as lowercase matches the first
22827                        // codepoint of the query as lowercase
22828                        word.chars()
22829                            .flat_map(|codepoint| codepoint.to_lowercase())
22830                            .zip(query_start.to_lowercase())
22831                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22832                    })
22833                });
22834            }
22835
22836            let matched_strings = matches
22837                .into_iter()
22838                .map(|m| m.string)
22839                .collect::<HashSet<_>>();
22840
22841            completions.extend(snippets.iter().filter_map(|snippet| {
22842                let matching_prefix = snippet
22843                    .prefix
22844                    .iter()
22845                    .find(|prefix| matched_strings.contains(*prefix))?;
22846                let start = as_offset - last_word.len();
22847                let start = snapshot.anchor_before(start);
22848                let range = start..buffer_position;
22849                let lsp_start = to_lsp(&start);
22850                let lsp_range = lsp::Range {
22851                    start: lsp_start,
22852                    end: lsp_end,
22853                };
22854                Some(Completion {
22855                    replace_range: range,
22856                    new_text: snippet.body.clone(),
22857                    source: CompletionSource::Lsp {
22858                        insert_range: None,
22859                        server_id: LanguageServerId(usize::MAX),
22860                        resolved: true,
22861                        lsp_completion: Box::new(lsp::CompletionItem {
22862                            label: snippet.prefix.first().unwrap().clone(),
22863                            kind: Some(CompletionItemKind::SNIPPET),
22864                            label_details: snippet.description.as_ref().map(|description| {
22865                                lsp::CompletionItemLabelDetails {
22866                                    detail: Some(description.clone()),
22867                                    description: None,
22868                                }
22869                            }),
22870                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22871                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22872                                lsp::InsertReplaceEdit {
22873                                    new_text: snippet.body.clone(),
22874                                    insert: lsp_range,
22875                                    replace: lsp_range,
22876                                },
22877                            )),
22878                            filter_text: Some(snippet.body.clone()),
22879                            sort_text: Some(char::MAX.to_string()),
22880                            ..lsp::CompletionItem::default()
22881                        }),
22882                        lsp_defaults: None,
22883                    },
22884                    label: CodeLabel {
22885                        text: matching_prefix.clone(),
22886                        runs: Vec::new(),
22887                        filter_range: 0..matching_prefix.len(),
22888                    },
22889                    icon_path: None,
22890                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22891                        single_line: snippet.name.clone().into(),
22892                        plain_text: snippet
22893                            .description
22894                            .clone()
22895                            .map(|description| description.into()),
22896                    }),
22897                    insert_text_mode: None,
22898                    confirm: None,
22899                })
22900            }))
22901        }
22902
22903        Ok(CompletionResponse {
22904            completions,
22905            display_options: CompletionDisplayOptions::default(),
22906            is_incomplete,
22907        })
22908    })
22909}
22910
22911impl CompletionProvider for Entity<Project> {
22912    fn completions(
22913        &self,
22914        _excerpt_id: ExcerptId,
22915        buffer: &Entity<Buffer>,
22916        buffer_position: text::Anchor,
22917        options: CompletionContext,
22918        _window: &mut Window,
22919        cx: &mut Context<Editor>,
22920    ) -> Task<Result<Vec<CompletionResponse>>> {
22921        self.update(cx, |project, cx| {
22922            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22923            let project_completions = project.completions(buffer, buffer_position, options, cx);
22924            cx.background_spawn(async move {
22925                let mut responses = project_completions.await?;
22926                let snippets = snippets.await?;
22927                if !snippets.completions.is_empty() {
22928                    responses.push(snippets);
22929                }
22930                Ok(responses)
22931            })
22932        })
22933    }
22934
22935    fn resolve_completions(
22936        &self,
22937        buffer: Entity<Buffer>,
22938        completion_indices: Vec<usize>,
22939        completions: Rc<RefCell<Box<[Completion]>>>,
22940        cx: &mut Context<Editor>,
22941    ) -> Task<Result<bool>> {
22942        self.update(cx, |project, cx| {
22943            project.lsp_store().update(cx, |lsp_store, cx| {
22944                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22945            })
22946        })
22947    }
22948
22949    fn apply_additional_edits_for_completion(
22950        &self,
22951        buffer: Entity<Buffer>,
22952        completions: Rc<RefCell<Box<[Completion]>>>,
22953        completion_index: usize,
22954        push_to_history: bool,
22955        cx: &mut Context<Editor>,
22956    ) -> Task<Result<Option<language::Transaction>>> {
22957        self.update(cx, |project, cx| {
22958            project.lsp_store().update(cx, |lsp_store, cx| {
22959                lsp_store.apply_additional_edits_for_completion(
22960                    buffer,
22961                    completions,
22962                    completion_index,
22963                    push_to_history,
22964                    cx,
22965                )
22966            })
22967        })
22968    }
22969
22970    fn is_completion_trigger(
22971        &self,
22972        buffer: &Entity<Buffer>,
22973        position: language::Anchor,
22974        text: &str,
22975        trigger_in_words: bool,
22976        menu_is_open: bool,
22977        cx: &mut Context<Editor>,
22978    ) -> bool {
22979        let mut chars = text.chars();
22980        let char = if let Some(char) = chars.next() {
22981            char
22982        } else {
22983            return false;
22984        };
22985        if chars.next().is_some() {
22986            return false;
22987        }
22988
22989        let buffer = buffer.read(cx);
22990        let snapshot = buffer.snapshot();
22991        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22992            return false;
22993        }
22994        let classifier = snapshot
22995            .char_classifier_at(position)
22996            .scope_context(Some(CharScopeContext::Completion));
22997        if trigger_in_words && classifier.is_word(char) {
22998            return true;
22999        }
23000
23001        buffer.completion_triggers().contains(text)
23002    }
23003}
23004
23005impl SemanticsProvider for Entity<Project> {
23006    fn hover(
23007        &self,
23008        buffer: &Entity<Buffer>,
23009        position: text::Anchor,
23010        cx: &mut App,
23011    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23012        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23013    }
23014
23015    fn document_highlights(
23016        &self,
23017        buffer: &Entity<Buffer>,
23018        position: text::Anchor,
23019        cx: &mut App,
23020    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23021        Some(self.update(cx, |project, cx| {
23022            project.document_highlights(buffer, position, cx)
23023        }))
23024    }
23025
23026    fn definitions(
23027        &self,
23028        buffer: &Entity<Buffer>,
23029        position: text::Anchor,
23030        kind: GotoDefinitionKind,
23031        cx: &mut App,
23032    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23033        Some(self.update(cx, |project, cx| match kind {
23034            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23035            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23036            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23037            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23038        }))
23039    }
23040
23041    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23042        self.update(cx, |project, cx| {
23043            if project
23044                .active_debug_session(cx)
23045                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23046            {
23047                return true;
23048            }
23049
23050            buffer.update(cx, |buffer, cx| {
23051                project.any_language_server_supports_inlay_hints(buffer, cx)
23052            })
23053        })
23054    }
23055
23056    fn inline_values(
23057        &self,
23058        buffer_handle: Entity<Buffer>,
23059        range: Range<text::Anchor>,
23060        cx: &mut App,
23061    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23062        self.update(cx, |project, cx| {
23063            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23064
23065            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23066        })
23067    }
23068
23069    fn inlay_hints(
23070        &self,
23071        buffer_handle: Entity<Buffer>,
23072        range: Range<text::Anchor>,
23073        cx: &mut App,
23074    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23075        Some(self.update(cx, |project, cx| {
23076            project.inlay_hints(buffer_handle, range, cx)
23077        }))
23078    }
23079
23080    fn resolve_inlay_hint(
23081        &self,
23082        hint: InlayHint,
23083        buffer_handle: Entity<Buffer>,
23084        server_id: LanguageServerId,
23085        cx: &mut App,
23086    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23087        Some(self.update(cx, |project, cx| {
23088            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23089        }))
23090    }
23091
23092    fn range_for_rename(
23093        &self,
23094        buffer: &Entity<Buffer>,
23095        position: text::Anchor,
23096        cx: &mut App,
23097    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23098        Some(self.update(cx, |project, cx| {
23099            let buffer = buffer.clone();
23100            let task = project.prepare_rename(buffer.clone(), position, cx);
23101            cx.spawn(async move |_, cx| {
23102                Ok(match task.await? {
23103                    PrepareRenameResponse::Success(range) => Some(range),
23104                    PrepareRenameResponse::InvalidPosition => None,
23105                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23106                        // Fallback on using TreeSitter info to determine identifier range
23107                        buffer.read_with(cx, |buffer, _| {
23108                            let snapshot = buffer.snapshot();
23109                            let (range, kind) = snapshot.surrounding_word(position, None);
23110                            if kind != Some(CharKind::Word) {
23111                                return None;
23112                            }
23113                            Some(
23114                                snapshot.anchor_before(range.start)
23115                                    ..snapshot.anchor_after(range.end),
23116                            )
23117                        })?
23118                    }
23119                })
23120            })
23121        }))
23122    }
23123
23124    fn perform_rename(
23125        &self,
23126        buffer: &Entity<Buffer>,
23127        position: text::Anchor,
23128        new_name: String,
23129        cx: &mut App,
23130    ) -> Option<Task<Result<ProjectTransaction>>> {
23131        Some(self.update(cx, |project, cx| {
23132            project.perform_rename(buffer.clone(), position, new_name, cx)
23133        }))
23134    }
23135}
23136
23137fn inlay_hint_settings(
23138    location: Anchor,
23139    snapshot: &MultiBufferSnapshot,
23140    cx: &mut Context<Editor>,
23141) -> InlayHintSettings {
23142    let file = snapshot.file_at(location);
23143    let language = snapshot.language_at(location).map(|l| l.name());
23144    language_settings(language, file, cx).inlay_hints
23145}
23146
23147fn consume_contiguous_rows(
23148    contiguous_row_selections: &mut Vec<Selection<Point>>,
23149    selection: &Selection<Point>,
23150    display_map: &DisplaySnapshot,
23151    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23152) -> (MultiBufferRow, MultiBufferRow) {
23153    contiguous_row_selections.push(selection.clone());
23154    let start_row = starting_row(selection, display_map);
23155    let mut end_row = ending_row(selection, display_map);
23156
23157    while let Some(next_selection) = selections.peek() {
23158        if next_selection.start.row <= end_row.0 {
23159            end_row = ending_row(next_selection, display_map);
23160            contiguous_row_selections.push(selections.next().unwrap().clone());
23161        } else {
23162            break;
23163        }
23164    }
23165    (start_row, end_row)
23166}
23167
23168fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23169    if selection.start.column > 0 {
23170        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23171    } else {
23172        MultiBufferRow(selection.start.row)
23173    }
23174}
23175
23176fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23177    if next_selection.end.column > 0 || next_selection.is_empty() {
23178        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23179    } else {
23180        MultiBufferRow(next_selection.end.row)
23181    }
23182}
23183
23184impl EditorSnapshot {
23185    pub fn remote_selections_in_range<'a>(
23186        &'a self,
23187        range: &'a Range<Anchor>,
23188        collaboration_hub: &dyn CollaborationHub,
23189        cx: &'a App,
23190    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23191        let participant_names = collaboration_hub.user_names(cx);
23192        let participant_indices = collaboration_hub.user_participant_indices(cx);
23193        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23194        let collaborators_by_replica_id = collaborators_by_peer_id
23195            .values()
23196            .map(|collaborator| (collaborator.replica_id, collaborator))
23197            .collect::<HashMap<_, _>>();
23198        self.buffer_snapshot
23199            .selections_in_range(range, false)
23200            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23201                if replica_id == AGENT_REPLICA_ID {
23202                    Some(RemoteSelection {
23203                        replica_id,
23204                        selection,
23205                        cursor_shape,
23206                        line_mode,
23207                        collaborator_id: CollaboratorId::Agent,
23208                        user_name: Some("Agent".into()),
23209                        color: cx.theme().players().agent(),
23210                    })
23211                } else {
23212                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23213                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23214                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23215                    Some(RemoteSelection {
23216                        replica_id,
23217                        selection,
23218                        cursor_shape,
23219                        line_mode,
23220                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23221                        user_name,
23222                        color: if let Some(index) = participant_index {
23223                            cx.theme().players().color_for_participant(index.0)
23224                        } else {
23225                            cx.theme().players().absent()
23226                        },
23227                    })
23228                }
23229            })
23230    }
23231
23232    pub fn hunks_for_ranges(
23233        &self,
23234        ranges: impl IntoIterator<Item = Range<Point>>,
23235    ) -> Vec<MultiBufferDiffHunk> {
23236        let mut hunks = Vec::new();
23237        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23238            HashMap::default();
23239        for query_range in ranges {
23240            let query_rows =
23241                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23242            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23243                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23244            ) {
23245                // Include deleted hunks that are adjacent to the query range, because
23246                // otherwise they would be missed.
23247                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23248                if hunk.status().is_deleted() {
23249                    intersects_range |= hunk.row_range.start == query_rows.end;
23250                    intersects_range |= hunk.row_range.end == query_rows.start;
23251                }
23252                if intersects_range {
23253                    if !processed_buffer_rows
23254                        .entry(hunk.buffer_id)
23255                        .or_default()
23256                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23257                    {
23258                        continue;
23259                    }
23260                    hunks.push(hunk);
23261                }
23262            }
23263        }
23264
23265        hunks
23266    }
23267
23268    fn display_diff_hunks_for_rows<'a>(
23269        &'a self,
23270        display_rows: Range<DisplayRow>,
23271        folded_buffers: &'a HashSet<BufferId>,
23272    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23273        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23274        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23275
23276        self.buffer_snapshot
23277            .diff_hunks_in_range(buffer_start..buffer_end)
23278            .filter_map(|hunk| {
23279                if folded_buffers.contains(&hunk.buffer_id) {
23280                    return None;
23281                }
23282
23283                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23284                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23285
23286                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23287                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23288
23289                let display_hunk = if hunk_display_start.column() != 0 {
23290                    DisplayDiffHunk::Folded {
23291                        display_row: hunk_display_start.row(),
23292                    }
23293                } else {
23294                    let mut end_row = hunk_display_end.row();
23295                    if hunk_display_end.column() > 0 {
23296                        end_row.0 += 1;
23297                    }
23298                    let is_created_file = hunk.is_created_file();
23299                    DisplayDiffHunk::Unfolded {
23300                        status: hunk.status(),
23301                        diff_base_byte_range: hunk.diff_base_byte_range,
23302                        display_row_range: hunk_display_start.row()..end_row,
23303                        multi_buffer_range: Anchor::range_in_buffer(
23304                            hunk.excerpt_id,
23305                            hunk.buffer_id,
23306                            hunk.buffer_range,
23307                        ),
23308                        is_created_file,
23309                    }
23310                };
23311
23312                Some(display_hunk)
23313            })
23314    }
23315
23316    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23317        self.display_snapshot.buffer_snapshot.language_at(position)
23318    }
23319
23320    pub fn is_focused(&self) -> bool {
23321        self.is_focused
23322    }
23323
23324    pub fn placeholder_text(&self) -> Option<String> {
23325        self.placeholder_display_snapshot
23326            .as_ref()
23327            .map(|display_map| display_map.text())
23328    }
23329
23330    pub fn scroll_position(&self) -> gpui::Point<f32> {
23331        self.scroll_anchor.scroll_position(&self.display_snapshot)
23332    }
23333
23334    fn gutter_dimensions(
23335        &self,
23336        font_id: FontId,
23337        font_size: Pixels,
23338        max_line_number_width: Pixels,
23339        cx: &App,
23340    ) -> Option<GutterDimensions> {
23341        if !self.show_gutter {
23342            return None;
23343        }
23344
23345        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23346        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23347
23348        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23349            matches!(
23350                ProjectSettings::get_global(cx).git.git_gutter,
23351                GitGutterSetting::TrackedFiles
23352            )
23353        });
23354        let gutter_settings = EditorSettings::get_global(cx).gutter;
23355        let show_line_numbers = self
23356            .show_line_numbers
23357            .unwrap_or(gutter_settings.line_numbers);
23358        let line_gutter_width = if show_line_numbers {
23359            // Avoid flicker-like gutter resizes when the line number gains another digit by
23360            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23361            let min_width_for_number_on_gutter =
23362                ch_advance * gutter_settings.min_line_number_digits as f32;
23363            max_line_number_width.max(min_width_for_number_on_gutter)
23364        } else {
23365            0.0.into()
23366        };
23367
23368        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23369        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23370
23371        let git_blame_entries_width =
23372            self.git_blame_gutter_max_author_length
23373                .map(|max_author_length| {
23374                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23375                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23376
23377                    /// The number of characters to dedicate to gaps and margins.
23378                    const SPACING_WIDTH: usize = 4;
23379
23380                    let max_char_count = max_author_length.min(renderer.max_author_length())
23381                        + ::git::SHORT_SHA_LENGTH
23382                        + MAX_RELATIVE_TIMESTAMP.len()
23383                        + SPACING_WIDTH;
23384
23385                    ch_advance * max_char_count
23386                });
23387
23388        let is_singleton = self.buffer_snapshot.is_singleton();
23389
23390        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23391        left_padding += if !is_singleton {
23392            ch_width * 4.0
23393        } else if show_runnables || show_breakpoints {
23394            ch_width * 3.0
23395        } else if show_git_gutter && show_line_numbers {
23396            ch_width * 2.0
23397        } else if show_git_gutter || show_line_numbers {
23398            ch_width
23399        } else {
23400            px(0.)
23401        };
23402
23403        let shows_folds = is_singleton && gutter_settings.folds;
23404
23405        let right_padding = if shows_folds && show_line_numbers {
23406            ch_width * 4.0
23407        } else if shows_folds || (!is_singleton && show_line_numbers) {
23408            ch_width * 3.0
23409        } else if show_line_numbers {
23410            ch_width
23411        } else {
23412            px(0.)
23413        };
23414
23415        Some(GutterDimensions {
23416            left_padding,
23417            right_padding,
23418            width: line_gutter_width + left_padding + right_padding,
23419            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23420            git_blame_entries_width,
23421        })
23422    }
23423
23424    pub fn render_crease_toggle(
23425        &self,
23426        buffer_row: MultiBufferRow,
23427        row_contains_cursor: bool,
23428        editor: Entity<Editor>,
23429        window: &mut Window,
23430        cx: &mut App,
23431    ) -> Option<AnyElement> {
23432        let folded = self.is_line_folded(buffer_row);
23433        let mut is_foldable = false;
23434
23435        if let Some(crease) = self
23436            .crease_snapshot
23437            .query_row(buffer_row, &self.buffer_snapshot)
23438        {
23439            is_foldable = true;
23440            match crease {
23441                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23442                    if let Some(render_toggle) = render_toggle {
23443                        let toggle_callback =
23444                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23445                                if folded {
23446                                    editor.update(cx, |editor, cx| {
23447                                        editor.fold_at(buffer_row, window, cx)
23448                                    });
23449                                } else {
23450                                    editor.update(cx, |editor, cx| {
23451                                        editor.unfold_at(buffer_row, window, cx)
23452                                    });
23453                                }
23454                            });
23455                        return Some((render_toggle)(
23456                            buffer_row,
23457                            folded,
23458                            toggle_callback,
23459                            window,
23460                            cx,
23461                        ));
23462                    }
23463                }
23464            }
23465        }
23466
23467        is_foldable |= self.starts_indent(buffer_row);
23468
23469        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23470            Some(
23471                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23472                    .toggle_state(folded)
23473                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23474                        if folded {
23475                            this.unfold_at(buffer_row, window, cx);
23476                        } else {
23477                            this.fold_at(buffer_row, window, cx);
23478                        }
23479                    }))
23480                    .into_any_element(),
23481            )
23482        } else {
23483            None
23484        }
23485    }
23486
23487    pub fn render_crease_trailer(
23488        &self,
23489        buffer_row: MultiBufferRow,
23490        window: &mut Window,
23491        cx: &mut App,
23492    ) -> Option<AnyElement> {
23493        let folded = self.is_line_folded(buffer_row);
23494        if let Crease::Inline { render_trailer, .. } = self
23495            .crease_snapshot
23496            .query_row(buffer_row, &self.buffer_snapshot)?
23497        {
23498            let render_trailer = render_trailer.as_ref()?;
23499            Some(render_trailer(buffer_row, folded, window, cx))
23500        } else {
23501            None
23502        }
23503    }
23504}
23505
23506impl Deref for EditorSnapshot {
23507    type Target = DisplaySnapshot;
23508
23509    fn deref(&self) -> &Self::Target {
23510        &self.display_snapshot
23511    }
23512}
23513
23514#[derive(Clone, Debug, PartialEq, Eq)]
23515pub enum EditorEvent {
23516    InputIgnored {
23517        text: Arc<str>,
23518    },
23519    InputHandled {
23520        utf16_range_to_replace: Option<Range<isize>>,
23521        text: Arc<str>,
23522    },
23523    ExcerptsAdded {
23524        buffer: Entity<Buffer>,
23525        predecessor: ExcerptId,
23526        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23527    },
23528    ExcerptsRemoved {
23529        ids: Vec<ExcerptId>,
23530        removed_buffer_ids: Vec<BufferId>,
23531    },
23532    BufferFoldToggled {
23533        ids: Vec<ExcerptId>,
23534        folded: bool,
23535    },
23536    ExcerptsEdited {
23537        ids: Vec<ExcerptId>,
23538    },
23539    ExcerptsExpanded {
23540        ids: Vec<ExcerptId>,
23541    },
23542    BufferEdited,
23543    Edited {
23544        transaction_id: clock::Lamport,
23545    },
23546    Reparsed(BufferId),
23547    Focused,
23548    FocusedIn,
23549    Blurred,
23550    DirtyChanged,
23551    Saved,
23552    TitleChanged,
23553    SelectionsChanged {
23554        local: bool,
23555    },
23556    ScrollPositionChanged {
23557        local: bool,
23558        autoscroll: bool,
23559    },
23560    TransactionUndone {
23561        transaction_id: clock::Lamport,
23562    },
23563    TransactionBegun {
23564        transaction_id: clock::Lamport,
23565    },
23566    CursorShapeChanged,
23567    BreadcrumbsChanged,
23568    PushedToNavHistory {
23569        anchor: Anchor,
23570        is_deactivate: bool,
23571    },
23572}
23573
23574impl EventEmitter<EditorEvent> for Editor {}
23575
23576impl Focusable for Editor {
23577    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23578        self.focus_handle.clone()
23579    }
23580}
23581
23582impl Render for Editor {
23583    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23584        let settings = ThemeSettings::get_global(cx);
23585
23586        let mut text_style = match self.mode {
23587            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23588                color: cx.theme().colors().editor_foreground,
23589                font_family: settings.ui_font.family.clone(),
23590                font_features: settings.ui_font.features.clone(),
23591                font_fallbacks: settings.ui_font.fallbacks.clone(),
23592                font_size: rems(0.875).into(),
23593                font_weight: settings.ui_font.weight,
23594                line_height: relative(settings.buffer_line_height.value()),
23595                ..Default::default()
23596            },
23597            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23598                color: cx.theme().colors().editor_foreground,
23599                font_family: settings.buffer_font.family.clone(),
23600                font_features: settings.buffer_font.features.clone(),
23601                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23602                font_size: settings.buffer_font_size(cx).into(),
23603                font_weight: settings.buffer_font.weight,
23604                line_height: relative(settings.buffer_line_height.value()),
23605                ..Default::default()
23606            },
23607        };
23608        if let Some(text_style_refinement) = &self.text_style_refinement {
23609            text_style.refine(text_style_refinement)
23610        }
23611
23612        let background = match self.mode {
23613            EditorMode::SingleLine => cx.theme().system().transparent,
23614            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23615            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23616            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23617        };
23618
23619        EditorElement::new(
23620            &cx.entity(),
23621            EditorStyle {
23622                background,
23623                border: cx.theme().colors().border,
23624                local_player: cx.theme().players().local(),
23625                text: text_style,
23626                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23627                syntax: cx.theme().syntax().clone(),
23628                status: cx.theme().status().clone(),
23629                inlay_hints_style: make_inlay_hints_style(cx),
23630                edit_prediction_styles: make_suggestion_styles(cx),
23631                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23632                show_underlines: self.diagnostics_enabled(),
23633            },
23634        )
23635    }
23636}
23637
23638impl EntityInputHandler for Editor {
23639    fn text_for_range(
23640        &mut self,
23641        range_utf16: Range<usize>,
23642        adjusted_range: &mut Option<Range<usize>>,
23643        _: &mut Window,
23644        cx: &mut Context<Self>,
23645    ) -> Option<String> {
23646        let snapshot = self.buffer.read(cx).read(cx);
23647        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23648        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23649        if (start.0..end.0) != range_utf16 {
23650            adjusted_range.replace(start.0..end.0);
23651        }
23652        Some(snapshot.text_for_range(start..end).collect())
23653    }
23654
23655    fn selected_text_range(
23656        &mut self,
23657        ignore_disabled_input: bool,
23658        _: &mut Window,
23659        cx: &mut Context<Self>,
23660    ) -> Option<UTF16Selection> {
23661        // Prevent the IME menu from appearing when holding down an alphabetic key
23662        // while input is disabled.
23663        if !ignore_disabled_input && !self.input_enabled {
23664            return None;
23665        }
23666
23667        let selection = self.selections.newest::<OffsetUtf16>(cx);
23668        let range = selection.range();
23669
23670        Some(UTF16Selection {
23671            range: range.start.0..range.end.0,
23672            reversed: selection.reversed,
23673        })
23674    }
23675
23676    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23677        let snapshot = self.buffer.read(cx).read(cx);
23678        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23679        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23680    }
23681
23682    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23683        self.clear_highlights::<InputComposition>(cx);
23684        self.ime_transaction.take();
23685    }
23686
23687    fn replace_text_in_range(
23688        &mut self,
23689        range_utf16: Option<Range<usize>>,
23690        text: &str,
23691        window: &mut Window,
23692        cx: &mut Context<Self>,
23693    ) {
23694        if !self.input_enabled {
23695            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23696            return;
23697        }
23698
23699        self.transact(window, cx, |this, window, cx| {
23700            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23701                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23702                Some(this.selection_replacement_ranges(range_utf16, cx))
23703            } else {
23704                this.marked_text_ranges(cx)
23705            };
23706
23707            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23708                let newest_selection_id = this.selections.newest_anchor().id;
23709                this.selections
23710                    .all::<OffsetUtf16>(cx)
23711                    .iter()
23712                    .zip(ranges_to_replace.iter())
23713                    .find_map(|(selection, range)| {
23714                        if selection.id == newest_selection_id {
23715                            Some(
23716                                (range.start.0 as isize - selection.head().0 as isize)
23717                                    ..(range.end.0 as isize - selection.head().0 as isize),
23718                            )
23719                        } else {
23720                            None
23721                        }
23722                    })
23723            });
23724
23725            cx.emit(EditorEvent::InputHandled {
23726                utf16_range_to_replace: range_to_replace,
23727                text: text.into(),
23728            });
23729
23730            if let Some(new_selected_ranges) = new_selected_ranges {
23731                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23732                    selections.select_ranges(new_selected_ranges)
23733                });
23734                this.backspace(&Default::default(), window, cx);
23735            }
23736
23737            this.handle_input(text, window, cx);
23738        });
23739
23740        if let Some(transaction) = self.ime_transaction {
23741            self.buffer.update(cx, |buffer, cx| {
23742                buffer.group_until_transaction(transaction, cx);
23743            });
23744        }
23745
23746        self.unmark_text(window, cx);
23747    }
23748
23749    fn replace_and_mark_text_in_range(
23750        &mut self,
23751        range_utf16: Option<Range<usize>>,
23752        text: &str,
23753        new_selected_range_utf16: Option<Range<usize>>,
23754        window: &mut Window,
23755        cx: &mut Context<Self>,
23756    ) {
23757        if !self.input_enabled {
23758            return;
23759        }
23760
23761        let transaction = self.transact(window, cx, |this, window, cx| {
23762            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23763                let snapshot = this.buffer.read(cx).read(cx);
23764                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23765                    for marked_range in &mut marked_ranges {
23766                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23767                        marked_range.start.0 += relative_range_utf16.start;
23768                        marked_range.start =
23769                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23770                        marked_range.end =
23771                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23772                    }
23773                }
23774                Some(marked_ranges)
23775            } else if let Some(range_utf16) = range_utf16 {
23776                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23777                Some(this.selection_replacement_ranges(range_utf16, cx))
23778            } else {
23779                None
23780            };
23781
23782            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23783                let newest_selection_id = this.selections.newest_anchor().id;
23784                this.selections
23785                    .all::<OffsetUtf16>(cx)
23786                    .iter()
23787                    .zip(ranges_to_replace.iter())
23788                    .find_map(|(selection, range)| {
23789                        if selection.id == newest_selection_id {
23790                            Some(
23791                                (range.start.0 as isize - selection.head().0 as isize)
23792                                    ..(range.end.0 as isize - selection.head().0 as isize),
23793                            )
23794                        } else {
23795                            None
23796                        }
23797                    })
23798            });
23799
23800            cx.emit(EditorEvent::InputHandled {
23801                utf16_range_to_replace: range_to_replace,
23802                text: text.into(),
23803            });
23804
23805            if let Some(ranges) = ranges_to_replace {
23806                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23807                    s.select_ranges(ranges)
23808                });
23809            }
23810
23811            let marked_ranges = {
23812                let snapshot = this.buffer.read(cx).read(cx);
23813                this.selections
23814                    .disjoint_anchors_arc()
23815                    .iter()
23816                    .map(|selection| {
23817                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23818                    })
23819                    .collect::<Vec<_>>()
23820            };
23821
23822            if text.is_empty() {
23823                this.unmark_text(window, cx);
23824            } else {
23825                this.highlight_text::<InputComposition>(
23826                    marked_ranges.clone(),
23827                    HighlightStyle {
23828                        underline: Some(UnderlineStyle {
23829                            thickness: px(1.),
23830                            color: None,
23831                            wavy: false,
23832                        }),
23833                        ..Default::default()
23834                    },
23835                    cx,
23836                );
23837            }
23838
23839            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23840            let use_autoclose = this.use_autoclose;
23841            let use_auto_surround = this.use_auto_surround;
23842            this.set_use_autoclose(false);
23843            this.set_use_auto_surround(false);
23844            this.handle_input(text, window, cx);
23845            this.set_use_autoclose(use_autoclose);
23846            this.set_use_auto_surround(use_auto_surround);
23847
23848            if let Some(new_selected_range) = new_selected_range_utf16 {
23849                let snapshot = this.buffer.read(cx).read(cx);
23850                let new_selected_ranges = marked_ranges
23851                    .into_iter()
23852                    .map(|marked_range| {
23853                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23854                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23855                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23856                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23857                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23858                    })
23859                    .collect::<Vec<_>>();
23860
23861                drop(snapshot);
23862                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23863                    selections.select_ranges(new_selected_ranges)
23864                });
23865            }
23866        });
23867
23868        self.ime_transaction = self.ime_transaction.or(transaction);
23869        if let Some(transaction) = self.ime_transaction {
23870            self.buffer.update(cx, |buffer, cx| {
23871                buffer.group_until_transaction(transaction, cx);
23872            });
23873        }
23874
23875        if self.text_highlights::<InputComposition>(cx).is_none() {
23876            self.ime_transaction.take();
23877        }
23878    }
23879
23880    fn bounds_for_range(
23881        &mut self,
23882        range_utf16: Range<usize>,
23883        element_bounds: gpui::Bounds<Pixels>,
23884        window: &mut Window,
23885        cx: &mut Context<Self>,
23886    ) -> Option<gpui::Bounds<Pixels>> {
23887        let text_layout_details = self.text_layout_details(window);
23888        let CharacterDimensions {
23889            em_width,
23890            em_advance,
23891            line_height,
23892        } = self.character_dimensions(window);
23893
23894        let snapshot = self.snapshot(window, cx);
23895        let scroll_position = snapshot.scroll_position();
23896        let scroll_left = scroll_position.x * em_advance;
23897
23898        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23899        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23900            + self.gutter_dimensions.full_width();
23901        let y = line_height * (start.row().as_f32() - scroll_position.y);
23902
23903        Some(Bounds {
23904            origin: element_bounds.origin + point(x, y),
23905            size: size(em_width, line_height),
23906        })
23907    }
23908
23909    fn character_index_for_point(
23910        &mut self,
23911        point: gpui::Point<Pixels>,
23912        _window: &mut Window,
23913        _cx: &mut Context<Self>,
23914    ) -> Option<usize> {
23915        let position_map = self.last_position_map.as_ref()?;
23916        if !position_map.text_hitbox.contains(&point) {
23917            return None;
23918        }
23919        let display_point = position_map.point_for_position(point).previous_valid;
23920        let anchor = position_map
23921            .snapshot
23922            .display_point_to_anchor(display_point, Bias::Left);
23923        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23924        Some(utf16_offset.0)
23925    }
23926}
23927
23928trait SelectionExt {
23929    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23930    fn spanned_rows(
23931        &self,
23932        include_end_if_at_line_start: bool,
23933        map: &DisplaySnapshot,
23934    ) -> Range<MultiBufferRow>;
23935}
23936
23937impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23938    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23939        let start = self
23940            .start
23941            .to_point(&map.buffer_snapshot)
23942            .to_display_point(map);
23943        let end = self
23944            .end
23945            .to_point(&map.buffer_snapshot)
23946            .to_display_point(map);
23947        if self.reversed {
23948            end..start
23949        } else {
23950            start..end
23951        }
23952    }
23953
23954    fn spanned_rows(
23955        &self,
23956        include_end_if_at_line_start: bool,
23957        map: &DisplaySnapshot,
23958    ) -> Range<MultiBufferRow> {
23959        let start = self.start.to_point(&map.buffer_snapshot);
23960        let mut end = self.end.to_point(&map.buffer_snapshot);
23961        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23962            end.row -= 1;
23963        }
23964
23965        let buffer_start = map.prev_line_boundary(start).0;
23966        let buffer_end = map.next_line_boundary(end).0;
23967        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23968    }
23969}
23970
23971impl<T: InvalidationRegion> InvalidationStack<T> {
23972    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23973    where
23974        S: Clone + ToOffset,
23975    {
23976        while let Some(region) = self.last() {
23977            let all_selections_inside_invalidation_ranges =
23978                if selections.len() == region.ranges().len() {
23979                    selections
23980                        .iter()
23981                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23982                        .all(|(selection, invalidation_range)| {
23983                            let head = selection.head().to_offset(buffer);
23984                            invalidation_range.start <= head && invalidation_range.end >= head
23985                        })
23986                } else {
23987                    false
23988                };
23989
23990            if all_selections_inside_invalidation_ranges {
23991                break;
23992            } else {
23993                self.pop();
23994            }
23995        }
23996    }
23997}
23998
23999impl<T> Default for InvalidationStack<T> {
24000    fn default() -> Self {
24001        Self(Default::default())
24002    }
24003}
24004
24005impl<T> Deref for InvalidationStack<T> {
24006    type Target = Vec<T>;
24007
24008    fn deref(&self) -> &Self::Target {
24009        &self.0
24010    }
24011}
24012
24013impl<T> DerefMut for InvalidationStack<T> {
24014    fn deref_mut(&mut self) -> &mut Self::Target {
24015        &mut self.0
24016    }
24017}
24018
24019impl InvalidationRegion for SnippetState {
24020    fn ranges(&self) -> &[Range<Anchor>] {
24021        &self.ranges[self.active_index]
24022    }
24023}
24024
24025fn edit_prediction_edit_text(
24026    current_snapshot: &BufferSnapshot,
24027    edits: &[(Range<Anchor>, String)],
24028    edit_preview: &EditPreview,
24029    include_deletions: bool,
24030    cx: &App,
24031) -> HighlightedText {
24032    let edits = edits
24033        .iter()
24034        .map(|(anchor, text)| {
24035            (
24036                anchor.start.text_anchor..anchor.end.text_anchor,
24037                text.clone(),
24038            )
24039        })
24040        .collect::<Vec<_>>();
24041
24042    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24043}
24044
24045fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24046    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24047    // Just show the raw edit text with basic styling
24048    let mut text = String::new();
24049    let mut highlights = Vec::new();
24050
24051    let insertion_highlight_style = HighlightStyle {
24052        color: Some(cx.theme().colors().text),
24053        ..Default::default()
24054    };
24055
24056    for (_, edit_text) in edits {
24057        let start_offset = text.len();
24058        text.push_str(edit_text);
24059        let end_offset = text.len();
24060
24061        if start_offset < end_offset {
24062            highlights.push((start_offset..end_offset, insertion_highlight_style));
24063        }
24064    }
24065
24066    HighlightedText {
24067        text: text.into(),
24068        highlights,
24069    }
24070}
24071
24072pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24073    match severity {
24074        lsp::DiagnosticSeverity::ERROR => colors.error,
24075        lsp::DiagnosticSeverity::WARNING => colors.warning,
24076        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24077        lsp::DiagnosticSeverity::HINT => colors.info,
24078        _ => colors.ignored,
24079    }
24080}
24081
24082pub fn styled_runs_for_code_label<'a>(
24083    label: &'a CodeLabel,
24084    syntax_theme: &'a theme::SyntaxTheme,
24085) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24086    let fade_out = HighlightStyle {
24087        fade_out: Some(0.35),
24088        ..Default::default()
24089    };
24090
24091    let mut prev_end = label.filter_range.end;
24092    label
24093        .runs
24094        .iter()
24095        .enumerate()
24096        .flat_map(move |(ix, (range, highlight_id))| {
24097            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24098                style
24099            } else {
24100                return Default::default();
24101            };
24102            let muted_style = style.highlight(fade_out);
24103
24104            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24105            if range.start >= label.filter_range.end {
24106                if range.start > prev_end {
24107                    runs.push((prev_end..range.start, fade_out));
24108                }
24109                runs.push((range.clone(), muted_style));
24110            } else if range.end <= label.filter_range.end {
24111                runs.push((range.clone(), style));
24112            } else {
24113                runs.push((range.start..label.filter_range.end, style));
24114                runs.push((label.filter_range.end..range.end, muted_style));
24115            }
24116            prev_end = cmp::max(prev_end, range.end);
24117
24118            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24119                runs.push((prev_end..label.text.len(), fade_out));
24120            }
24121
24122            runs
24123        })
24124}
24125
24126pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24127    let mut prev_index = 0;
24128    let mut prev_codepoint: Option<char> = None;
24129    text.char_indices()
24130        .chain([(text.len(), '\0')])
24131        .filter_map(move |(index, codepoint)| {
24132            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24133            let is_boundary = index == text.len()
24134                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24135                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24136            if is_boundary {
24137                let chunk = &text[prev_index..index];
24138                prev_index = index;
24139                Some(chunk)
24140            } else {
24141                None
24142            }
24143        })
24144}
24145
24146pub trait RangeToAnchorExt: Sized {
24147    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24148
24149    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24150        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
24151        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24152    }
24153}
24154
24155impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24156    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24157        let start_offset = self.start.to_offset(snapshot);
24158        let end_offset = self.end.to_offset(snapshot);
24159        if start_offset == end_offset {
24160            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24161        } else {
24162            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24163        }
24164    }
24165}
24166
24167pub trait RowExt {
24168    fn as_f32(&self) -> f32;
24169
24170    fn next_row(&self) -> Self;
24171
24172    fn previous_row(&self) -> Self;
24173
24174    fn minus(&self, other: Self) -> u32;
24175}
24176
24177impl RowExt for DisplayRow {
24178    fn as_f32(&self) -> f32 {
24179        self.0 as f32
24180    }
24181
24182    fn next_row(&self) -> Self {
24183        Self(self.0 + 1)
24184    }
24185
24186    fn previous_row(&self) -> Self {
24187        Self(self.0.saturating_sub(1))
24188    }
24189
24190    fn minus(&self, other: Self) -> u32 {
24191        self.0 - other.0
24192    }
24193}
24194
24195impl RowExt for MultiBufferRow {
24196    fn as_f32(&self) -> f32 {
24197        self.0 as f32
24198    }
24199
24200    fn next_row(&self) -> Self {
24201        Self(self.0 + 1)
24202    }
24203
24204    fn previous_row(&self) -> Self {
24205        Self(self.0.saturating_sub(1))
24206    }
24207
24208    fn minus(&self, other: Self) -> u32 {
24209        self.0 - other.0
24210    }
24211}
24212
24213trait RowRangeExt {
24214    type Row;
24215
24216    fn len(&self) -> usize;
24217
24218    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24219}
24220
24221impl RowRangeExt for Range<MultiBufferRow> {
24222    type Row = MultiBufferRow;
24223
24224    fn len(&self) -> usize {
24225        (self.end.0 - self.start.0) as usize
24226    }
24227
24228    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24229        (self.start.0..self.end.0).map(MultiBufferRow)
24230    }
24231}
24232
24233impl RowRangeExt for Range<DisplayRow> {
24234    type Row = DisplayRow;
24235
24236    fn len(&self) -> usize {
24237        (self.end.0 - self.start.0) as usize
24238    }
24239
24240    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24241        (self.start.0..self.end.0).map(DisplayRow)
24242    }
24243}
24244
24245/// If select range has more than one line, we
24246/// just point the cursor to range.start.
24247fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24248    if range.start.row == range.end.row {
24249        range
24250    } else {
24251        range.start..range.start
24252    }
24253}
24254pub struct KillRing(ClipboardItem);
24255impl Global for KillRing {}
24256
24257const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24258
24259enum BreakpointPromptEditAction {
24260    Log,
24261    Condition,
24262    HitCondition,
24263}
24264
24265struct BreakpointPromptEditor {
24266    pub(crate) prompt: Entity<Editor>,
24267    editor: WeakEntity<Editor>,
24268    breakpoint_anchor: Anchor,
24269    breakpoint: Breakpoint,
24270    edit_action: BreakpointPromptEditAction,
24271    block_ids: HashSet<CustomBlockId>,
24272    editor_margins: Arc<Mutex<EditorMargins>>,
24273    _subscriptions: Vec<Subscription>,
24274}
24275
24276impl BreakpointPromptEditor {
24277    const MAX_LINES: u8 = 4;
24278
24279    fn new(
24280        editor: WeakEntity<Editor>,
24281        breakpoint_anchor: Anchor,
24282        breakpoint: Breakpoint,
24283        edit_action: BreakpointPromptEditAction,
24284        window: &mut Window,
24285        cx: &mut Context<Self>,
24286    ) -> Self {
24287        let base_text = match edit_action {
24288            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24289            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24290            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24291        }
24292        .map(|msg| msg.to_string())
24293        .unwrap_or_default();
24294
24295        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24296        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24297
24298        let prompt = cx.new(|cx| {
24299            let mut prompt = Editor::new(
24300                EditorMode::AutoHeight {
24301                    min_lines: 1,
24302                    max_lines: Some(Self::MAX_LINES as usize),
24303                },
24304                buffer,
24305                None,
24306                window,
24307                cx,
24308            );
24309            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24310            prompt.set_show_cursor_when_unfocused(false, cx);
24311            prompt.set_placeholder_text(
24312                match edit_action {
24313                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24314                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24315                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24316                },
24317                window,
24318                cx,
24319            );
24320
24321            prompt
24322        });
24323
24324        Self {
24325            prompt,
24326            editor,
24327            breakpoint_anchor,
24328            breakpoint,
24329            edit_action,
24330            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24331            block_ids: Default::default(),
24332            _subscriptions: vec![],
24333        }
24334    }
24335
24336    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24337        self.block_ids.extend(block_ids)
24338    }
24339
24340    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24341        if let Some(editor) = self.editor.upgrade() {
24342            let message = self
24343                .prompt
24344                .read(cx)
24345                .buffer
24346                .read(cx)
24347                .as_singleton()
24348                .expect("A multi buffer in breakpoint prompt isn't possible")
24349                .read(cx)
24350                .as_rope()
24351                .to_string();
24352
24353            editor.update(cx, |editor, cx| {
24354                editor.edit_breakpoint_at_anchor(
24355                    self.breakpoint_anchor,
24356                    self.breakpoint.clone(),
24357                    match self.edit_action {
24358                        BreakpointPromptEditAction::Log => {
24359                            BreakpointEditAction::EditLogMessage(message.into())
24360                        }
24361                        BreakpointPromptEditAction::Condition => {
24362                            BreakpointEditAction::EditCondition(message.into())
24363                        }
24364                        BreakpointPromptEditAction::HitCondition => {
24365                            BreakpointEditAction::EditHitCondition(message.into())
24366                        }
24367                    },
24368                    cx,
24369                );
24370
24371                editor.remove_blocks(self.block_ids.clone(), None, cx);
24372                cx.focus_self(window);
24373            });
24374        }
24375    }
24376
24377    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24378        self.editor
24379            .update(cx, |editor, cx| {
24380                editor.remove_blocks(self.block_ids.clone(), None, cx);
24381                window.focus(&editor.focus_handle);
24382            })
24383            .log_err();
24384    }
24385
24386    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24387        let settings = ThemeSettings::get_global(cx);
24388        let text_style = TextStyle {
24389            color: if self.prompt.read(cx).read_only(cx) {
24390                cx.theme().colors().text_disabled
24391            } else {
24392                cx.theme().colors().text
24393            },
24394            font_family: settings.buffer_font.family.clone(),
24395            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24396            font_size: settings.buffer_font_size(cx).into(),
24397            font_weight: settings.buffer_font.weight,
24398            line_height: relative(settings.buffer_line_height.value()),
24399            ..Default::default()
24400        };
24401        EditorElement::new(
24402            &self.prompt,
24403            EditorStyle {
24404                background: cx.theme().colors().editor_background,
24405                local_player: cx.theme().players().local(),
24406                text: text_style,
24407                ..Default::default()
24408            },
24409        )
24410    }
24411}
24412
24413impl Render for BreakpointPromptEditor {
24414    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24415        let editor_margins = *self.editor_margins.lock();
24416        let gutter_dimensions = editor_margins.gutter;
24417        h_flex()
24418            .key_context("Editor")
24419            .bg(cx.theme().colors().editor_background)
24420            .border_y_1()
24421            .border_color(cx.theme().status().info_border)
24422            .size_full()
24423            .py(window.line_height() / 2.5)
24424            .on_action(cx.listener(Self::confirm))
24425            .on_action(cx.listener(Self::cancel))
24426            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24427            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24428    }
24429}
24430
24431impl Focusable for BreakpointPromptEditor {
24432    fn focus_handle(&self, cx: &App) -> FocusHandle {
24433        self.prompt.focus_handle(cx)
24434    }
24435}
24436
24437fn all_edits_insertions_or_deletions(
24438    edits: &Vec<(Range<Anchor>, String)>,
24439    snapshot: &MultiBufferSnapshot,
24440) -> bool {
24441    let mut all_insertions = true;
24442    let mut all_deletions = true;
24443
24444    for (range, new_text) in edits.iter() {
24445        let range_is_empty = range.to_offset(snapshot).is_empty();
24446        let text_is_empty = new_text.is_empty();
24447
24448        if range_is_empty != text_is_empty {
24449            if range_is_empty {
24450                all_deletions = false;
24451            } else {
24452                all_insertions = false;
24453            }
24454        } else {
24455            return false;
24456        }
24457
24458        if !all_insertions && !all_deletions {
24459            return false;
24460        }
24461    }
24462    all_insertions || all_deletions
24463}
24464
24465struct MissingEditPredictionKeybindingTooltip;
24466
24467impl Render for MissingEditPredictionKeybindingTooltip {
24468    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24469        ui::tooltip_container(cx, |container, cx| {
24470            container
24471                .flex_shrink_0()
24472                .max_w_80()
24473                .min_h(rems_from_px(124.))
24474                .justify_between()
24475                .child(
24476                    v_flex()
24477                        .flex_1()
24478                        .text_ui_sm(cx)
24479                        .child(Label::new("Conflict with Accept Keybinding"))
24480                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24481                )
24482                .child(
24483                    h_flex()
24484                        .pb_1()
24485                        .gap_1()
24486                        .items_end()
24487                        .w_full()
24488                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24489                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24490                        }))
24491                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24492                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24493                        })),
24494                )
24495        })
24496    }
24497}
24498
24499#[derive(Debug, Clone, Copy, PartialEq)]
24500pub struct LineHighlight {
24501    pub background: Background,
24502    pub border: Option<gpui::Hsla>,
24503    pub include_gutter: bool,
24504    pub type_id: Option<TypeId>,
24505}
24506
24507struct LineManipulationResult {
24508    pub new_text: String,
24509    pub line_count_before: usize,
24510    pub line_count_after: usize,
24511}
24512
24513fn render_diff_hunk_controls(
24514    row: u32,
24515    status: &DiffHunkStatus,
24516    hunk_range: Range<Anchor>,
24517    is_created_file: bool,
24518    line_height: Pixels,
24519    editor: &Entity<Editor>,
24520    _window: &mut Window,
24521    cx: &mut App,
24522) -> AnyElement {
24523    h_flex()
24524        .h(line_height)
24525        .mr_1()
24526        .gap_1()
24527        .px_0p5()
24528        .pb_1()
24529        .border_x_1()
24530        .border_b_1()
24531        .border_color(cx.theme().colors().border_variant)
24532        .rounded_b_lg()
24533        .bg(cx.theme().colors().editor_background)
24534        .gap_1()
24535        .block_mouse_except_scroll()
24536        .shadow_md()
24537        .child(if status.has_secondary_hunk() {
24538            Button::new(("stage", row as u64), "Stage")
24539                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24540                .tooltip({
24541                    let focus_handle = editor.focus_handle(cx);
24542                    move |window, cx| {
24543                        Tooltip::for_action_in(
24544                            "Stage Hunk",
24545                            &::git::ToggleStaged,
24546                            &focus_handle,
24547                            window,
24548                            cx,
24549                        )
24550                    }
24551                })
24552                .on_click({
24553                    let editor = editor.clone();
24554                    move |_event, _window, cx| {
24555                        editor.update(cx, |editor, cx| {
24556                            editor.stage_or_unstage_diff_hunks(
24557                                true,
24558                                vec![hunk_range.start..hunk_range.start],
24559                                cx,
24560                            );
24561                        });
24562                    }
24563                })
24564        } else {
24565            Button::new(("unstage", row as u64), "Unstage")
24566                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24567                .tooltip({
24568                    let focus_handle = editor.focus_handle(cx);
24569                    move |window, cx| {
24570                        Tooltip::for_action_in(
24571                            "Unstage Hunk",
24572                            &::git::ToggleStaged,
24573                            &focus_handle,
24574                            window,
24575                            cx,
24576                        )
24577                    }
24578                })
24579                .on_click({
24580                    let editor = editor.clone();
24581                    move |_event, _window, cx| {
24582                        editor.update(cx, |editor, cx| {
24583                            editor.stage_or_unstage_diff_hunks(
24584                                false,
24585                                vec![hunk_range.start..hunk_range.start],
24586                                cx,
24587                            );
24588                        });
24589                    }
24590                })
24591        })
24592        .child(
24593            Button::new(("restore", row as u64), "Restore")
24594                .tooltip({
24595                    let focus_handle = editor.focus_handle(cx);
24596                    move |window, cx| {
24597                        Tooltip::for_action_in(
24598                            "Restore Hunk",
24599                            &::git::Restore,
24600                            &focus_handle,
24601                            window,
24602                            cx,
24603                        )
24604                    }
24605                })
24606                .on_click({
24607                    let editor = editor.clone();
24608                    move |_event, window, cx| {
24609                        editor.update(cx, |editor, cx| {
24610                            let snapshot = editor.snapshot(window, cx);
24611                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24612                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24613                        });
24614                    }
24615                })
24616                .disabled(is_created_file),
24617        )
24618        .when(
24619            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24620            |el| {
24621                el.child(
24622                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24623                        .shape(IconButtonShape::Square)
24624                        .icon_size(IconSize::Small)
24625                        // .disabled(!has_multiple_hunks)
24626                        .tooltip({
24627                            let focus_handle = editor.focus_handle(cx);
24628                            move |window, cx| {
24629                                Tooltip::for_action_in(
24630                                    "Next Hunk",
24631                                    &GoToHunk,
24632                                    &focus_handle,
24633                                    window,
24634                                    cx,
24635                                )
24636                            }
24637                        })
24638                        .on_click({
24639                            let editor = editor.clone();
24640                            move |_event, window, cx| {
24641                                editor.update(cx, |editor, cx| {
24642                                    let snapshot = editor.snapshot(window, cx);
24643                                    let position =
24644                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24645                                    editor.go_to_hunk_before_or_after_position(
24646                                        &snapshot,
24647                                        position,
24648                                        Direction::Next,
24649                                        window,
24650                                        cx,
24651                                    );
24652                                    editor.expand_selected_diff_hunks(cx);
24653                                });
24654                            }
24655                        }),
24656                )
24657                .child(
24658                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24659                        .shape(IconButtonShape::Square)
24660                        .icon_size(IconSize::Small)
24661                        // .disabled(!has_multiple_hunks)
24662                        .tooltip({
24663                            let focus_handle = editor.focus_handle(cx);
24664                            move |window, cx| {
24665                                Tooltip::for_action_in(
24666                                    "Previous Hunk",
24667                                    &GoToPreviousHunk,
24668                                    &focus_handle,
24669                                    window,
24670                                    cx,
24671                                )
24672                            }
24673                        })
24674                        .on_click({
24675                            let editor = editor.clone();
24676                            move |_event, window, cx| {
24677                                editor.update(cx, |editor, cx| {
24678                                    let snapshot = editor.snapshot(window, cx);
24679                                    let point =
24680                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24681                                    editor.go_to_hunk_before_or_after_position(
24682                                        &snapshot,
24683                                        point,
24684                                        Direction::Prev,
24685                                        window,
24686                                        cx,
24687                                    );
24688                                    editor.expand_selected_diff_hunks(cx);
24689                                });
24690                            }
24691                        }),
24692                )
24693            },
24694        )
24695        .into_any_element()
24696}
24697
24698pub fn multibuffer_context_lines(cx: &App) -> u32 {
24699    EditorSettings::try_get(cx)
24700        .map(|settings| settings.excerpt_context_lines)
24701        .unwrap_or(2)
24702        .min(32)
24703}