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};
  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    scroll::{ScrollOffset, ScrollPixelOffset},
  214    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  215};
  216
  217pub const FILE_HEADER_HEIGHT: u32 = 2;
  218pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  219const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  220const MAX_LINE_LEN: usize = 1024;
  221const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  222const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  223pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  224#[doc(hidden)]
  225pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  226pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  227
  228pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  230pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  231
  232pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  233pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  234pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  235
  236pub type RenderDiffHunkControlsFn = Arc<
  237    dyn Fn(
  238        u32,
  239        &DiffHunkStatus,
  240        Range<Anchor>,
  241        bool,
  242        Pixels,
  243        &Entity<Editor>,
  244        &mut Window,
  245        &mut App,
  246    ) -> AnyElement,
  247>;
  248
  249enum ReportEditorEvent {
  250    Saved { auto_saved: bool },
  251    EditorOpened,
  252    Closed,
  253}
  254
  255impl ReportEditorEvent {
  256    pub fn event_type(&self) -> &'static str {
  257        match self {
  258            Self::Saved { .. } => "Editor Saved",
  259            Self::EditorOpened => "Editor Opened",
  260            Self::Closed => "Editor Closed",
  261        }
  262    }
  263}
  264
  265struct InlineValueCache {
  266    enabled: bool,
  267    inlays: Vec<InlayId>,
  268    refresh_task: Task<Option<()>>,
  269}
  270
  271impl InlineValueCache {
  272    fn new(enabled: bool) -> Self {
  273        Self {
  274            enabled,
  275            inlays: Vec::new(),
  276            refresh_task: Task::ready(None),
  277        }
  278    }
  279}
  280
  281#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  282pub enum InlayId {
  283    EditPrediction(u32),
  284    DebuggerValue(u32),
  285    // LSP
  286    Hint(u32),
  287    Color(u32),
  288}
  289
  290impl InlayId {
  291    fn id(&self) -> u32 {
  292        match self {
  293            Self::EditPrediction(id) => *id,
  294            Self::DebuggerValue(id) => *id,
  295            Self::Hint(id) => *id,
  296            Self::Color(id) => *id,
  297        }
  298    }
  299}
  300
  301pub enum ActiveDebugLine {}
  302pub enum DebugStackFrameLine {}
  303enum DocumentHighlightRead {}
  304enum DocumentHighlightWrite {}
  305enum InputComposition {}
  306pub enum PendingInput {}
  307enum SelectedTextHighlight {}
  308
  309pub enum ConflictsOuter {}
  310pub enum ConflictsOurs {}
  311pub enum ConflictsTheirs {}
  312pub enum ConflictsOursMarker {}
  313pub enum ConflictsTheirsMarker {}
  314
  315#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  316pub enum Navigated {
  317    Yes,
  318    No,
  319}
  320
  321impl Navigated {
  322    pub fn from_bool(yes: bool) -> Navigated {
  323        if yes { Navigated::Yes } else { Navigated::No }
  324    }
  325}
  326
  327#[derive(Debug, Clone, PartialEq, Eq)]
  328enum DisplayDiffHunk {
  329    Folded {
  330        display_row: DisplayRow,
  331    },
  332    Unfolded {
  333        is_created_file: bool,
  334        diff_base_byte_range: Range<usize>,
  335        display_row_range: Range<DisplayRow>,
  336        multi_buffer_range: Range<Anchor>,
  337        status: DiffHunkStatus,
  338    },
  339}
  340
  341pub enum HideMouseCursorOrigin {
  342    TypingAction,
  343    MovementAction,
  344}
  345
  346pub fn init_settings(cx: &mut App) {
  347    EditorSettings::register(cx);
  348}
  349
  350pub fn init(cx: &mut App) {
  351    init_settings(cx);
  352
  353    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  354
  355    workspace::register_project_item::<Editor>(cx);
  356    workspace::FollowableViewRegistry::register::<Editor>(cx);
  357    workspace::register_serializable_item::<Editor>(cx);
  358
  359    cx.observe_new(
  360        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  361            workspace.register_action(Editor::new_file);
  362            workspace.register_action(Editor::new_file_vertical);
  363            workspace.register_action(Editor::new_file_horizontal);
  364            workspace.register_action(Editor::cancel_language_server_work);
  365            workspace.register_action(Editor::toggle_focus);
  366        },
  367    )
  368    .detach();
  369
  370    cx.on_action(move |_: &workspace::NewFile, cx| {
  371        let app_state = workspace::AppState::global(cx);
  372        if let Some(app_state) = app_state.upgrade() {
  373            workspace::open_new(
  374                Default::default(),
  375                app_state,
  376                cx,
  377                |workspace, window, cx| {
  378                    Editor::new_file(workspace, &Default::default(), window, cx)
  379                },
  380            )
  381            .detach();
  382        }
  383    });
  384    cx.on_action(move |_: &workspace::NewWindow, cx| {
  385        let app_state = workspace::AppState::global(cx);
  386        if let Some(app_state) = app_state.upgrade() {
  387            workspace::open_new(
  388                Default::default(),
  389                app_state,
  390                cx,
  391                |workspace, window, cx| {
  392                    cx.activate(true);
  393                    Editor::new_file(workspace, &Default::default(), window, cx)
  394                },
  395            )
  396            .detach();
  397        }
  398    });
  399}
  400
  401pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  402    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  403}
  404
  405pub trait DiagnosticRenderer {
  406    fn render_group(
  407        &self,
  408        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  409        buffer_id: BufferId,
  410        snapshot: EditorSnapshot,
  411        editor: WeakEntity<Editor>,
  412        cx: &mut App,
  413    ) -> Vec<BlockProperties<Anchor>>;
  414
  415    fn render_hover(
  416        &self,
  417        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  418        range: Range<Point>,
  419        buffer_id: BufferId,
  420        cx: &mut App,
  421    ) -> Option<Entity<markdown::Markdown>>;
  422
  423    fn open_link(
  424        &self,
  425        editor: &mut Editor,
  426        link: SharedString,
  427        window: &mut Window,
  428        cx: &mut Context<Editor>,
  429    );
  430}
  431
  432pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  433
  434impl GlobalDiagnosticRenderer {
  435    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  436        cx.try_global::<Self>().map(|g| g.0.clone())
  437    }
  438}
  439
  440impl gpui::Global for GlobalDiagnosticRenderer {}
  441pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  442    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  443}
  444
  445pub struct SearchWithinRange;
  446
  447trait InvalidationRegion {
  448    fn ranges(&self) -> &[Range<Anchor>];
  449}
  450
  451#[derive(Clone, Debug, PartialEq)]
  452pub enum SelectPhase {
  453    Begin {
  454        position: DisplayPoint,
  455        add: bool,
  456        click_count: usize,
  457    },
  458    BeginColumnar {
  459        position: DisplayPoint,
  460        reset: bool,
  461        mode: ColumnarMode,
  462        goal_column: u32,
  463    },
  464    Extend {
  465        position: DisplayPoint,
  466        click_count: usize,
  467    },
  468    Update {
  469        position: DisplayPoint,
  470        goal_column: u32,
  471        scroll_delta: gpui::Point<f32>,
  472    },
  473    End,
  474}
  475
  476#[derive(Clone, Debug, PartialEq)]
  477pub enum ColumnarMode {
  478    FromMouse,
  479    FromSelection,
  480}
  481
  482#[derive(Clone, Debug)]
  483pub enum SelectMode {
  484    Character,
  485    Word(Range<Anchor>),
  486    Line(Range<Anchor>),
  487    All,
  488}
  489
  490#[derive(Clone, PartialEq, Eq, Debug)]
  491pub enum EditorMode {
  492    SingleLine,
  493    AutoHeight {
  494        min_lines: usize,
  495        max_lines: Option<usize>,
  496    },
  497    Full {
  498        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  499        scale_ui_elements_with_buffer_font_size: bool,
  500        /// When set to `true`, the editor will render a background for the active line.
  501        show_active_line_background: bool,
  502        /// When set to `true`, the editor's height will be determined by its content.
  503        sized_by_content: bool,
  504    },
  505    Minimap {
  506        parent: WeakEntity<Editor>,
  507    },
  508}
  509
  510impl EditorMode {
  511    pub fn full() -> Self {
  512        Self::Full {
  513            scale_ui_elements_with_buffer_font_size: true,
  514            show_active_line_background: true,
  515            sized_by_content: false,
  516        }
  517    }
  518
  519    #[inline]
  520    pub fn is_full(&self) -> bool {
  521        matches!(self, Self::Full { .. })
  522    }
  523
  524    #[inline]
  525    pub fn is_single_line(&self) -> bool {
  526        matches!(self, Self::SingleLine { .. })
  527    }
  528
  529    #[inline]
  530    fn is_minimap(&self) -> bool {
  531        matches!(self, Self::Minimap { .. })
  532    }
  533}
  534
  535#[derive(Copy, Clone, Debug)]
  536pub enum SoftWrap {
  537    /// Prefer not to wrap at all.
  538    ///
  539    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  540    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  541    GitDiff,
  542    /// Prefer a single line generally, unless an overly long line is encountered.
  543    None,
  544    /// Soft wrap lines that exceed the editor width.
  545    EditorWidth,
  546    /// Soft wrap lines at the preferred line length.
  547    Column(u32),
  548    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  549    Bounded(u32),
  550}
  551
  552#[derive(Clone)]
  553pub struct EditorStyle {
  554    pub background: Hsla,
  555    pub border: Hsla,
  556    pub local_player: PlayerColor,
  557    pub text: TextStyle,
  558    pub scrollbar_width: Pixels,
  559    pub syntax: Arc<SyntaxTheme>,
  560    pub status: StatusColors,
  561    pub inlay_hints_style: HighlightStyle,
  562    pub edit_prediction_styles: EditPredictionStyles,
  563    pub unnecessary_code_fade: f32,
  564    pub show_underlines: bool,
  565}
  566
  567impl Default for EditorStyle {
  568    fn default() -> Self {
  569        Self {
  570            background: Hsla::default(),
  571            border: Hsla::default(),
  572            local_player: PlayerColor::default(),
  573            text: TextStyle::default(),
  574            scrollbar_width: Pixels::default(),
  575            syntax: Default::default(),
  576            // HACK: Status colors don't have a real default.
  577            // We should look into removing the status colors from the editor
  578            // style and retrieve them directly from the theme.
  579            status: StatusColors::dark(),
  580            inlay_hints_style: HighlightStyle::default(),
  581            edit_prediction_styles: EditPredictionStyles {
  582                insertion: HighlightStyle::default(),
  583                whitespace: HighlightStyle::default(),
  584            },
  585            unnecessary_code_fade: Default::default(),
  586            show_underlines: true,
  587        }
  588    }
  589}
  590
  591pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  592    let show_background = language_settings::language_settings(None, None, cx)
  593        .inlay_hints
  594        .show_background;
  595
  596    let mut style = cx.theme().syntax().get("hint");
  597
  598    if style.color.is_none() {
  599        style.color = Some(cx.theme().status().hint);
  600    }
  601
  602    if !show_background {
  603        style.background_color = None;
  604        return style;
  605    }
  606
  607    if style.background_color.is_none() {
  608        style.background_color = Some(cx.theme().status().hint_background);
  609    }
  610
  611    style
  612}
  613
  614pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  615    EditPredictionStyles {
  616        insertion: HighlightStyle {
  617            color: Some(cx.theme().status().predictive),
  618            ..HighlightStyle::default()
  619        },
  620        whitespace: HighlightStyle {
  621            background_color: Some(cx.theme().status().created_background),
  622            ..HighlightStyle::default()
  623        },
  624    }
  625}
  626
  627type CompletionId = usize;
  628
  629pub(crate) enum EditDisplayMode {
  630    TabAccept,
  631    DiffPopover,
  632    Inline,
  633}
  634
  635enum EditPrediction {
  636    Edit {
  637        edits: Vec<(Range<Anchor>, String)>,
  638        edit_preview: Option<EditPreview>,
  639        display_mode: EditDisplayMode,
  640        snapshot: BufferSnapshot,
  641    },
  642    /// Move to a specific location in the active editor
  643    MoveWithin {
  644        target: Anchor,
  645        snapshot: BufferSnapshot,
  646    },
  647    /// Move to a specific location in a different editor (not the active one)
  648    MoveOutside {
  649        target: language::Anchor,
  650        snapshot: BufferSnapshot,
  651    },
  652}
  653
  654struct EditPredictionState {
  655    inlay_ids: Vec<InlayId>,
  656    completion: EditPrediction,
  657    completion_id: Option<SharedString>,
  658    invalidation_range: Option<Range<Anchor>>,
  659}
  660
  661enum EditPredictionSettings {
  662    Disabled,
  663    Enabled {
  664        show_in_menu: bool,
  665        preview_requires_modifier: bool,
  666    },
  667}
  668
  669enum EditPredictionHighlight {}
  670
  671#[derive(Debug, Clone)]
  672struct InlineDiagnostic {
  673    message: SharedString,
  674    group_id: usize,
  675    is_primary: bool,
  676    start: Point,
  677    severity: lsp::DiagnosticSeverity,
  678}
  679
  680pub enum MenuEditPredictionsPolicy {
  681    Never,
  682    ByProvider,
  683}
  684
  685pub enum EditPredictionPreview {
  686    /// Modifier is not pressed
  687    Inactive { released_too_fast: bool },
  688    /// Modifier pressed
  689    Active {
  690        since: Instant,
  691        previous_scroll_position: Option<ScrollAnchor>,
  692    },
  693}
  694
  695impl EditPredictionPreview {
  696    pub fn released_too_fast(&self) -> bool {
  697        match self {
  698            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  699            EditPredictionPreview::Active { .. } => false,
  700        }
  701    }
  702
  703    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  704        if let EditPredictionPreview::Active {
  705            previous_scroll_position,
  706            ..
  707        } = self
  708        {
  709            *previous_scroll_position = scroll_position;
  710        }
  711    }
  712}
  713
  714pub struct ContextMenuOptions {
  715    pub min_entries_visible: usize,
  716    pub max_entries_visible: usize,
  717    pub placement: Option<ContextMenuPlacement>,
  718}
  719
  720#[derive(Debug, Clone, PartialEq, Eq)]
  721pub enum ContextMenuPlacement {
  722    Above,
  723    Below,
  724}
  725
  726#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  727struct EditorActionId(usize);
  728
  729impl EditorActionId {
  730    pub fn post_inc(&mut self) -> Self {
  731        let answer = self.0;
  732
  733        *self = Self(answer + 1);
  734
  735        Self(answer)
  736    }
  737}
  738
  739// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  740// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  741
  742type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  743type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  744
  745#[derive(Default)]
  746struct ScrollbarMarkerState {
  747    scrollbar_size: Size<Pixels>,
  748    dirty: bool,
  749    markers: Arc<[PaintQuad]>,
  750    pending_refresh: Option<Task<Result<()>>>,
  751}
  752
  753impl ScrollbarMarkerState {
  754    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  755        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  756    }
  757}
  758
  759#[derive(Clone, Copy, PartialEq, Eq)]
  760pub enum MinimapVisibility {
  761    Disabled,
  762    Enabled {
  763        /// The configuration currently present in the users settings.
  764        setting_configuration: bool,
  765        /// Whether to override the currently set visibility from the users setting.
  766        toggle_override: bool,
  767    },
  768}
  769
  770impl MinimapVisibility {
  771    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  772        if mode.is_full() {
  773            Self::Enabled {
  774                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  775                toggle_override: false,
  776            }
  777        } else {
  778            Self::Disabled
  779        }
  780    }
  781
  782    fn hidden(&self) -> Self {
  783        match *self {
  784            Self::Enabled {
  785                setting_configuration,
  786                ..
  787            } => Self::Enabled {
  788                setting_configuration,
  789                toggle_override: setting_configuration,
  790            },
  791            Self::Disabled => Self::Disabled,
  792        }
  793    }
  794
  795    fn disabled(&self) -> bool {
  796        matches!(*self, Self::Disabled)
  797    }
  798
  799    fn settings_visibility(&self) -> bool {
  800        match *self {
  801            Self::Enabled {
  802                setting_configuration,
  803                ..
  804            } => setting_configuration,
  805            _ => false,
  806        }
  807    }
  808
  809    fn visible(&self) -> bool {
  810        match *self {
  811            Self::Enabled {
  812                setting_configuration,
  813                toggle_override,
  814            } => setting_configuration ^ toggle_override,
  815            _ => false,
  816        }
  817    }
  818
  819    fn toggle_visibility(&self) -> Self {
  820        match *self {
  821            Self::Enabled {
  822                toggle_override,
  823                setting_configuration,
  824            } => Self::Enabled {
  825                setting_configuration,
  826                toggle_override: !toggle_override,
  827            },
  828            Self::Disabled => Self::Disabled,
  829        }
  830    }
  831}
  832
  833#[derive(Clone, Debug)]
  834struct RunnableTasks {
  835    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  836    offset: multi_buffer::Anchor,
  837    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  838    column: u32,
  839    // Values of all named captures, including those starting with '_'
  840    extra_variables: HashMap<String, String>,
  841    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  842    context_range: Range<BufferOffset>,
  843}
  844
  845impl RunnableTasks {
  846    fn resolve<'a>(
  847        &'a self,
  848        cx: &'a task::TaskContext,
  849    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  850        self.templates.iter().filter_map(|(kind, template)| {
  851            template
  852                .resolve_task(&kind.to_id_base(), cx)
  853                .map(|task| (kind.clone(), task))
  854        })
  855    }
  856}
  857
  858#[derive(Clone)]
  859pub struct ResolvedTasks {
  860    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  861    position: Anchor,
  862}
  863
  864#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  865struct BufferOffset(usize);
  866
  867/// Addons allow storing per-editor state in other crates (e.g. Vim)
  868pub trait Addon: 'static {
  869    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  870
  871    fn render_buffer_header_controls(
  872        &self,
  873        _: &ExcerptInfo,
  874        _: &Window,
  875        _: &App,
  876    ) -> Option<AnyElement> {
  877        None
  878    }
  879
  880    fn to_any(&self) -> &dyn std::any::Any;
  881
  882    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  883        None
  884    }
  885}
  886
  887struct ChangeLocation {
  888    current: Option<Vec<Anchor>>,
  889    original: Vec<Anchor>,
  890}
  891impl ChangeLocation {
  892    fn locations(&self) -> &[Anchor] {
  893        self.current.as_ref().unwrap_or(&self.original)
  894    }
  895}
  896
  897/// A set of caret positions, registered when the editor was edited.
  898pub struct ChangeList {
  899    changes: Vec<ChangeLocation>,
  900    /// Currently "selected" change.
  901    position: Option<usize>,
  902}
  903
  904impl ChangeList {
  905    pub fn new() -> Self {
  906        Self {
  907            changes: Vec::new(),
  908            position: None,
  909        }
  910    }
  911
  912    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  913    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  914    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  915        if self.changes.is_empty() {
  916            return None;
  917        }
  918
  919        let prev = self.position.unwrap_or(self.changes.len());
  920        let next = if direction == Direction::Prev {
  921            prev.saturating_sub(count)
  922        } else {
  923            (prev + count).min(self.changes.len() - 1)
  924        };
  925        self.position = Some(next);
  926        self.changes.get(next).map(|change| change.locations())
  927    }
  928
  929    /// Adds a new change to the list, resetting the change list position.
  930    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  931        self.position.take();
  932        if let Some(last) = self.changes.last_mut()
  933            && group
  934        {
  935            last.current = Some(new_positions)
  936        } else {
  937            self.changes.push(ChangeLocation {
  938                original: new_positions,
  939                current: None,
  940            });
  941        }
  942    }
  943
  944    pub fn last(&self) -> Option<&[Anchor]> {
  945        self.changes.last().map(|change| change.locations())
  946    }
  947
  948    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  949        self.changes.last().map(|change| change.original.as_slice())
  950    }
  951
  952    pub fn invert_last_group(&mut self) {
  953        if let Some(last) = self.changes.last_mut()
  954            && let Some(current) = last.current.as_mut()
  955        {
  956            mem::swap(&mut last.original, current);
  957        }
  958    }
  959}
  960
  961#[derive(Clone)]
  962struct InlineBlamePopoverState {
  963    scroll_handle: ScrollHandle,
  964    commit_message: Option<ParsedCommitMessage>,
  965    markdown: Entity<Markdown>,
  966}
  967
  968struct InlineBlamePopover {
  969    position: gpui::Point<Pixels>,
  970    hide_task: Option<Task<()>>,
  971    popover_bounds: Option<Bounds<Pixels>>,
  972    popover_state: InlineBlamePopoverState,
  973    keyboard_grace: bool,
  974}
  975
  976enum SelectionDragState {
  977    /// State when no drag related activity is detected.
  978    None,
  979    /// State when the mouse is down on a selection that is about to be dragged.
  980    ReadyToDrag {
  981        selection: Selection<Anchor>,
  982        click_position: gpui::Point<Pixels>,
  983        mouse_down_time: Instant,
  984    },
  985    /// State when the mouse is dragging the selection in the editor.
  986    Dragging {
  987        selection: Selection<Anchor>,
  988        drop_cursor: Selection<Anchor>,
  989        hide_drop_cursor: bool,
  990    },
  991}
  992
  993enum ColumnarSelectionState {
  994    FromMouse {
  995        selection_tail: Anchor,
  996        display_point: Option<DisplayPoint>,
  997    },
  998    FromSelection {
  999        selection_tail: Anchor,
 1000    },
 1001}
 1002
 1003/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1004/// a breakpoint on them.
 1005#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1006struct PhantomBreakpointIndicator {
 1007    display_row: DisplayRow,
 1008    /// There's a small debounce between hovering over the line and showing the indicator.
 1009    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1010    is_active: bool,
 1011    collides_with_existing_breakpoint: bool,
 1012}
 1013
 1014/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1015///
 1016/// See the [module level documentation](self) for more information.
 1017pub struct Editor {
 1018    focus_handle: FocusHandle,
 1019    last_focused_descendant: Option<WeakFocusHandle>,
 1020    /// The text buffer being edited
 1021    buffer: Entity<MultiBuffer>,
 1022    /// Map of how text in the buffer should be displayed.
 1023    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1024    pub display_map: Entity<DisplayMap>,
 1025    placeholder_display_map: Option<Entity<DisplayMap>>,
 1026    pub selections: SelectionsCollection,
 1027    pub scroll_manager: ScrollManager,
 1028    /// When inline assist editors are linked, they all render cursors because
 1029    /// typing enters text into each of them, even the ones that aren't focused.
 1030    pub(crate) show_cursor_when_unfocused: bool,
 1031    columnar_selection_state: Option<ColumnarSelectionState>,
 1032    add_selections_state: Option<AddSelectionsState>,
 1033    select_next_state: Option<SelectNextState>,
 1034    select_prev_state: Option<SelectNextState>,
 1035    selection_history: SelectionHistory,
 1036    defer_selection_effects: bool,
 1037    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1038    autoclose_regions: Vec<AutocloseRegion>,
 1039    snippet_stack: InvalidationStack<SnippetState>,
 1040    select_syntax_node_history: SelectSyntaxNodeHistory,
 1041    ime_transaction: Option<TransactionId>,
 1042    pub diagnostics_max_severity: DiagnosticSeverity,
 1043    active_diagnostics: ActiveDiagnostic,
 1044    show_inline_diagnostics: bool,
 1045    inline_diagnostics_update: Task<()>,
 1046    inline_diagnostics_enabled: bool,
 1047    diagnostics_enabled: bool,
 1048    word_completions_enabled: bool,
 1049    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1050    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1051    hard_wrap: Option<usize>,
 1052    project: Option<Entity<Project>>,
 1053    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1054    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1055    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1056    blink_manager: Entity<BlinkManager>,
 1057    show_cursor_names: bool,
 1058    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1059    pub show_local_selections: bool,
 1060    mode: EditorMode,
 1061    show_breadcrumbs: bool,
 1062    show_gutter: bool,
 1063    show_scrollbars: ScrollbarAxes,
 1064    minimap_visibility: MinimapVisibility,
 1065    offset_content: bool,
 1066    disable_expand_excerpt_buttons: bool,
 1067    show_line_numbers: Option<bool>,
 1068    use_relative_line_numbers: Option<bool>,
 1069    show_git_diff_gutter: Option<bool>,
 1070    show_code_actions: Option<bool>,
 1071    show_runnables: Option<bool>,
 1072    show_breakpoints: Option<bool>,
 1073    show_wrap_guides: Option<bool>,
 1074    show_indent_guides: Option<bool>,
 1075    highlight_order: usize,
 1076    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1077    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1078    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1079    scrollbar_marker_state: ScrollbarMarkerState,
 1080    active_indent_guides_state: ActiveIndentGuidesState,
 1081    nav_history: Option<ItemNavHistory>,
 1082    context_menu: RefCell<Option<CodeContextMenu>>,
 1083    context_menu_options: Option<ContextMenuOptions>,
 1084    mouse_context_menu: Option<MouseContextMenu>,
 1085    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1086    inline_blame_popover: Option<InlineBlamePopover>,
 1087    inline_blame_popover_show_task: Option<Task<()>>,
 1088    signature_help_state: SignatureHelpState,
 1089    auto_signature_help: Option<bool>,
 1090    find_all_references_task_sources: Vec<Anchor>,
 1091    next_completion_id: CompletionId,
 1092    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1093    code_actions_task: Option<Task<Result<()>>>,
 1094    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1096    document_highlights_task: Option<Task<()>>,
 1097    linked_editing_range_task: Option<Task<Option<()>>>,
 1098    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1099    pending_rename: Option<RenameState>,
 1100    searchable: bool,
 1101    cursor_shape: CursorShape,
 1102    current_line_highlight: Option<CurrentLineHighlight>,
 1103    collapse_matches: bool,
 1104    autoindent_mode: Option<AutoindentMode>,
 1105    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1106    input_enabled: bool,
 1107    use_modal_editing: bool,
 1108    read_only: bool,
 1109    leader_id: Option<CollaboratorId>,
 1110    remote_id: Option<ViewId>,
 1111    pub hover_state: HoverState,
 1112    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1113    gutter_hovered: bool,
 1114    hovered_link_state: Option<HoveredLinkState>,
 1115    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1116    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1117    active_edit_prediction: Option<EditPredictionState>,
 1118    /// Used to prevent flickering as the user types while the menu is open
 1119    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1120    edit_prediction_settings: EditPredictionSettings,
 1121    edit_predictions_hidden_for_vim_mode: bool,
 1122    show_edit_predictions_override: Option<bool>,
 1123    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1124    edit_prediction_preview: EditPredictionPreview,
 1125    edit_prediction_indent_conflict: bool,
 1126    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1127    inlay_hint_cache: InlayHintCache,
 1128    next_inlay_id: u32,
 1129    next_color_inlay_id: u32,
 1130    _subscriptions: Vec<Subscription>,
 1131    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1132    gutter_dimensions: GutterDimensions,
 1133    style: Option<EditorStyle>,
 1134    text_style_refinement: Option<TextStyleRefinement>,
 1135    next_editor_action_id: EditorActionId,
 1136    editor_actions: Rc<
 1137        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1138    >,
 1139    use_autoclose: bool,
 1140    use_auto_surround: bool,
 1141    auto_replace_emoji_shortcode: bool,
 1142    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1143    show_git_blame_gutter: bool,
 1144    show_git_blame_inline: bool,
 1145    show_git_blame_inline_delay_task: Option<Task<()>>,
 1146    git_blame_inline_enabled: bool,
 1147    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1148    serialize_dirty_buffers: bool,
 1149    show_selection_menu: Option<bool>,
 1150    blame: Option<Entity<GitBlame>>,
 1151    blame_subscription: Option<Subscription>,
 1152    custom_context_menu: Option<
 1153        Box<
 1154            dyn 'static
 1155                + Fn(
 1156                    &mut Self,
 1157                    DisplayPoint,
 1158                    &mut Window,
 1159                    &mut Context<Self>,
 1160                ) -> Option<Entity<ui::ContextMenu>>,
 1161        >,
 1162    >,
 1163    last_bounds: Option<Bounds<Pixels>>,
 1164    last_position_map: Option<Rc<PositionMap>>,
 1165    expect_bounds_change: Option<Bounds<Pixels>>,
 1166    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1167    tasks_update_task: Option<Task<()>>,
 1168    breakpoint_store: Option<Entity<BreakpointStore>>,
 1169    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1170    hovered_diff_hunk_row: Option<DisplayRow>,
 1171    pull_diagnostics_task: Task<()>,
 1172    in_project_search: bool,
 1173    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1174    breadcrumb_header: Option<String>,
 1175    focused_block: Option<FocusedBlock>,
 1176    next_scroll_position: NextScrollCursorCenterTopBottom,
 1177    addons: HashMap<TypeId, Box<dyn Addon>>,
 1178    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1179    load_diff_task: Option<Shared<Task<()>>>,
 1180    /// Whether we are temporarily displaying a diff other than git's
 1181    temporary_diff_override: bool,
 1182    selection_mark_mode: bool,
 1183    toggle_fold_multiple_buffers: Task<()>,
 1184    _scroll_cursor_center_top_bottom_task: Task<()>,
 1185    serialize_selections: Task<()>,
 1186    serialize_folds: Task<()>,
 1187    mouse_cursor_hidden: bool,
 1188    minimap: Option<Entity<Self>>,
 1189    hide_mouse_mode: HideMouseMode,
 1190    pub change_list: ChangeList,
 1191    inline_value_cache: InlineValueCache,
 1192    selection_drag_state: SelectionDragState,
 1193    colors: Option<LspColorData>,
 1194    folding_newlines: Task<()>,
 1195    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1196}
 1197
 1198#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1199enum NextScrollCursorCenterTopBottom {
 1200    #[default]
 1201    Center,
 1202    Top,
 1203    Bottom,
 1204}
 1205
 1206impl NextScrollCursorCenterTopBottom {
 1207    fn next(&self) -> Self {
 1208        match self {
 1209            Self::Center => Self::Top,
 1210            Self::Top => Self::Bottom,
 1211            Self::Bottom => Self::Center,
 1212        }
 1213    }
 1214}
 1215
 1216#[derive(Clone)]
 1217pub struct EditorSnapshot {
 1218    pub mode: EditorMode,
 1219    show_gutter: bool,
 1220    show_line_numbers: Option<bool>,
 1221    show_git_diff_gutter: Option<bool>,
 1222    show_code_actions: Option<bool>,
 1223    show_runnables: Option<bool>,
 1224    show_breakpoints: Option<bool>,
 1225    git_blame_gutter_max_author_length: Option<usize>,
 1226    pub display_snapshot: DisplaySnapshot,
 1227    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1228    is_focused: bool,
 1229    scroll_anchor: ScrollAnchor,
 1230    ongoing_scroll: OngoingScroll,
 1231    current_line_highlight: CurrentLineHighlight,
 1232    gutter_hovered: bool,
 1233}
 1234
 1235#[derive(Default, Debug, Clone, Copy)]
 1236pub struct GutterDimensions {
 1237    pub left_padding: Pixels,
 1238    pub right_padding: Pixels,
 1239    pub width: Pixels,
 1240    pub margin: Pixels,
 1241    pub git_blame_entries_width: Option<Pixels>,
 1242}
 1243
 1244impl GutterDimensions {
 1245    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1246        Self {
 1247            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1248            ..Default::default()
 1249        }
 1250    }
 1251
 1252    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1253        -cx.text_system().descent(font_id, font_size)
 1254    }
 1255    /// The full width of the space taken up by the gutter.
 1256    pub fn full_width(&self) -> Pixels {
 1257        self.margin + self.width
 1258    }
 1259
 1260    /// The width of the space reserved for the fold indicators,
 1261    /// use alongside 'justify_end' and `gutter_width` to
 1262    /// right align content with the line numbers
 1263    pub fn fold_area_width(&self) -> Pixels {
 1264        self.margin + self.right_padding
 1265    }
 1266}
 1267
 1268struct CharacterDimensions {
 1269    em_width: Pixels,
 1270    em_advance: Pixels,
 1271    line_height: Pixels,
 1272}
 1273
 1274#[derive(Debug)]
 1275pub struct RemoteSelection {
 1276    pub replica_id: ReplicaId,
 1277    pub selection: Selection<Anchor>,
 1278    pub cursor_shape: CursorShape,
 1279    pub collaborator_id: CollaboratorId,
 1280    pub line_mode: bool,
 1281    pub user_name: Option<SharedString>,
 1282    pub color: PlayerColor,
 1283}
 1284
 1285#[derive(Clone, Debug)]
 1286struct SelectionHistoryEntry {
 1287    selections: Arc<[Selection<Anchor>]>,
 1288    select_next_state: Option<SelectNextState>,
 1289    select_prev_state: Option<SelectNextState>,
 1290    add_selections_state: Option<AddSelectionsState>,
 1291}
 1292
 1293#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1294enum SelectionHistoryMode {
 1295    Normal,
 1296    Undoing,
 1297    Redoing,
 1298    Skipping,
 1299}
 1300
 1301#[derive(Clone, PartialEq, Eq, Hash)]
 1302struct HoveredCursor {
 1303    replica_id: u16,
 1304    selection_id: usize,
 1305}
 1306
 1307impl Default for SelectionHistoryMode {
 1308    fn default() -> Self {
 1309        Self::Normal
 1310    }
 1311}
 1312
 1313#[derive(Debug)]
 1314/// SelectionEffects controls the side-effects of updating the selection.
 1315///
 1316/// The default behaviour does "what you mostly want":
 1317/// - it pushes to the nav history if the cursor moved by >10 lines
 1318/// - it re-triggers completion requests
 1319/// - it scrolls to fit
 1320///
 1321/// You might want to modify these behaviours. For example when doing a "jump"
 1322/// like go to definition, we always want to add to nav history; but when scrolling
 1323/// in vim mode we never do.
 1324///
 1325/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1326/// move.
 1327#[derive(Clone)]
 1328pub struct SelectionEffects {
 1329    nav_history: Option<bool>,
 1330    completions: bool,
 1331    scroll: Option<Autoscroll>,
 1332}
 1333
 1334impl Default for SelectionEffects {
 1335    fn default() -> Self {
 1336        Self {
 1337            nav_history: None,
 1338            completions: true,
 1339            scroll: Some(Autoscroll::fit()),
 1340        }
 1341    }
 1342}
 1343impl SelectionEffects {
 1344    pub fn scroll(scroll: Autoscroll) -> Self {
 1345        Self {
 1346            scroll: Some(scroll),
 1347            ..Default::default()
 1348        }
 1349    }
 1350
 1351    pub fn no_scroll() -> Self {
 1352        Self {
 1353            scroll: None,
 1354            ..Default::default()
 1355        }
 1356    }
 1357
 1358    pub fn completions(self, completions: bool) -> Self {
 1359        Self {
 1360            completions,
 1361            ..self
 1362        }
 1363    }
 1364
 1365    pub fn nav_history(self, nav_history: bool) -> Self {
 1366        Self {
 1367            nav_history: Some(nav_history),
 1368            ..self
 1369        }
 1370    }
 1371}
 1372
 1373struct DeferredSelectionEffectsState {
 1374    changed: bool,
 1375    effects: SelectionEffects,
 1376    old_cursor_position: Anchor,
 1377    history_entry: SelectionHistoryEntry,
 1378}
 1379
 1380#[derive(Default)]
 1381struct SelectionHistory {
 1382    #[allow(clippy::type_complexity)]
 1383    selections_by_transaction:
 1384        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1385    mode: SelectionHistoryMode,
 1386    undo_stack: VecDeque<SelectionHistoryEntry>,
 1387    redo_stack: VecDeque<SelectionHistoryEntry>,
 1388}
 1389
 1390impl SelectionHistory {
 1391    #[track_caller]
 1392    fn insert_transaction(
 1393        &mut self,
 1394        transaction_id: TransactionId,
 1395        selections: Arc<[Selection<Anchor>]>,
 1396    ) {
 1397        if selections.is_empty() {
 1398            log::error!(
 1399                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1400                std::panic::Location::caller()
 1401            );
 1402            return;
 1403        }
 1404        self.selections_by_transaction
 1405            .insert(transaction_id, (selections, None));
 1406    }
 1407
 1408    #[allow(clippy::type_complexity)]
 1409    fn transaction(
 1410        &self,
 1411        transaction_id: TransactionId,
 1412    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1413        self.selections_by_transaction.get(&transaction_id)
 1414    }
 1415
 1416    #[allow(clippy::type_complexity)]
 1417    fn transaction_mut(
 1418        &mut self,
 1419        transaction_id: TransactionId,
 1420    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1421        self.selections_by_transaction.get_mut(&transaction_id)
 1422    }
 1423
 1424    fn push(&mut self, entry: SelectionHistoryEntry) {
 1425        if !entry.selections.is_empty() {
 1426            match self.mode {
 1427                SelectionHistoryMode::Normal => {
 1428                    self.push_undo(entry);
 1429                    self.redo_stack.clear();
 1430                }
 1431                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1432                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1433                SelectionHistoryMode::Skipping => {}
 1434            }
 1435        }
 1436    }
 1437
 1438    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1439        if self
 1440            .undo_stack
 1441            .back()
 1442            .is_none_or(|e| e.selections != entry.selections)
 1443        {
 1444            self.undo_stack.push_back(entry);
 1445            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1446                self.undo_stack.pop_front();
 1447            }
 1448        }
 1449    }
 1450
 1451    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1452        if self
 1453            .redo_stack
 1454            .back()
 1455            .is_none_or(|e| e.selections != entry.selections)
 1456        {
 1457            self.redo_stack.push_back(entry);
 1458            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1459                self.redo_stack.pop_front();
 1460            }
 1461        }
 1462    }
 1463}
 1464
 1465#[derive(Clone, Copy)]
 1466pub struct RowHighlightOptions {
 1467    pub autoscroll: bool,
 1468    pub include_gutter: bool,
 1469}
 1470
 1471impl Default for RowHighlightOptions {
 1472    fn default() -> Self {
 1473        Self {
 1474            autoscroll: Default::default(),
 1475            include_gutter: true,
 1476        }
 1477    }
 1478}
 1479
 1480struct RowHighlight {
 1481    index: usize,
 1482    range: Range<Anchor>,
 1483    color: Hsla,
 1484    options: RowHighlightOptions,
 1485    type_id: TypeId,
 1486}
 1487
 1488#[derive(Clone, Debug)]
 1489struct AddSelectionsState {
 1490    groups: Vec<AddSelectionsGroup>,
 1491}
 1492
 1493#[derive(Clone, Debug)]
 1494struct AddSelectionsGroup {
 1495    above: bool,
 1496    stack: Vec<usize>,
 1497}
 1498
 1499#[derive(Clone)]
 1500struct SelectNextState {
 1501    query: AhoCorasick,
 1502    wordwise: bool,
 1503    done: bool,
 1504}
 1505
 1506impl std::fmt::Debug for SelectNextState {
 1507    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1508        f.debug_struct(std::any::type_name::<Self>())
 1509            .field("wordwise", &self.wordwise)
 1510            .field("done", &self.done)
 1511            .finish()
 1512    }
 1513}
 1514
 1515#[derive(Debug)]
 1516struct AutocloseRegion {
 1517    selection_id: usize,
 1518    range: Range<Anchor>,
 1519    pair: BracketPair,
 1520}
 1521
 1522#[derive(Debug)]
 1523struct SnippetState {
 1524    ranges: Vec<Vec<Range<Anchor>>>,
 1525    active_index: usize,
 1526    choices: Vec<Option<Vec<String>>>,
 1527}
 1528
 1529#[doc(hidden)]
 1530pub struct RenameState {
 1531    pub range: Range<Anchor>,
 1532    pub old_name: Arc<str>,
 1533    pub editor: Entity<Editor>,
 1534    block_id: CustomBlockId,
 1535}
 1536
 1537struct InvalidationStack<T>(Vec<T>);
 1538
 1539struct RegisteredEditPredictionProvider {
 1540    provider: Arc<dyn EditPredictionProviderHandle>,
 1541    _subscription: Subscription,
 1542}
 1543
 1544#[derive(Debug, PartialEq, Eq)]
 1545pub struct ActiveDiagnosticGroup {
 1546    pub active_range: Range<Anchor>,
 1547    pub active_message: String,
 1548    pub group_id: usize,
 1549    pub blocks: HashSet<CustomBlockId>,
 1550}
 1551
 1552#[derive(Debug, PartialEq, Eq)]
 1553
 1554pub(crate) enum ActiveDiagnostic {
 1555    None,
 1556    All,
 1557    Group(ActiveDiagnosticGroup),
 1558}
 1559
 1560#[derive(Serialize, Deserialize, Clone, Debug)]
 1561pub struct ClipboardSelection {
 1562    /// The number of bytes in this selection.
 1563    pub len: usize,
 1564    /// Whether this was a full-line selection.
 1565    pub is_entire_line: bool,
 1566    /// The indentation of the first line when this content was originally copied.
 1567    pub first_line_indent: u32,
 1568}
 1569
 1570// selections, scroll behavior, was newest selection reversed
 1571type SelectSyntaxNodeHistoryState = (
 1572    Box<[Selection<usize>]>,
 1573    SelectSyntaxNodeScrollBehavior,
 1574    bool,
 1575);
 1576
 1577#[derive(Default)]
 1578struct SelectSyntaxNodeHistory {
 1579    stack: Vec<SelectSyntaxNodeHistoryState>,
 1580    // disable temporarily to allow changing selections without losing the stack
 1581    pub disable_clearing: bool,
 1582}
 1583
 1584impl SelectSyntaxNodeHistory {
 1585    pub fn try_clear(&mut self) {
 1586        if !self.disable_clearing {
 1587            self.stack.clear();
 1588        }
 1589    }
 1590
 1591    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1592        self.stack.push(selection);
 1593    }
 1594
 1595    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1596        self.stack.pop()
 1597    }
 1598}
 1599
 1600enum SelectSyntaxNodeScrollBehavior {
 1601    CursorTop,
 1602    FitSelection,
 1603    CursorBottom,
 1604}
 1605
 1606#[derive(Debug)]
 1607pub(crate) struct NavigationData {
 1608    cursor_anchor: Anchor,
 1609    cursor_position: Point,
 1610    scroll_anchor: ScrollAnchor,
 1611    scroll_top_row: u32,
 1612}
 1613
 1614#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1615pub enum GotoDefinitionKind {
 1616    Symbol,
 1617    Declaration,
 1618    Type,
 1619    Implementation,
 1620}
 1621
 1622#[derive(Debug, Clone)]
 1623enum InlayHintRefreshReason {
 1624    ModifiersChanged(bool),
 1625    Toggle(bool),
 1626    SettingsChange(InlayHintSettings),
 1627    NewLinesShown,
 1628    BufferEdited(HashSet<Arc<Language>>),
 1629    RefreshRequested,
 1630    ExcerptsRemoved(Vec<ExcerptId>),
 1631}
 1632
 1633impl InlayHintRefreshReason {
 1634    fn description(&self) -> &'static str {
 1635        match self {
 1636            Self::ModifiersChanged(_) => "modifiers changed",
 1637            Self::Toggle(_) => "toggle",
 1638            Self::SettingsChange(_) => "settings change",
 1639            Self::NewLinesShown => "new lines shown",
 1640            Self::BufferEdited(_) => "buffer edited",
 1641            Self::RefreshRequested => "refresh requested",
 1642            Self::ExcerptsRemoved(_) => "excerpts removed",
 1643        }
 1644    }
 1645}
 1646
 1647pub enum FormatTarget {
 1648    Buffers(HashSet<Entity<Buffer>>),
 1649    Ranges(Vec<Range<MultiBufferPoint>>),
 1650}
 1651
 1652pub(crate) struct FocusedBlock {
 1653    id: BlockId,
 1654    focus_handle: WeakFocusHandle,
 1655}
 1656
 1657#[derive(Clone)]
 1658enum JumpData {
 1659    MultiBufferRow {
 1660        row: MultiBufferRow,
 1661        line_offset_from_top: u32,
 1662    },
 1663    MultiBufferPoint {
 1664        excerpt_id: ExcerptId,
 1665        position: Point,
 1666        anchor: text::Anchor,
 1667        line_offset_from_top: u32,
 1668    },
 1669}
 1670
 1671pub enum MultibufferSelectionMode {
 1672    First,
 1673    All,
 1674}
 1675
 1676#[derive(Clone, Copy, Debug, Default)]
 1677pub struct RewrapOptions {
 1678    pub override_language_settings: bool,
 1679    pub preserve_existing_whitespace: bool,
 1680}
 1681
 1682impl Editor {
 1683    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1684        let buffer = cx.new(|cx| Buffer::local("", cx));
 1685        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1686        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1687    }
 1688
 1689    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1690        let buffer = cx.new(|cx| Buffer::local("", cx));
 1691        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1692        Self::new(EditorMode::full(), buffer, None, window, cx)
 1693    }
 1694
 1695    pub fn auto_height(
 1696        min_lines: usize,
 1697        max_lines: usize,
 1698        window: &mut Window,
 1699        cx: &mut Context<Self>,
 1700    ) -> Self {
 1701        let buffer = cx.new(|cx| Buffer::local("", cx));
 1702        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1703        Self::new(
 1704            EditorMode::AutoHeight {
 1705                min_lines,
 1706                max_lines: Some(max_lines),
 1707            },
 1708            buffer,
 1709            None,
 1710            window,
 1711            cx,
 1712        )
 1713    }
 1714
 1715    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1716    /// The editor grows as tall as needed to fit its content.
 1717    pub fn auto_height_unbounded(
 1718        min_lines: usize,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        let buffer = cx.new(|cx| Buffer::local("", cx));
 1723        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1724        Self::new(
 1725            EditorMode::AutoHeight {
 1726                min_lines,
 1727                max_lines: None,
 1728            },
 1729            buffer,
 1730            None,
 1731            window,
 1732            cx,
 1733        )
 1734    }
 1735
 1736    pub fn for_buffer(
 1737        buffer: Entity<Buffer>,
 1738        project: Option<Entity<Project>>,
 1739        window: &mut Window,
 1740        cx: &mut Context<Self>,
 1741    ) -> Self {
 1742        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1743        Self::new(EditorMode::full(), buffer, project, window, cx)
 1744    }
 1745
 1746    pub fn for_multibuffer(
 1747        buffer: Entity<MultiBuffer>,
 1748        project: Option<Entity<Project>>,
 1749        window: &mut Window,
 1750        cx: &mut Context<Self>,
 1751    ) -> Self {
 1752        Self::new(EditorMode::full(), buffer, project, window, cx)
 1753    }
 1754
 1755    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1756        let mut clone = Self::new(
 1757            self.mode.clone(),
 1758            self.buffer.clone(),
 1759            self.project.clone(),
 1760            window,
 1761            cx,
 1762        );
 1763        self.display_map.update(cx, |display_map, cx| {
 1764            let snapshot = display_map.snapshot(cx);
 1765            clone.display_map.update(cx, |display_map, cx| {
 1766                display_map.set_state(&snapshot, cx);
 1767            });
 1768        });
 1769        clone.folds_did_change(cx);
 1770        clone.selections.clone_state(&self.selections);
 1771        clone.scroll_manager.clone_state(&self.scroll_manager);
 1772        clone.searchable = self.searchable;
 1773        clone.read_only = self.read_only;
 1774        clone
 1775    }
 1776
 1777    pub fn new(
 1778        mode: EditorMode,
 1779        buffer: Entity<MultiBuffer>,
 1780        project: Option<Entity<Project>>,
 1781        window: &mut Window,
 1782        cx: &mut Context<Self>,
 1783    ) -> Self {
 1784        Editor::new_internal(mode, buffer, project, None, window, cx)
 1785    }
 1786
 1787    fn new_internal(
 1788        mode: EditorMode,
 1789        buffer: Entity<MultiBuffer>,
 1790        project: Option<Entity<Project>>,
 1791        display_map: Option<Entity<DisplayMap>>,
 1792        window: &mut Window,
 1793        cx: &mut Context<Self>,
 1794    ) -> Self {
 1795        debug_assert!(
 1796            display_map.is_none() || mode.is_minimap(),
 1797            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1798        );
 1799
 1800        let full_mode = mode.is_full();
 1801        let is_minimap = mode.is_minimap();
 1802        let diagnostics_max_severity = if full_mode {
 1803            EditorSettings::get_global(cx)
 1804                .diagnostics_max_severity
 1805                .unwrap_or(DiagnosticSeverity::Hint)
 1806        } else {
 1807            DiagnosticSeverity::Off
 1808        };
 1809        let style = window.text_style();
 1810        let font_size = style.font_size.to_pixels(window.rem_size());
 1811        let editor = cx.entity().downgrade();
 1812        let fold_placeholder = FoldPlaceholder {
 1813            constrain_width: false,
 1814            render: Arc::new(move |fold_id, fold_range, cx| {
 1815                let editor = editor.clone();
 1816                div()
 1817                    .id(fold_id)
 1818                    .bg(cx.theme().colors().ghost_element_background)
 1819                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1820                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1821                    .rounded_xs()
 1822                    .size_full()
 1823                    .cursor_pointer()
 1824                    .child("")
 1825                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1826                    .on_click(move |_, _window, cx| {
 1827                        editor
 1828                            .update(cx, |editor, cx| {
 1829                                editor.unfold_ranges(
 1830                                    &[fold_range.start..fold_range.end],
 1831                                    true,
 1832                                    false,
 1833                                    cx,
 1834                                );
 1835                                cx.stop_propagation();
 1836                            })
 1837                            .ok();
 1838                    })
 1839                    .into_any()
 1840            }),
 1841            merge_adjacent: true,
 1842            ..FoldPlaceholder::default()
 1843        };
 1844        let display_map = display_map.unwrap_or_else(|| {
 1845            cx.new(|cx| {
 1846                DisplayMap::new(
 1847                    buffer.clone(),
 1848                    style.font(),
 1849                    font_size,
 1850                    None,
 1851                    FILE_HEADER_HEIGHT,
 1852                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1853                    fold_placeholder,
 1854                    diagnostics_max_severity,
 1855                    cx,
 1856                )
 1857            })
 1858        });
 1859
 1860        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1861
 1862        let blink_manager = cx.new(|cx| {
 1863            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1864            if is_minimap {
 1865                blink_manager.disable(cx);
 1866            }
 1867            blink_manager
 1868        });
 1869
 1870        let soft_wrap_mode_override =
 1871            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1872
 1873        let mut project_subscriptions = Vec::new();
 1874        if full_mode && let Some(project) = project.as_ref() {
 1875            project_subscriptions.push(cx.subscribe_in(
 1876                project,
 1877                window,
 1878                |editor, _, event, window, cx| match event {
 1879                    project::Event::RefreshCodeLens => {
 1880                        // we always query lens with actions, without storing them, always refreshing them
 1881                    }
 1882                    project::Event::RefreshInlayHints => {
 1883                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1884                    }
 1885                    project::Event::LanguageServerAdded(..)
 1886                    | project::Event::LanguageServerRemoved(..) => {
 1887                        if editor.tasks_update_task.is_none() {
 1888                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1889                        }
 1890                    }
 1891                    project::Event::SnippetEdit(id, snippet_edits) => {
 1892                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1893                            let focus_handle = editor.focus_handle(cx);
 1894                            if focus_handle.is_focused(window) {
 1895                                let snapshot = buffer.read(cx).snapshot();
 1896                                for (range, snippet) in snippet_edits {
 1897                                    let editor_range =
 1898                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1899                                    editor
 1900                                        .insert_snippet(
 1901                                            &[editor_range],
 1902                                            snippet.clone(),
 1903                                            window,
 1904                                            cx,
 1905                                        )
 1906                                        .ok();
 1907                                }
 1908                            }
 1909                        }
 1910                    }
 1911                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1912                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1913                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1914                        }
 1915                    }
 1916
 1917                    project::Event::EntryRenamed(transaction) => {
 1918                        let Some(workspace) = editor.workspace() else {
 1919                            return;
 1920                        };
 1921                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1922                        else {
 1923                            return;
 1924                        };
 1925                        if active_editor.entity_id() == cx.entity_id() {
 1926                            let edited_buffers_already_open = {
 1927                                let other_editors: Vec<Entity<Editor>> = workspace
 1928                                    .read(cx)
 1929                                    .panes()
 1930                                    .iter()
 1931                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1932                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1933                                    .collect();
 1934
 1935                                transaction.0.keys().all(|buffer| {
 1936                                    other_editors.iter().any(|editor| {
 1937                                        let multi_buffer = editor.read(cx).buffer();
 1938                                        multi_buffer.read(cx).is_singleton()
 1939                                            && multi_buffer.read(cx).as_singleton().map_or(
 1940                                                false,
 1941                                                |singleton| {
 1942                                                    singleton.entity_id() == buffer.entity_id()
 1943                                                },
 1944                                            )
 1945                                    })
 1946                                })
 1947                            };
 1948
 1949                            if !edited_buffers_already_open {
 1950                                let workspace = workspace.downgrade();
 1951                                let transaction = transaction.clone();
 1952                                cx.defer_in(window, move |_, window, cx| {
 1953                                    cx.spawn_in(window, async move |editor, cx| {
 1954                                        Self::open_project_transaction(
 1955                                            &editor,
 1956                                            workspace,
 1957                                            transaction,
 1958                                            "Rename".to_string(),
 1959                                            cx,
 1960                                        )
 1961                                        .await
 1962                                        .ok()
 1963                                    })
 1964                                    .detach();
 1965                                });
 1966                            }
 1967                        }
 1968                    }
 1969
 1970                    _ => {}
 1971                },
 1972            ));
 1973            if let Some(task_inventory) = project
 1974                .read(cx)
 1975                .task_store()
 1976                .read(cx)
 1977                .task_inventory()
 1978                .cloned()
 1979            {
 1980                project_subscriptions.push(cx.observe_in(
 1981                    &task_inventory,
 1982                    window,
 1983                    |editor, _, window, cx| {
 1984                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1985                    },
 1986                ));
 1987            };
 1988
 1989            project_subscriptions.push(cx.subscribe_in(
 1990                &project.read(cx).breakpoint_store(),
 1991                window,
 1992                |editor, _, event, window, cx| match event {
 1993                    BreakpointStoreEvent::ClearDebugLines => {
 1994                        editor.clear_row_highlights::<ActiveDebugLine>();
 1995                        editor.refresh_inline_values(cx);
 1996                    }
 1997                    BreakpointStoreEvent::SetDebugLine => {
 1998                        if editor.go_to_active_debug_line(window, cx) {
 1999                            cx.stop_propagation();
 2000                        }
 2001
 2002                        editor.refresh_inline_values(cx);
 2003                    }
 2004                    _ => {}
 2005                },
 2006            ));
 2007            let git_store = project.read(cx).git_store().clone();
 2008            let project = project.clone();
 2009            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2010                if let GitStoreEvent::RepositoryUpdated(
 2011                    _,
 2012                    RepositoryEvent::Updated {
 2013                        new_instance: true, ..
 2014                    },
 2015                    _,
 2016                ) = event
 2017                {
 2018                    this.load_diff_task = Some(
 2019                        update_uncommitted_diff_for_buffer(
 2020                            cx.entity(),
 2021                            &project,
 2022                            this.buffer.read(cx).all_buffers(),
 2023                            this.buffer.clone(),
 2024                            cx,
 2025                        )
 2026                        .shared(),
 2027                    );
 2028                }
 2029            }));
 2030        }
 2031
 2032        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2033
 2034        let inlay_hint_settings =
 2035            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2036        let focus_handle = cx.focus_handle();
 2037        if !is_minimap {
 2038            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2039                .detach();
 2040            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2041                .detach();
 2042            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2043                .detach();
 2044            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2045                .detach();
 2046            cx.observe_pending_input(window, Self::observe_pending_input)
 2047                .detach();
 2048        }
 2049
 2050        let show_indent_guides =
 2051            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2052                Some(false)
 2053            } else {
 2054                None
 2055            };
 2056
 2057        let breakpoint_store = match (&mode, project.as_ref()) {
 2058            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2059            _ => None,
 2060        };
 2061
 2062        let mut code_action_providers = Vec::new();
 2063        let mut load_uncommitted_diff = None;
 2064        if let Some(project) = project.clone() {
 2065            load_uncommitted_diff = Some(
 2066                update_uncommitted_diff_for_buffer(
 2067                    cx.entity(),
 2068                    &project,
 2069                    buffer.read(cx).all_buffers(),
 2070                    buffer.clone(),
 2071                    cx,
 2072                )
 2073                .shared(),
 2074            );
 2075            code_action_providers.push(Rc::new(project) as Rc<_>);
 2076        }
 2077
 2078        let mut editor = Self {
 2079            focus_handle,
 2080            show_cursor_when_unfocused: false,
 2081            last_focused_descendant: None,
 2082            buffer: buffer.clone(),
 2083            display_map: display_map.clone(),
 2084            placeholder_display_map: None,
 2085            selections,
 2086            scroll_manager: ScrollManager::new(cx),
 2087            columnar_selection_state: None,
 2088            add_selections_state: None,
 2089            select_next_state: None,
 2090            select_prev_state: None,
 2091            selection_history: SelectionHistory::default(),
 2092            defer_selection_effects: false,
 2093            deferred_selection_effects_state: None,
 2094            autoclose_regions: Vec::new(),
 2095            snippet_stack: InvalidationStack::default(),
 2096            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2097            ime_transaction: None,
 2098            active_diagnostics: ActiveDiagnostic::None,
 2099            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2100            inline_diagnostics_update: Task::ready(()),
 2101            inline_diagnostics: Vec::new(),
 2102            soft_wrap_mode_override,
 2103            diagnostics_max_severity,
 2104            hard_wrap: None,
 2105            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2106            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2107            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2108            project,
 2109            blink_manager: blink_manager.clone(),
 2110            show_local_selections: true,
 2111            show_scrollbars: ScrollbarAxes {
 2112                horizontal: full_mode,
 2113                vertical: full_mode,
 2114            },
 2115            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2116            offset_content: !matches!(mode, EditorMode::SingleLine),
 2117            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2118            show_gutter: full_mode,
 2119            show_line_numbers: (!full_mode).then_some(false),
 2120            use_relative_line_numbers: None,
 2121            disable_expand_excerpt_buttons: !full_mode,
 2122            show_git_diff_gutter: None,
 2123            show_code_actions: None,
 2124            show_runnables: None,
 2125            show_breakpoints: None,
 2126            show_wrap_guides: None,
 2127            show_indent_guides,
 2128            highlight_order: 0,
 2129            highlighted_rows: HashMap::default(),
 2130            background_highlights: HashMap::default(),
 2131            gutter_highlights: HashMap::default(),
 2132            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2133            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2134            nav_history: None,
 2135            context_menu: RefCell::new(None),
 2136            context_menu_options: None,
 2137            mouse_context_menu: None,
 2138            completion_tasks: Vec::new(),
 2139            inline_blame_popover: None,
 2140            inline_blame_popover_show_task: None,
 2141            signature_help_state: SignatureHelpState::default(),
 2142            auto_signature_help: None,
 2143            find_all_references_task_sources: Vec::new(),
 2144            next_completion_id: 0,
 2145            next_inlay_id: 0,
 2146            code_action_providers,
 2147            available_code_actions: None,
 2148            code_actions_task: None,
 2149            quick_selection_highlight_task: None,
 2150            debounced_selection_highlight_task: None,
 2151            document_highlights_task: None,
 2152            linked_editing_range_task: None,
 2153            pending_rename: None,
 2154            searchable: !is_minimap,
 2155            cursor_shape: EditorSettings::get_global(cx)
 2156                .cursor_shape
 2157                .unwrap_or_default(),
 2158            current_line_highlight: None,
 2159            autoindent_mode: Some(AutoindentMode::EachLine),
 2160            collapse_matches: false,
 2161            workspace: None,
 2162            input_enabled: !is_minimap,
 2163            use_modal_editing: full_mode,
 2164            read_only: is_minimap,
 2165            use_autoclose: true,
 2166            use_auto_surround: true,
 2167            auto_replace_emoji_shortcode: false,
 2168            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2169            leader_id: None,
 2170            remote_id: None,
 2171            hover_state: HoverState::default(),
 2172            pending_mouse_down: None,
 2173            hovered_link_state: None,
 2174            edit_prediction_provider: None,
 2175            active_edit_prediction: None,
 2176            stale_edit_prediction_in_menu: None,
 2177            edit_prediction_preview: EditPredictionPreview::Inactive {
 2178                released_too_fast: false,
 2179            },
 2180            inline_diagnostics_enabled: full_mode,
 2181            diagnostics_enabled: full_mode,
 2182            word_completions_enabled: full_mode,
 2183            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2184            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2185            gutter_hovered: false,
 2186            pixel_position_of_newest_cursor: None,
 2187            last_bounds: None,
 2188            last_position_map: None,
 2189            expect_bounds_change: None,
 2190            gutter_dimensions: GutterDimensions::default(),
 2191            style: None,
 2192            show_cursor_names: false,
 2193            hovered_cursors: HashMap::default(),
 2194            next_editor_action_id: EditorActionId::default(),
 2195            editor_actions: Rc::default(),
 2196            edit_predictions_hidden_for_vim_mode: false,
 2197            show_edit_predictions_override: None,
 2198            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2199            edit_prediction_settings: EditPredictionSettings::Disabled,
 2200            edit_prediction_indent_conflict: false,
 2201            edit_prediction_requires_modifier_in_indent_conflict: true,
 2202            custom_context_menu: None,
 2203            show_git_blame_gutter: false,
 2204            show_git_blame_inline: false,
 2205            show_selection_menu: None,
 2206            show_git_blame_inline_delay_task: None,
 2207            git_blame_inline_enabled: full_mode
 2208                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2209            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2210            serialize_dirty_buffers: !is_minimap
 2211                && ProjectSettings::get_global(cx)
 2212                    .session
 2213                    .restore_unsaved_buffers,
 2214            blame: None,
 2215            blame_subscription: None,
 2216            tasks: BTreeMap::default(),
 2217
 2218            breakpoint_store,
 2219            gutter_breakpoint_indicator: (None, None),
 2220            hovered_diff_hunk_row: None,
 2221            _subscriptions: (!is_minimap)
 2222                .then(|| {
 2223                    vec![
 2224                        cx.observe(&buffer, Self::on_buffer_changed),
 2225                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2226                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2227                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2228                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2229                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2230                        cx.observe_window_activation(window, |editor, window, cx| {
 2231                            let active = window.is_window_active();
 2232                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2233                                if active {
 2234                                    blink_manager.enable(cx);
 2235                                } else {
 2236                                    blink_manager.disable(cx);
 2237                                }
 2238                            });
 2239                            if active {
 2240                                editor.show_mouse_cursor(cx);
 2241                            }
 2242                        }),
 2243                    ]
 2244                })
 2245                .unwrap_or_default(),
 2246            tasks_update_task: None,
 2247            pull_diagnostics_task: Task::ready(()),
 2248            colors: None,
 2249            next_color_inlay_id: 0,
 2250            linked_edit_ranges: Default::default(),
 2251            in_project_search: false,
 2252            previous_search_ranges: None,
 2253            breadcrumb_header: None,
 2254            focused_block: None,
 2255            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2256            addons: HashMap::default(),
 2257            registered_buffers: HashMap::default(),
 2258            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2259            selection_mark_mode: false,
 2260            toggle_fold_multiple_buffers: Task::ready(()),
 2261            serialize_selections: Task::ready(()),
 2262            serialize_folds: Task::ready(()),
 2263            text_style_refinement: None,
 2264            load_diff_task: load_uncommitted_diff,
 2265            temporary_diff_override: false,
 2266            mouse_cursor_hidden: false,
 2267            minimap: None,
 2268            hide_mouse_mode: EditorSettings::get_global(cx)
 2269                .hide_mouse
 2270                .unwrap_or_default(),
 2271            change_list: ChangeList::new(),
 2272            mode,
 2273            selection_drag_state: SelectionDragState::None,
 2274            folding_newlines: Task::ready(()),
 2275            lookup_key: None,
 2276        };
 2277
 2278        if is_minimap {
 2279            return editor;
 2280        }
 2281
 2282        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2283            editor
 2284                ._subscriptions
 2285                .push(cx.observe(breakpoints, |_, _, cx| {
 2286                    cx.notify();
 2287                }));
 2288        }
 2289        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2290        editor._subscriptions.extend(project_subscriptions);
 2291
 2292        editor._subscriptions.push(cx.subscribe_in(
 2293            &cx.entity(),
 2294            window,
 2295            |editor, _, e: &EditorEvent, window, cx| match e {
 2296                EditorEvent::ScrollPositionChanged { local, .. } => {
 2297                    if *local {
 2298                        let new_anchor = editor.scroll_manager.anchor();
 2299                        let snapshot = editor.snapshot(window, cx);
 2300                        editor.update_restoration_data(cx, move |data| {
 2301                            data.scroll_position = (
 2302                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2303                                new_anchor.offset,
 2304                            );
 2305                        });
 2306                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2307                        editor.inline_blame_popover.take();
 2308                    }
 2309                }
 2310                EditorEvent::Edited { .. } => {
 2311                    if !vim_enabled(cx) {
 2312                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2313                        let pop_state = editor
 2314                            .change_list
 2315                            .last()
 2316                            .map(|previous| {
 2317                                previous.len() == selections.len()
 2318                                    && previous.iter().enumerate().all(|(ix, p)| {
 2319                                        p.to_display_point(&map).row()
 2320                                            == selections[ix].head().row()
 2321                                    })
 2322                            })
 2323                            .unwrap_or(false);
 2324                        let new_positions = selections
 2325                            .into_iter()
 2326                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2327                            .collect();
 2328                        editor
 2329                            .change_list
 2330                            .push_to_change_list(pop_state, new_positions);
 2331                    }
 2332                }
 2333                _ => (),
 2334            },
 2335        ));
 2336
 2337        if let Some(dap_store) = editor
 2338            .project
 2339            .as_ref()
 2340            .map(|project| project.read(cx).dap_store())
 2341        {
 2342            let weak_editor = cx.weak_entity();
 2343
 2344            editor
 2345                ._subscriptions
 2346                .push(
 2347                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2348                        let session_entity = cx.entity();
 2349                        weak_editor
 2350                            .update(cx, |editor, cx| {
 2351                                editor._subscriptions.push(
 2352                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2353                                );
 2354                            })
 2355                            .ok();
 2356                    }),
 2357                );
 2358
 2359            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2360                editor
 2361                    ._subscriptions
 2362                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2363            }
 2364        }
 2365
 2366        // skip adding the initial selection to selection history
 2367        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2368        editor.end_selection(window, cx);
 2369        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2370
 2371        editor.scroll_manager.show_scrollbars(window, cx);
 2372        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2373
 2374        if full_mode {
 2375            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2376            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2377
 2378            if editor.git_blame_inline_enabled {
 2379                editor.start_git_blame_inline(false, window, cx);
 2380            }
 2381
 2382            editor.go_to_active_debug_line(window, cx);
 2383
 2384            if let Some(buffer) = buffer.read(cx).as_singleton()
 2385                && let Some(project) = editor.project()
 2386            {
 2387                let handle = project.update(cx, |project, cx| {
 2388                    project.register_buffer_with_language_servers(&buffer, cx)
 2389                });
 2390                editor
 2391                    .registered_buffers
 2392                    .insert(buffer.read(cx).remote_id(), handle);
 2393            }
 2394
 2395            editor.minimap =
 2396                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2397            editor.colors = Some(LspColorData::new(cx));
 2398            editor.update_lsp_data(false, None, window, cx);
 2399        }
 2400
 2401        if editor.mode.is_full() {
 2402            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2403        }
 2404
 2405        editor
 2406    }
 2407
 2408    pub fn deploy_mouse_context_menu(
 2409        &mut self,
 2410        position: gpui::Point<Pixels>,
 2411        context_menu: Entity<ContextMenu>,
 2412        window: &mut Window,
 2413        cx: &mut Context<Self>,
 2414    ) {
 2415        self.mouse_context_menu = Some(MouseContextMenu::new(
 2416            self,
 2417            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2418            context_menu,
 2419            window,
 2420            cx,
 2421        ));
 2422    }
 2423
 2424    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2425        self.mouse_context_menu
 2426            .as_ref()
 2427            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2428    }
 2429
 2430    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2431        if self
 2432            .selections
 2433            .pending_anchor()
 2434            .is_some_and(|pending_selection| {
 2435                let snapshot = self.buffer().read(cx).snapshot(cx);
 2436                pending_selection.range().includes(range, &snapshot)
 2437            })
 2438        {
 2439            return true;
 2440        }
 2441
 2442        self.selections
 2443            .disjoint_in_range::<usize>(range.clone(), cx)
 2444            .into_iter()
 2445            .any(|selection| {
 2446                // This is needed to cover a corner case, if we just check for an existing
 2447                // selection in the fold range, having a cursor at the start of the fold
 2448                // marks it as selected. Non-empty selections don't cause this.
 2449                let length = selection.end - selection.start;
 2450                length > 0
 2451            })
 2452    }
 2453
 2454    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2455        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2456    }
 2457
 2458    fn key_context_internal(
 2459        &self,
 2460        has_active_edit_prediction: bool,
 2461        window: &Window,
 2462        cx: &App,
 2463    ) -> KeyContext {
 2464        let mut key_context = KeyContext::new_with_defaults();
 2465        key_context.add("Editor");
 2466        let mode = match self.mode {
 2467            EditorMode::SingleLine => "single_line",
 2468            EditorMode::AutoHeight { .. } => "auto_height",
 2469            EditorMode::Minimap { .. } => "minimap",
 2470            EditorMode::Full { .. } => "full",
 2471        };
 2472
 2473        if EditorSettings::jupyter_enabled(cx) {
 2474            key_context.add("jupyter");
 2475        }
 2476
 2477        key_context.set("mode", mode);
 2478        if self.pending_rename.is_some() {
 2479            key_context.add("renaming");
 2480        }
 2481
 2482        match self.context_menu.borrow().as_ref() {
 2483            Some(CodeContextMenu::Completions(menu)) => {
 2484                if menu.visible() {
 2485                    key_context.add("menu");
 2486                    key_context.add("showing_completions");
 2487                }
 2488            }
 2489            Some(CodeContextMenu::CodeActions(menu)) => {
 2490                if menu.visible() {
 2491                    key_context.add("menu");
 2492                    key_context.add("showing_code_actions")
 2493                }
 2494            }
 2495            None => {}
 2496        }
 2497
 2498        if self.signature_help_state.has_multiple_signatures() {
 2499            key_context.add("showing_signature_help");
 2500        }
 2501
 2502        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2503        if !self.focus_handle(cx).contains_focused(window, cx)
 2504            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2505        {
 2506            for addon in self.addons.values() {
 2507                addon.extend_key_context(&mut key_context, cx)
 2508            }
 2509        }
 2510
 2511        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2512            if let Some(extension) = singleton_buffer
 2513                .read(cx)
 2514                .file()
 2515                .and_then(|file| file.path().extension())
 2516            {
 2517                key_context.set("extension", extension.to_string());
 2518            }
 2519        } else {
 2520            key_context.add("multibuffer");
 2521        }
 2522
 2523        if has_active_edit_prediction {
 2524            if self.edit_prediction_in_conflict() {
 2525                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2526            } else {
 2527                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2528                key_context.add("copilot_suggestion");
 2529            }
 2530        }
 2531
 2532        if self.selection_mark_mode {
 2533            key_context.add("selection_mode");
 2534        }
 2535
 2536        key_context
 2537    }
 2538
 2539    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2540        self.last_bounds.as_ref()
 2541    }
 2542
 2543    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2544        if self.mouse_cursor_hidden {
 2545            self.mouse_cursor_hidden = false;
 2546            cx.notify();
 2547        }
 2548    }
 2549
 2550    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2551        let hide_mouse_cursor = match origin {
 2552            HideMouseCursorOrigin::TypingAction => {
 2553                matches!(
 2554                    self.hide_mouse_mode,
 2555                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2556                )
 2557            }
 2558            HideMouseCursorOrigin::MovementAction => {
 2559                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2560            }
 2561        };
 2562        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2563            self.mouse_cursor_hidden = hide_mouse_cursor;
 2564            cx.notify();
 2565        }
 2566    }
 2567
 2568    pub fn edit_prediction_in_conflict(&self) -> bool {
 2569        if !self.show_edit_predictions_in_menu() {
 2570            return false;
 2571        }
 2572
 2573        let showing_completions = self
 2574            .context_menu
 2575            .borrow()
 2576            .as_ref()
 2577            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2578
 2579        showing_completions
 2580            || self.edit_prediction_requires_modifier()
 2581            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2582            // bindings to insert tab characters.
 2583            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2584    }
 2585
 2586    pub fn accept_edit_prediction_keybind(
 2587        &self,
 2588        accept_partial: bool,
 2589        window: &Window,
 2590        cx: &App,
 2591    ) -> AcceptEditPredictionBinding {
 2592        let key_context = self.key_context_internal(true, window, cx);
 2593        let in_conflict = self.edit_prediction_in_conflict();
 2594
 2595        let bindings = if accept_partial {
 2596            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2597        } else {
 2598            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2599        };
 2600
 2601        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2602        // just the first one.
 2603        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2604            !in_conflict
 2605                || binding
 2606                    .keystrokes()
 2607                    .first()
 2608                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2609        }))
 2610    }
 2611
 2612    pub fn new_file(
 2613        workspace: &mut Workspace,
 2614        _: &workspace::NewFile,
 2615        window: &mut Window,
 2616        cx: &mut Context<Workspace>,
 2617    ) {
 2618        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2619            "Failed to create buffer",
 2620            window,
 2621            cx,
 2622            |e, _, _| match e.error_code() {
 2623                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2624                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2625                e.error_tag("required").unwrap_or("the latest version")
 2626            )),
 2627                _ => None,
 2628            },
 2629        );
 2630    }
 2631
 2632    pub fn new_in_workspace(
 2633        workspace: &mut Workspace,
 2634        window: &mut Window,
 2635        cx: &mut Context<Workspace>,
 2636    ) -> Task<Result<Entity<Editor>>> {
 2637        let project = workspace.project().clone();
 2638        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2639
 2640        cx.spawn_in(window, async move |workspace, cx| {
 2641            let buffer = create.await?;
 2642            workspace.update_in(cx, |workspace, window, cx| {
 2643                let editor =
 2644                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2645                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2646                editor
 2647            })
 2648        })
 2649    }
 2650
 2651    fn new_file_vertical(
 2652        workspace: &mut Workspace,
 2653        _: &workspace::NewFileSplitVertical,
 2654        window: &mut Window,
 2655        cx: &mut Context<Workspace>,
 2656    ) {
 2657        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2658    }
 2659
 2660    fn new_file_horizontal(
 2661        workspace: &mut Workspace,
 2662        _: &workspace::NewFileSplitHorizontal,
 2663        window: &mut Window,
 2664        cx: &mut Context<Workspace>,
 2665    ) {
 2666        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2667    }
 2668
 2669    fn new_file_in_direction(
 2670        workspace: &mut Workspace,
 2671        direction: SplitDirection,
 2672        window: &mut Window,
 2673        cx: &mut Context<Workspace>,
 2674    ) {
 2675        let project = workspace.project().clone();
 2676        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2677
 2678        cx.spawn_in(window, async move |workspace, cx| {
 2679            let buffer = create.await?;
 2680            workspace.update_in(cx, move |workspace, window, cx| {
 2681                workspace.split_item(
 2682                    direction,
 2683                    Box::new(
 2684                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2685                    ),
 2686                    window,
 2687                    cx,
 2688                )
 2689            })?;
 2690            anyhow::Ok(())
 2691        })
 2692        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2693            match e.error_code() {
 2694                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2695                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2696                e.error_tag("required").unwrap_or("the latest version")
 2697            )),
 2698                _ => None,
 2699            }
 2700        });
 2701    }
 2702
 2703    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2704        self.leader_id
 2705    }
 2706
 2707    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2708        &self.buffer
 2709    }
 2710
 2711    pub fn project(&self) -> Option<&Entity<Project>> {
 2712        self.project.as_ref()
 2713    }
 2714
 2715    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2716        self.workspace.as_ref()?.0.upgrade()
 2717    }
 2718
 2719    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2720        self.buffer().read(cx).title(cx)
 2721    }
 2722
 2723    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2724        let git_blame_gutter_max_author_length = self
 2725            .render_git_blame_gutter(cx)
 2726            .then(|| {
 2727                if let Some(blame) = self.blame.as_ref() {
 2728                    let max_author_length =
 2729                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2730                    Some(max_author_length)
 2731                } else {
 2732                    None
 2733                }
 2734            })
 2735            .flatten();
 2736
 2737        EditorSnapshot {
 2738            mode: self.mode.clone(),
 2739            show_gutter: self.show_gutter,
 2740            show_line_numbers: self.show_line_numbers,
 2741            show_git_diff_gutter: self.show_git_diff_gutter,
 2742            show_code_actions: self.show_code_actions,
 2743            show_runnables: self.show_runnables,
 2744            show_breakpoints: self.show_breakpoints,
 2745            git_blame_gutter_max_author_length,
 2746            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2747            placeholder_display_snapshot: self
 2748                .placeholder_display_map
 2749                .as_ref()
 2750                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2751            scroll_anchor: self.scroll_manager.anchor(),
 2752            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2753            is_focused: self.focus_handle.is_focused(window),
 2754            current_line_highlight: self
 2755                .current_line_highlight
 2756                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2757            gutter_hovered: self.gutter_hovered,
 2758        }
 2759    }
 2760
 2761    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2762        self.buffer.read(cx).language_at(point, cx)
 2763    }
 2764
 2765    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2766        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2767    }
 2768
 2769    pub fn active_excerpt(
 2770        &self,
 2771        cx: &App,
 2772    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2773        self.buffer
 2774            .read(cx)
 2775            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2776    }
 2777
 2778    pub fn mode(&self) -> &EditorMode {
 2779        &self.mode
 2780    }
 2781
 2782    pub fn set_mode(&mut self, mode: EditorMode) {
 2783        self.mode = mode;
 2784    }
 2785
 2786    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2787        self.collaboration_hub.as_deref()
 2788    }
 2789
 2790    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2791        self.collaboration_hub = Some(hub);
 2792    }
 2793
 2794    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2795        self.in_project_search = in_project_search;
 2796    }
 2797
 2798    pub fn set_custom_context_menu(
 2799        &mut self,
 2800        f: impl 'static
 2801        + Fn(
 2802            &mut Self,
 2803            DisplayPoint,
 2804            &mut Window,
 2805            &mut Context<Self>,
 2806        ) -> Option<Entity<ui::ContextMenu>>,
 2807    ) {
 2808        self.custom_context_menu = Some(Box::new(f))
 2809    }
 2810
 2811    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2812        self.completion_provider = provider;
 2813    }
 2814
 2815    #[cfg(any(test, feature = "test-support"))]
 2816    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2817        self.completion_provider.clone()
 2818    }
 2819
 2820    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2821        self.semantics_provider.clone()
 2822    }
 2823
 2824    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2825        self.semantics_provider = provider;
 2826    }
 2827
 2828    pub fn set_edit_prediction_provider<T>(
 2829        &mut self,
 2830        provider: Option<Entity<T>>,
 2831        window: &mut Window,
 2832        cx: &mut Context<Self>,
 2833    ) where
 2834        T: EditPredictionProvider,
 2835    {
 2836        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2837            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2838                if this.focus_handle.is_focused(window) {
 2839                    this.update_visible_edit_prediction(window, cx);
 2840                }
 2841            }),
 2842            provider: Arc::new(provider),
 2843        });
 2844        self.update_edit_prediction_settings(cx);
 2845        self.refresh_edit_prediction(false, false, window, cx);
 2846    }
 2847
 2848    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2849        self.placeholder_display_map
 2850            .as_ref()
 2851            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2852    }
 2853
 2854    pub fn set_placeholder_text(
 2855        &mut self,
 2856        placeholder_text: &str,
 2857        window: &mut Window,
 2858        cx: &mut Context<Self>,
 2859    ) {
 2860        let multibuffer = cx
 2861            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2862
 2863        let style = window.text_style();
 2864
 2865        self.placeholder_display_map = Some(cx.new(|cx| {
 2866            DisplayMap::new(
 2867                multibuffer,
 2868                style.font(),
 2869                style.font_size.to_pixels(window.rem_size()),
 2870                None,
 2871                FILE_HEADER_HEIGHT,
 2872                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2873                Default::default(),
 2874                DiagnosticSeverity::Off,
 2875                cx,
 2876            )
 2877        }));
 2878        cx.notify();
 2879    }
 2880
 2881    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2882        self.cursor_shape = cursor_shape;
 2883
 2884        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2885        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2886
 2887        cx.notify();
 2888    }
 2889
 2890    pub fn set_current_line_highlight(
 2891        &mut self,
 2892        current_line_highlight: Option<CurrentLineHighlight>,
 2893    ) {
 2894        self.current_line_highlight = current_line_highlight;
 2895    }
 2896
 2897    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2898        self.collapse_matches = collapse_matches;
 2899    }
 2900
 2901    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2902        let buffers = self.buffer.read(cx).all_buffers();
 2903        let Some(project) = self.project.as_ref() else {
 2904            return;
 2905        };
 2906        project.update(cx, |project, cx| {
 2907            for buffer in buffers {
 2908                self.registered_buffers
 2909                    .entry(buffer.read(cx).remote_id())
 2910                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2911            }
 2912        })
 2913    }
 2914
 2915    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2916        if self.collapse_matches {
 2917            return range.start..range.start;
 2918        }
 2919        range.clone()
 2920    }
 2921
 2922    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2923        if self.display_map.read(cx).clip_at_line_ends != clip {
 2924            self.display_map
 2925                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2926        }
 2927    }
 2928
 2929    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2930        self.input_enabled = input_enabled;
 2931    }
 2932
 2933    pub fn set_edit_predictions_hidden_for_vim_mode(
 2934        &mut self,
 2935        hidden: bool,
 2936        window: &mut Window,
 2937        cx: &mut Context<Self>,
 2938    ) {
 2939        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2940            self.edit_predictions_hidden_for_vim_mode = hidden;
 2941            if hidden {
 2942                self.update_visible_edit_prediction(window, cx);
 2943            } else {
 2944                self.refresh_edit_prediction(true, false, window, cx);
 2945            }
 2946        }
 2947    }
 2948
 2949    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2950        self.menu_edit_predictions_policy = value;
 2951    }
 2952
 2953    pub fn set_autoindent(&mut self, autoindent: bool) {
 2954        if autoindent {
 2955            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2956        } else {
 2957            self.autoindent_mode = None;
 2958        }
 2959    }
 2960
 2961    pub fn read_only(&self, cx: &App) -> bool {
 2962        self.read_only || self.buffer.read(cx).read_only()
 2963    }
 2964
 2965    pub fn set_read_only(&mut self, read_only: bool) {
 2966        self.read_only = read_only;
 2967    }
 2968
 2969    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2970        self.use_autoclose = autoclose;
 2971    }
 2972
 2973    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2974        self.use_auto_surround = auto_surround;
 2975    }
 2976
 2977    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2978        self.auto_replace_emoji_shortcode = auto_replace;
 2979    }
 2980
 2981    pub fn toggle_edit_predictions(
 2982        &mut self,
 2983        _: &ToggleEditPrediction,
 2984        window: &mut Window,
 2985        cx: &mut Context<Self>,
 2986    ) {
 2987        if self.show_edit_predictions_override.is_some() {
 2988            self.set_show_edit_predictions(None, window, cx);
 2989        } else {
 2990            let show_edit_predictions = !self.edit_predictions_enabled();
 2991            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2992        }
 2993    }
 2994
 2995    pub fn set_show_edit_predictions(
 2996        &mut self,
 2997        show_edit_predictions: Option<bool>,
 2998        window: &mut Window,
 2999        cx: &mut Context<Self>,
 3000    ) {
 3001        self.show_edit_predictions_override = show_edit_predictions;
 3002        self.update_edit_prediction_settings(cx);
 3003
 3004        if let Some(false) = show_edit_predictions {
 3005            self.discard_edit_prediction(false, cx);
 3006        } else {
 3007            self.refresh_edit_prediction(false, true, window, cx);
 3008        }
 3009    }
 3010
 3011    fn edit_predictions_disabled_in_scope(
 3012        &self,
 3013        buffer: &Entity<Buffer>,
 3014        buffer_position: language::Anchor,
 3015        cx: &App,
 3016    ) -> bool {
 3017        let snapshot = buffer.read(cx).snapshot();
 3018        let settings = snapshot.settings_at(buffer_position, cx);
 3019
 3020        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3021            return false;
 3022        };
 3023
 3024        scope.override_name().is_some_and(|scope_name| {
 3025            settings
 3026                .edit_predictions_disabled_in
 3027                .iter()
 3028                .any(|s| s == scope_name)
 3029        })
 3030    }
 3031
 3032    pub fn set_use_modal_editing(&mut self, to: bool) {
 3033        self.use_modal_editing = to;
 3034    }
 3035
 3036    pub fn use_modal_editing(&self) -> bool {
 3037        self.use_modal_editing
 3038    }
 3039
 3040    fn selections_did_change(
 3041        &mut self,
 3042        local: bool,
 3043        old_cursor_position: &Anchor,
 3044        effects: SelectionEffects,
 3045        window: &mut Window,
 3046        cx: &mut Context<Self>,
 3047    ) {
 3048        window.invalidate_character_coordinates();
 3049
 3050        // Copy selections to primary selection buffer
 3051        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3052        if local {
 3053            let selections = self.selections.all::<usize>(cx);
 3054            let buffer_handle = self.buffer.read(cx).read(cx);
 3055
 3056            let mut text = String::new();
 3057            for (index, selection) in selections.iter().enumerate() {
 3058                let text_for_selection = buffer_handle
 3059                    .text_for_range(selection.start..selection.end)
 3060                    .collect::<String>();
 3061
 3062                text.push_str(&text_for_selection);
 3063                if index != selections.len() - 1 {
 3064                    text.push('\n');
 3065                }
 3066            }
 3067
 3068            if !text.is_empty() {
 3069                cx.write_to_primary(ClipboardItem::new_string(text));
 3070            }
 3071        }
 3072
 3073        let selection_anchors = self.selections.disjoint_anchors_arc();
 3074
 3075        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3076            self.buffer.update(cx, |buffer, cx| {
 3077                buffer.set_active_selections(
 3078                    &selection_anchors,
 3079                    self.selections.line_mode(),
 3080                    self.cursor_shape,
 3081                    cx,
 3082                )
 3083            });
 3084        }
 3085        let display_map = self
 3086            .display_map
 3087            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3088        let buffer = &display_map.buffer_snapshot;
 3089        if self.selections.count() == 1 {
 3090            self.add_selections_state = None;
 3091        }
 3092        self.select_next_state = None;
 3093        self.select_prev_state = None;
 3094        self.select_syntax_node_history.try_clear();
 3095        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3096        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3097        self.take_rename(false, window, cx);
 3098
 3099        let newest_selection = self.selections.newest_anchor();
 3100        let new_cursor_position = newest_selection.head();
 3101        let selection_start = newest_selection.start;
 3102
 3103        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3104            self.push_to_nav_history(
 3105                *old_cursor_position,
 3106                Some(new_cursor_position.to_point(buffer)),
 3107                false,
 3108                effects.nav_history == Some(true),
 3109                cx,
 3110            );
 3111        }
 3112
 3113        if local {
 3114            if let Some(buffer_id) = new_cursor_position.buffer_id
 3115                && !self.registered_buffers.contains_key(&buffer_id)
 3116                && let Some(project) = self.project.as_ref()
 3117            {
 3118                project.update(cx, |project, cx| {
 3119                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3120                        return;
 3121                    };
 3122                    self.registered_buffers.insert(
 3123                        buffer_id,
 3124                        project.register_buffer_with_language_servers(&buffer, cx),
 3125                    );
 3126                })
 3127            }
 3128
 3129            let mut context_menu = self.context_menu.borrow_mut();
 3130            let completion_menu = match context_menu.as_ref() {
 3131                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3132                Some(CodeContextMenu::CodeActions(_)) => {
 3133                    *context_menu = None;
 3134                    None
 3135                }
 3136                None => None,
 3137            };
 3138            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3139            drop(context_menu);
 3140
 3141            if effects.completions
 3142                && let Some(completion_position) = completion_position
 3143            {
 3144                let start_offset = selection_start.to_offset(buffer);
 3145                let position_matches = start_offset == completion_position.to_offset(buffer);
 3146                let continue_showing = if position_matches {
 3147                    if self.snippet_stack.is_empty() {
 3148                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3149                            == Some(CharKind::Word)
 3150                    } else {
 3151                        // Snippet choices can be shown even when the cursor is in whitespace.
 3152                        // Dismissing the menu with actions like backspace is handled by
 3153                        // invalidation regions.
 3154                        true
 3155                    }
 3156                } else {
 3157                    false
 3158                };
 3159
 3160                if continue_showing {
 3161                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3162                } else {
 3163                    self.hide_context_menu(window, cx);
 3164                }
 3165            }
 3166
 3167            hide_hover(self, cx);
 3168
 3169            if old_cursor_position.to_display_point(&display_map).row()
 3170                != new_cursor_position.to_display_point(&display_map).row()
 3171            {
 3172                self.available_code_actions.take();
 3173            }
 3174            self.refresh_code_actions(window, cx);
 3175            self.refresh_document_highlights(cx);
 3176            self.refresh_selected_text_highlights(false, window, cx);
 3177            refresh_matching_bracket_highlights(self, window, cx);
 3178            self.update_visible_edit_prediction(window, cx);
 3179            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3180            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3181            self.inline_blame_popover.take();
 3182            if self.git_blame_inline_enabled {
 3183                self.start_inline_blame_timer(window, cx);
 3184            }
 3185        }
 3186
 3187        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3188        cx.emit(EditorEvent::SelectionsChanged { local });
 3189
 3190        let selections = &self.selections.disjoint_anchors_arc();
 3191        if selections.len() == 1 {
 3192            cx.emit(SearchEvent::ActiveMatchChanged)
 3193        }
 3194        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3195            let inmemory_selections = selections
 3196                .iter()
 3197                .map(|s| {
 3198                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3199                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3200                })
 3201                .collect();
 3202            self.update_restoration_data(cx, |data| {
 3203                data.selections = inmemory_selections;
 3204            });
 3205
 3206            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3207                && let Some(workspace_id) =
 3208                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3209            {
 3210                let snapshot = self.buffer().read(cx).snapshot(cx);
 3211                let selections = selections.clone();
 3212                let background_executor = cx.background_executor().clone();
 3213                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3214                self.serialize_selections = cx.background_spawn(async move {
 3215                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3216                    let db_selections = selections
 3217                        .iter()
 3218                        .map(|selection| {
 3219                            (
 3220                                selection.start.to_offset(&snapshot),
 3221                                selection.end.to_offset(&snapshot),
 3222                            )
 3223                        })
 3224                        .collect();
 3225
 3226                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3227                        .await
 3228                        .with_context(|| {
 3229                            format!(
 3230                                "persisting editor selections for editor {editor_id}, \
 3231                                workspace {workspace_id:?}"
 3232                            )
 3233                        })
 3234                        .log_err();
 3235                });
 3236            }
 3237        }
 3238
 3239        cx.notify();
 3240    }
 3241
 3242    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3243        use text::ToOffset as _;
 3244        use text::ToPoint as _;
 3245
 3246        if self.mode.is_minimap()
 3247            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3248        {
 3249            return;
 3250        }
 3251
 3252        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3253            return;
 3254        };
 3255
 3256        let snapshot = singleton.read(cx).snapshot();
 3257        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3258            let display_snapshot = display_map.snapshot(cx);
 3259
 3260            display_snapshot
 3261                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3262                .map(|fold| {
 3263                    fold.range.start.text_anchor.to_point(&snapshot)
 3264                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3265                })
 3266                .collect()
 3267        });
 3268        self.update_restoration_data(cx, |data| {
 3269            data.folds = inmemory_folds;
 3270        });
 3271
 3272        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3273            return;
 3274        };
 3275        let background_executor = cx.background_executor().clone();
 3276        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3277        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3278            display_map
 3279                .snapshot(cx)
 3280                .folds_in_range(0..snapshot.len())
 3281                .map(|fold| {
 3282                    (
 3283                        fold.range.start.text_anchor.to_offset(&snapshot),
 3284                        fold.range.end.text_anchor.to_offset(&snapshot),
 3285                    )
 3286                })
 3287                .collect()
 3288        });
 3289        self.serialize_folds = cx.background_spawn(async move {
 3290            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3291            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3292                .await
 3293                .with_context(|| {
 3294                    format!(
 3295                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3296                    )
 3297                })
 3298                .log_err();
 3299        });
 3300    }
 3301
 3302    pub fn sync_selections(
 3303        &mut self,
 3304        other: Entity<Editor>,
 3305        cx: &mut Context<Self>,
 3306    ) -> gpui::Subscription {
 3307        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3308        if !other_selections.is_empty() {
 3309            self.selections.change_with(cx, |selections| {
 3310                selections.select_anchors(other_selections);
 3311            });
 3312        }
 3313
 3314        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3315            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3316                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3317                if other_selections.is_empty() {
 3318                    return;
 3319                }
 3320                this.selections.change_with(cx, |selections| {
 3321                    selections.select_anchors(other_selections);
 3322                });
 3323            }
 3324        });
 3325
 3326        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3327            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3328                let these_selections = this.selections.disjoint_anchors().to_vec();
 3329                if these_selections.is_empty() {
 3330                    return;
 3331                }
 3332                other.update(cx, |other_editor, cx| {
 3333                    other_editor.selections.change_with(cx, |selections| {
 3334                        selections.select_anchors(these_selections);
 3335                    })
 3336                });
 3337            }
 3338        });
 3339
 3340        Subscription::join(other_subscription, this_subscription)
 3341    }
 3342
 3343    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3344    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3345    /// effects of selection change occur at the end of the transaction.
 3346    pub fn change_selections<R>(
 3347        &mut self,
 3348        effects: SelectionEffects,
 3349        window: &mut Window,
 3350        cx: &mut Context<Self>,
 3351        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3352    ) -> R {
 3353        if let Some(state) = &mut self.deferred_selection_effects_state {
 3354            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3355            state.effects.completions = effects.completions;
 3356            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3357            let (changed, result) = self.selections.change_with(cx, change);
 3358            state.changed |= changed;
 3359            return result;
 3360        }
 3361        let mut state = DeferredSelectionEffectsState {
 3362            changed: false,
 3363            effects,
 3364            old_cursor_position: self.selections.newest_anchor().head(),
 3365            history_entry: SelectionHistoryEntry {
 3366                selections: self.selections.disjoint_anchors_arc(),
 3367                select_next_state: self.select_next_state.clone(),
 3368                select_prev_state: self.select_prev_state.clone(),
 3369                add_selections_state: self.add_selections_state.clone(),
 3370            },
 3371        };
 3372        let (changed, result) = self.selections.change_with(cx, change);
 3373        state.changed = state.changed || changed;
 3374        if self.defer_selection_effects {
 3375            self.deferred_selection_effects_state = Some(state);
 3376        } else {
 3377            self.apply_selection_effects(state, window, cx);
 3378        }
 3379        result
 3380    }
 3381
 3382    /// Defers the effects of selection change, so that the effects of multiple calls to
 3383    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3384    /// to selection history and the state of popovers based on selection position aren't
 3385    /// erroneously updated.
 3386    pub fn with_selection_effects_deferred<R>(
 3387        &mut self,
 3388        window: &mut Window,
 3389        cx: &mut Context<Self>,
 3390        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3391    ) -> R {
 3392        let already_deferred = self.defer_selection_effects;
 3393        self.defer_selection_effects = true;
 3394        let result = update(self, window, cx);
 3395        if !already_deferred {
 3396            self.defer_selection_effects = false;
 3397            if let Some(state) = self.deferred_selection_effects_state.take() {
 3398                self.apply_selection_effects(state, window, cx);
 3399            }
 3400        }
 3401        result
 3402    }
 3403
 3404    fn apply_selection_effects(
 3405        &mut self,
 3406        state: DeferredSelectionEffectsState,
 3407        window: &mut Window,
 3408        cx: &mut Context<Self>,
 3409    ) {
 3410        if state.changed {
 3411            self.selection_history.push(state.history_entry);
 3412
 3413            if let Some(autoscroll) = state.effects.scroll {
 3414                self.request_autoscroll(autoscroll, cx);
 3415            }
 3416
 3417            let old_cursor_position = &state.old_cursor_position;
 3418
 3419            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3420
 3421            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3422                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3423            }
 3424        }
 3425    }
 3426
 3427    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3428    where
 3429        I: IntoIterator<Item = (Range<S>, T)>,
 3430        S: ToOffset,
 3431        T: Into<Arc<str>>,
 3432    {
 3433        if self.read_only(cx) {
 3434            return;
 3435        }
 3436
 3437        self.buffer
 3438            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3439    }
 3440
 3441    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3442    where
 3443        I: IntoIterator<Item = (Range<S>, T)>,
 3444        S: ToOffset,
 3445        T: Into<Arc<str>>,
 3446    {
 3447        if self.read_only(cx) {
 3448            return;
 3449        }
 3450
 3451        self.buffer.update(cx, |buffer, cx| {
 3452            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3453        });
 3454    }
 3455
 3456    pub fn edit_with_block_indent<I, S, T>(
 3457        &mut self,
 3458        edits: I,
 3459        original_indent_columns: Vec<Option<u32>>,
 3460        cx: &mut Context<Self>,
 3461    ) where
 3462        I: IntoIterator<Item = (Range<S>, T)>,
 3463        S: ToOffset,
 3464        T: Into<Arc<str>>,
 3465    {
 3466        if self.read_only(cx) {
 3467            return;
 3468        }
 3469
 3470        self.buffer.update(cx, |buffer, cx| {
 3471            buffer.edit(
 3472                edits,
 3473                Some(AutoindentMode::Block {
 3474                    original_indent_columns,
 3475                }),
 3476                cx,
 3477            )
 3478        });
 3479    }
 3480
 3481    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3482        self.hide_context_menu(window, cx);
 3483
 3484        match phase {
 3485            SelectPhase::Begin {
 3486                position,
 3487                add,
 3488                click_count,
 3489            } => self.begin_selection(position, add, click_count, window, cx),
 3490            SelectPhase::BeginColumnar {
 3491                position,
 3492                goal_column,
 3493                reset,
 3494                mode,
 3495            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3496            SelectPhase::Extend {
 3497                position,
 3498                click_count,
 3499            } => self.extend_selection(position, click_count, window, cx),
 3500            SelectPhase::Update {
 3501                position,
 3502                goal_column,
 3503                scroll_delta,
 3504            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3505            SelectPhase::End => self.end_selection(window, cx),
 3506        }
 3507    }
 3508
 3509    fn extend_selection(
 3510        &mut self,
 3511        position: DisplayPoint,
 3512        click_count: usize,
 3513        window: &mut Window,
 3514        cx: &mut Context<Self>,
 3515    ) {
 3516        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3517        let tail = self.selections.newest::<usize>(cx).tail();
 3518        self.begin_selection(position, false, click_count, window, cx);
 3519
 3520        let position = position.to_offset(&display_map, Bias::Left);
 3521        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3522
 3523        let mut pending_selection = self
 3524            .selections
 3525            .pending_anchor()
 3526            .cloned()
 3527            .expect("extend_selection not called with pending selection");
 3528        if position >= tail {
 3529            pending_selection.start = tail_anchor;
 3530        } else {
 3531            pending_selection.end = tail_anchor;
 3532            pending_selection.reversed = true;
 3533        }
 3534
 3535        let mut pending_mode = self.selections.pending_mode().unwrap();
 3536        match &mut pending_mode {
 3537            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3538            _ => {}
 3539        }
 3540
 3541        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3542            SelectionEffects::scroll(Autoscroll::fit())
 3543        } else {
 3544            SelectionEffects::no_scroll()
 3545        };
 3546
 3547        self.change_selections(effects, window, cx, |s| {
 3548            s.set_pending(pending_selection.clone(), pending_mode)
 3549        });
 3550    }
 3551
 3552    fn begin_selection(
 3553        &mut self,
 3554        position: DisplayPoint,
 3555        add: bool,
 3556        click_count: usize,
 3557        window: &mut Window,
 3558        cx: &mut Context<Self>,
 3559    ) {
 3560        if !self.focus_handle.is_focused(window) {
 3561            self.last_focused_descendant = None;
 3562            window.focus(&self.focus_handle);
 3563        }
 3564
 3565        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3566        let buffer = &display_map.buffer_snapshot;
 3567        let position = display_map.clip_point(position, Bias::Left);
 3568
 3569        let start;
 3570        let end;
 3571        let mode;
 3572        let mut auto_scroll;
 3573        match click_count {
 3574            1 => {
 3575                start = buffer.anchor_before(position.to_point(&display_map));
 3576                end = start;
 3577                mode = SelectMode::Character;
 3578                auto_scroll = true;
 3579            }
 3580            2 => {
 3581                let position = display_map
 3582                    .clip_point(position, Bias::Left)
 3583                    .to_offset(&display_map, Bias::Left);
 3584                let (range, _) = buffer.surrounding_word(position, None);
 3585                start = buffer.anchor_before(range.start);
 3586                end = buffer.anchor_before(range.end);
 3587                mode = SelectMode::Word(start..end);
 3588                auto_scroll = true;
 3589            }
 3590            3 => {
 3591                let position = display_map
 3592                    .clip_point(position, Bias::Left)
 3593                    .to_point(&display_map);
 3594                let line_start = display_map.prev_line_boundary(position).0;
 3595                let next_line_start = buffer.clip_point(
 3596                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3597                    Bias::Left,
 3598                );
 3599                start = buffer.anchor_before(line_start);
 3600                end = buffer.anchor_before(next_line_start);
 3601                mode = SelectMode::Line(start..end);
 3602                auto_scroll = true;
 3603            }
 3604            _ => {
 3605                start = buffer.anchor_before(0);
 3606                end = buffer.anchor_before(buffer.len());
 3607                mode = SelectMode::All;
 3608                auto_scroll = false;
 3609            }
 3610        }
 3611        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3612
 3613        let point_to_delete: Option<usize> = {
 3614            let selected_points: Vec<Selection<Point>> =
 3615                self.selections.disjoint_in_range(start..end, cx);
 3616
 3617            if !add || click_count > 1 {
 3618                None
 3619            } else if !selected_points.is_empty() {
 3620                Some(selected_points[0].id)
 3621            } else {
 3622                let clicked_point_already_selected =
 3623                    self.selections.disjoint_anchors().iter().find(|selection| {
 3624                        selection.start.to_point(buffer) == start.to_point(buffer)
 3625                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3626                    });
 3627
 3628                clicked_point_already_selected.map(|selection| selection.id)
 3629            }
 3630        };
 3631
 3632        let selections_count = self.selections.count();
 3633        let effects = if auto_scroll {
 3634            SelectionEffects::default()
 3635        } else {
 3636            SelectionEffects::no_scroll()
 3637        };
 3638
 3639        self.change_selections(effects, window, cx, |s| {
 3640            if let Some(point_to_delete) = point_to_delete {
 3641                s.delete(point_to_delete);
 3642
 3643                if selections_count == 1 {
 3644                    s.set_pending_anchor_range(start..end, mode);
 3645                }
 3646            } else {
 3647                if !add {
 3648                    s.clear_disjoint();
 3649                }
 3650
 3651                s.set_pending_anchor_range(start..end, mode);
 3652            }
 3653        });
 3654    }
 3655
 3656    fn begin_columnar_selection(
 3657        &mut self,
 3658        position: DisplayPoint,
 3659        goal_column: u32,
 3660        reset: bool,
 3661        mode: ColumnarMode,
 3662        window: &mut Window,
 3663        cx: &mut Context<Self>,
 3664    ) {
 3665        if !self.focus_handle.is_focused(window) {
 3666            self.last_focused_descendant = None;
 3667            window.focus(&self.focus_handle);
 3668        }
 3669
 3670        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3671
 3672        if reset {
 3673            let pointer_position = display_map
 3674                .buffer_snapshot
 3675                .anchor_before(position.to_point(&display_map));
 3676
 3677            self.change_selections(
 3678                SelectionEffects::scroll(Autoscroll::newest()),
 3679                window,
 3680                cx,
 3681                |s| {
 3682                    s.clear_disjoint();
 3683                    s.set_pending_anchor_range(
 3684                        pointer_position..pointer_position,
 3685                        SelectMode::Character,
 3686                    );
 3687                },
 3688            );
 3689        };
 3690
 3691        let tail = self.selections.newest::<Point>(cx).tail();
 3692        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3693        self.columnar_selection_state = match mode {
 3694            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3695                selection_tail: selection_anchor,
 3696                display_point: if reset {
 3697                    if position.column() != goal_column {
 3698                        Some(DisplayPoint::new(position.row(), goal_column))
 3699                    } else {
 3700                        None
 3701                    }
 3702                } else {
 3703                    None
 3704                },
 3705            }),
 3706            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3707                selection_tail: selection_anchor,
 3708            }),
 3709        };
 3710
 3711        if !reset {
 3712            self.select_columns(position, goal_column, &display_map, window, cx);
 3713        }
 3714    }
 3715
 3716    fn update_selection(
 3717        &mut self,
 3718        position: DisplayPoint,
 3719        goal_column: u32,
 3720        scroll_delta: gpui::Point<f32>,
 3721        window: &mut Window,
 3722        cx: &mut Context<Self>,
 3723    ) {
 3724        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3725
 3726        if self.columnar_selection_state.is_some() {
 3727            self.select_columns(position, goal_column, &display_map, window, cx);
 3728        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3729            let buffer = &display_map.buffer_snapshot;
 3730            let head;
 3731            let tail;
 3732            let mode = self.selections.pending_mode().unwrap();
 3733            match &mode {
 3734                SelectMode::Character => {
 3735                    head = position.to_point(&display_map);
 3736                    tail = pending.tail().to_point(buffer);
 3737                }
 3738                SelectMode::Word(original_range) => {
 3739                    let offset = display_map
 3740                        .clip_point(position, Bias::Left)
 3741                        .to_offset(&display_map, Bias::Left);
 3742                    let original_range = original_range.to_offset(buffer);
 3743
 3744                    let head_offset = if buffer.is_inside_word(offset, None)
 3745                        || original_range.contains(&offset)
 3746                    {
 3747                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3748                        if word_range.start < original_range.start {
 3749                            word_range.start
 3750                        } else {
 3751                            word_range.end
 3752                        }
 3753                    } else {
 3754                        offset
 3755                    };
 3756
 3757                    head = head_offset.to_point(buffer);
 3758                    if head_offset <= original_range.start {
 3759                        tail = original_range.end.to_point(buffer);
 3760                    } else {
 3761                        tail = original_range.start.to_point(buffer);
 3762                    }
 3763                }
 3764                SelectMode::Line(original_range) => {
 3765                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3766
 3767                    let position = display_map
 3768                        .clip_point(position, Bias::Left)
 3769                        .to_point(&display_map);
 3770                    let line_start = display_map.prev_line_boundary(position).0;
 3771                    let next_line_start = buffer.clip_point(
 3772                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3773                        Bias::Left,
 3774                    );
 3775
 3776                    if line_start < original_range.start {
 3777                        head = line_start
 3778                    } else {
 3779                        head = next_line_start
 3780                    }
 3781
 3782                    if head <= original_range.start {
 3783                        tail = original_range.end;
 3784                    } else {
 3785                        tail = original_range.start;
 3786                    }
 3787                }
 3788                SelectMode::All => {
 3789                    return;
 3790                }
 3791            };
 3792
 3793            if head < tail {
 3794                pending.start = buffer.anchor_before(head);
 3795                pending.end = buffer.anchor_before(tail);
 3796                pending.reversed = true;
 3797            } else {
 3798                pending.start = buffer.anchor_before(tail);
 3799                pending.end = buffer.anchor_before(head);
 3800                pending.reversed = false;
 3801            }
 3802
 3803            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3804                s.set_pending(pending.clone(), mode);
 3805            });
 3806        } else {
 3807            log::error!("update_selection dispatched with no pending selection");
 3808            return;
 3809        }
 3810
 3811        self.apply_scroll_delta(scroll_delta, window, cx);
 3812        cx.notify();
 3813    }
 3814
 3815    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3816        self.columnar_selection_state.take();
 3817        if self.selections.pending_anchor().is_some() {
 3818            let selections = self.selections.all::<usize>(cx);
 3819            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3820                s.select(selections);
 3821                s.clear_pending();
 3822            });
 3823        }
 3824    }
 3825
 3826    fn select_columns(
 3827        &mut self,
 3828        head: DisplayPoint,
 3829        goal_column: u32,
 3830        display_map: &DisplaySnapshot,
 3831        window: &mut Window,
 3832        cx: &mut Context<Self>,
 3833    ) {
 3834        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3835            return;
 3836        };
 3837
 3838        let tail = match columnar_state {
 3839            ColumnarSelectionState::FromMouse {
 3840                selection_tail,
 3841                display_point,
 3842            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3843            ColumnarSelectionState::FromSelection { selection_tail } => {
 3844                selection_tail.to_display_point(display_map)
 3845            }
 3846        };
 3847
 3848        let start_row = cmp::min(tail.row(), head.row());
 3849        let end_row = cmp::max(tail.row(), head.row());
 3850        let start_column = cmp::min(tail.column(), goal_column);
 3851        let end_column = cmp::max(tail.column(), goal_column);
 3852        let reversed = start_column < tail.column();
 3853
 3854        let selection_ranges = (start_row.0..=end_row.0)
 3855            .map(DisplayRow)
 3856            .filter_map(|row| {
 3857                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3858                    || start_column <= display_map.line_len(row))
 3859                    && !display_map.is_block_line(row)
 3860                {
 3861                    let start = display_map
 3862                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3863                        .to_point(display_map);
 3864                    let end = display_map
 3865                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3866                        .to_point(display_map);
 3867                    if reversed {
 3868                        Some(end..start)
 3869                    } else {
 3870                        Some(start..end)
 3871                    }
 3872                } else {
 3873                    None
 3874                }
 3875            })
 3876            .collect::<Vec<_>>();
 3877
 3878        let ranges = match columnar_state {
 3879            ColumnarSelectionState::FromMouse { .. } => {
 3880                let mut non_empty_ranges = selection_ranges
 3881                    .iter()
 3882                    .filter(|selection_range| selection_range.start != selection_range.end)
 3883                    .peekable();
 3884                if non_empty_ranges.peek().is_some() {
 3885                    non_empty_ranges.cloned().collect()
 3886                } else {
 3887                    selection_ranges
 3888                }
 3889            }
 3890            _ => selection_ranges,
 3891        };
 3892
 3893        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3894            s.select_ranges(ranges);
 3895        });
 3896        cx.notify();
 3897    }
 3898
 3899    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3900        self.selections
 3901            .all_adjusted(cx)
 3902            .iter()
 3903            .any(|selection| !selection.is_empty())
 3904    }
 3905
 3906    pub fn has_pending_nonempty_selection(&self) -> bool {
 3907        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3908            Some(Selection { start, end, .. }) => start != end,
 3909            None => false,
 3910        };
 3911
 3912        pending_nonempty_selection
 3913            || (self.columnar_selection_state.is_some()
 3914                && self.selections.disjoint_anchors().len() > 1)
 3915    }
 3916
 3917    pub fn has_pending_selection(&self) -> bool {
 3918        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3919    }
 3920
 3921    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3922        self.selection_mark_mode = false;
 3923        self.selection_drag_state = SelectionDragState::None;
 3924
 3925        if self.clear_expanded_diff_hunks(cx) {
 3926            cx.notify();
 3927            return;
 3928        }
 3929        if self.dismiss_menus_and_popups(true, window, cx) {
 3930            return;
 3931        }
 3932
 3933        if self.mode.is_full()
 3934            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3935        {
 3936            return;
 3937        }
 3938
 3939        cx.propagate();
 3940    }
 3941
 3942    pub fn dismiss_menus_and_popups(
 3943        &mut self,
 3944        is_user_requested: bool,
 3945        window: &mut Window,
 3946        cx: &mut Context<Self>,
 3947    ) -> bool {
 3948        if self.take_rename(false, window, cx).is_some() {
 3949            return true;
 3950        }
 3951
 3952        if hide_hover(self, cx) {
 3953            return true;
 3954        }
 3955
 3956        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3957            return true;
 3958        }
 3959
 3960        if self.hide_context_menu(window, cx).is_some() {
 3961            return true;
 3962        }
 3963
 3964        if self.mouse_context_menu.take().is_some() {
 3965            return true;
 3966        }
 3967
 3968        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3969            return true;
 3970        }
 3971
 3972        if self.snippet_stack.pop().is_some() {
 3973            return true;
 3974        }
 3975
 3976        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3977            self.dismiss_diagnostics(cx);
 3978            return true;
 3979        }
 3980
 3981        false
 3982    }
 3983
 3984    fn linked_editing_ranges_for(
 3985        &self,
 3986        selection: Range<text::Anchor>,
 3987        cx: &App,
 3988    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3989        if self.linked_edit_ranges.is_empty() {
 3990            return None;
 3991        }
 3992        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3993            selection.end.buffer_id.and_then(|end_buffer_id| {
 3994                if selection.start.buffer_id != Some(end_buffer_id) {
 3995                    return None;
 3996                }
 3997                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3998                let snapshot = buffer.read(cx).snapshot();
 3999                self.linked_edit_ranges
 4000                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4001                    .map(|ranges| (ranges, snapshot, buffer))
 4002            })?;
 4003        use text::ToOffset as TO;
 4004        // find offset from the start of current range to current cursor position
 4005        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4006
 4007        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4008        let start_difference = start_offset - start_byte_offset;
 4009        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4010        let end_difference = end_offset - start_byte_offset;
 4011        // Current range has associated linked ranges.
 4012        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4013        for range in linked_ranges.iter() {
 4014            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4015            let end_offset = start_offset + end_difference;
 4016            let start_offset = start_offset + start_difference;
 4017            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4018                continue;
 4019            }
 4020            if self.selections.disjoint_anchor_ranges().any(|s| {
 4021                if s.start.buffer_id != selection.start.buffer_id
 4022                    || s.end.buffer_id != selection.end.buffer_id
 4023                {
 4024                    return false;
 4025                }
 4026                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4027                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4028            }) {
 4029                continue;
 4030            }
 4031            let start = buffer_snapshot.anchor_after(start_offset);
 4032            let end = buffer_snapshot.anchor_after(end_offset);
 4033            linked_edits
 4034                .entry(buffer.clone())
 4035                .or_default()
 4036                .push(start..end);
 4037        }
 4038        Some(linked_edits)
 4039    }
 4040
 4041    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4042        let text: Arc<str> = text.into();
 4043
 4044        if self.read_only(cx) {
 4045            return;
 4046        }
 4047
 4048        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4049
 4050        let selections = self.selections.all_adjusted(cx);
 4051        let mut bracket_inserted = false;
 4052        let mut edits = Vec::new();
 4053        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4054        let mut new_selections = Vec::with_capacity(selections.len());
 4055        let mut new_autoclose_regions = Vec::new();
 4056        let snapshot = self.buffer.read(cx).read(cx);
 4057        let mut clear_linked_edit_ranges = false;
 4058
 4059        for (selection, autoclose_region) in
 4060            self.selections_with_autoclose_regions(selections, &snapshot)
 4061        {
 4062            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4063                // Determine if the inserted text matches the opening or closing
 4064                // bracket of any of this language's bracket pairs.
 4065                let mut bracket_pair = None;
 4066                let mut is_bracket_pair_start = false;
 4067                let mut is_bracket_pair_end = false;
 4068                if !text.is_empty() {
 4069                    let mut bracket_pair_matching_end = None;
 4070                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4071                    //  and they are removing the character that triggered IME popup.
 4072                    for (pair, enabled) in scope.brackets() {
 4073                        if !pair.close && !pair.surround {
 4074                            continue;
 4075                        }
 4076
 4077                        if enabled && pair.start.ends_with(text.as_ref()) {
 4078                            let prefix_len = pair.start.len() - text.len();
 4079                            let preceding_text_matches_prefix = prefix_len == 0
 4080                                || (selection.start.column >= (prefix_len as u32)
 4081                                    && snapshot.contains_str_at(
 4082                                        Point::new(
 4083                                            selection.start.row,
 4084                                            selection.start.column - (prefix_len as u32),
 4085                                        ),
 4086                                        &pair.start[..prefix_len],
 4087                                    ));
 4088                            if preceding_text_matches_prefix {
 4089                                bracket_pair = Some(pair.clone());
 4090                                is_bracket_pair_start = true;
 4091                                break;
 4092                            }
 4093                        }
 4094                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4095                        {
 4096                            // take first bracket pair matching end, but don't break in case a later bracket
 4097                            // pair matches start
 4098                            bracket_pair_matching_end = Some(pair.clone());
 4099                        }
 4100                    }
 4101                    if let Some(end) = bracket_pair_matching_end
 4102                        && bracket_pair.is_none()
 4103                    {
 4104                        bracket_pair = Some(end);
 4105                        is_bracket_pair_end = true;
 4106                    }
 4107                }
 4108
 4109                if let Some(bracket_pair) = bracket_pair {
 4110                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4111                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4112                    let auto_surround =
 4113                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4114                    if selection.is_empty() {
 4115                        if is_bracket_pair_start {
 4116                            // If the inserted text is a suffix of an opening bracket and the
 4117                            // selection is preceded by the rest of the opening bracket, then
 4118                            // insert the closing bracket.
 4119                            let following_text_allows_autoclose = snapshot
 4120                                .chars_at(selection.start)
 4121                                .next()
 4122                                .is_none_or(|c| scope.should_autoclose_before(c));
 4123
 4124                            let preceding_text_allows_autoclose = selection.start.column == 0
 4125                                || snapshot
 4126                                    .reversed_chars_at(selection.start)
 4127                                    .next()
 4128                                    .is_none_or(|c| {
 4129                                        bracket_pair.start != bracket_pair.end
 4130                                            || !snapshot
 4131                                                .char_classifier_at(selection.start)
 4132                                                .is_word(c)
 4133                                    });
 4134
 4135                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4136                                && bracket_pair.start.len() == 1
 4137                            {
 4138                                let target = bracket_pair.start.chars().next().unwrap();
 4139                                let current_line_count = snapshot
 4140                                    .reversed_chars_at(selection.start)
 4141                                    .take_while(|&c| c != '\n')
 4142                                    .filter(|&c| c == target)
 4143                                    .count();
 4144                                current_line_count % 2 == 1
 4145                            } else {
 4146                                false
 4147                            };
 4148
 4149                            if autoclose
 4150                                && bracket_pair.close
 4151                                && following_text_allows_autoclose
 4152                                && preceding_text_allows_autoclose
 4153                                && !is_closing_quote
 4154                            {
 4155                                let anchor = snapshot.anchor_before(selection.end);
 4156                                new_selections.push((selection.map(|_| anchor), text.len()));
 4157                                new_autoclose_regions.push((
 4158                                    anchor,
 4159                                    text.len(),
 4160                                    selection.id,
 4161                                    bracket_pair.clone(),
 4162                                ));
 4163                                edits.push((
 4164                                    selection.range(),
 4165                                    format!("{}{}", text, bracket_pair.end).into(),
 4166                                ));
 4167                                bracket_inserted = true;
 4168                                continue;
 4169                            }
 4170                        }
 4171
 4172                        if let Some(region) = autoclose_region {
 4173                            // If the selection is followed by an auto-inserted closing bracket,
 4174                            // then don't insert that closing bracket again; just move the selection
 4175                            // past the closing bracket.
 4176                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4177                                && text.as_ref() == region.pair.end.as_str()
 4178                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4179                            if should_skip {
 4180                                let anchor = snapshot.anchor_after(selection.end);
 4181                                new_selections
 4182                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4183                                continue;
 4184                            }
 4185                        }
 4186
 4187                        let always_treat_brackets_as_autoclosed = snapshot
 4188                            .language_settings_at(selection.start, cx)
 4189                            .always_treat_brackets_as_autoclosed;
 4190                        if always_treat_brackets_as_autoclosed
 4191                            && is_bracket_pair_end
 4192                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4193                        {
 4194                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4195                            // and the inserted text is a closing bracket and the selection is followed
 4196                            // by the closing bracket then move the selection past the closing bracket.
 4197                            let anchor = snapshot.anchor_after(selection.end);
 4198                            new_selections.push((selection.map(|_| anchor), text.len()));
 4199                            continue;
 4200                        }
 4201                    }
 4202                    // If an opening bracket is 1 character long and is typed while
 4203                    // text is selected, then surround that text with the bracket pair.
 4204                    else if auto_surround
 4205                        && bracket_pair.surround
 4206                        && is_bracket_pair_start
 4207                        && bracket_pair.start.chars().count() == 1
 4208                    {
 4209                        edits.push((selection.start..selection.start, text.clone()));
 4210                        edits.push((
 4211                            selection.end..selection.end,
 4212                            bracket_pair.end.as_str().into(),
 4213                        ));
 4214                        bracket_inserted = true;
 4215                        new_selections.push((
 4216                            Selection {
 4217                                id: selection.id,
 4218                                start: snapshot.anchor_after(selection.start),
 4219                                end: snapshot.anchor_before(selection.end),
 4220                                reversed: selection.reversed,
 4221                                goal: selection.goal,
 4222                            },
 4223                            0,
 4224                        ));
 4225                        continue;
 4226                    }
 4227                }
 4228            }
 4229
 4230            if self.auto_replace_emoji_shortcode
 4231                && selection.is_empty()
 4232                && text.as_ref().ends_with(':')
 4233                && let Some(possible_emoji_short_code) =
 4234                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4235                && !possible_emoji_short_code.is_empty()
 4236                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4237            {
 4238                let emoji_shortcode_start = Point::new(
 4239                    selection.start.row,
 4240                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4241                );
 4242
 4243                // Remove shortcode from buffer
 4244                edits.push((
 4245                    emoji_shortcode_start..selection.start,
 4246                    "".to_string().into(),
 4247                ));
 4248                new_selections.push((
 4249                    Selection {
 4250                        id: selection.id,
 4251                        start: snapshot.anchor_after(emoji_shortcode_start),
 4252                        end: snapshot.anchor_before(selection.start),
 4253                        reversed: selection.reversed,
 4254                        goal: selection.goal,
 4255                    },
 4256                    0,
 4257                ));
 4258
 4259                // Insert emoji
 4260                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4261                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4262                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4263
 4264                continue;
 4265            }
 4266
 4267            // If not handling any auto-close operation, then just replace the selected
 4268            // text with the given input and move the selection to the end of the
 4269            // newly inserted text.
 4270            let anchor = snapshot.anchor_after(selection.end);
 4271            if !self.linked_edit_ranges.is_empty() {
 4272                let start_anchor = snapshot.anchor_before(selection.start);
 4273
 4274                let is_word_char = text.chars().next().is_none_or(|char| {
 4275                    let classifier = snapshot
 4276                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4277                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4278                    classifier.is_word(char)
 4279                });
 4280
 4281                if is_word_char {
 4282                    if let Some(ranges) = self
 4283                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4284                    {
 4285                        for (buffer, edits) in ranges {
 4286                            linked_edits
 4287                                .entry(buffer.clone())
 4288                                .or_default()
 4289                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4290                        }
 4291                    }
 4292                } else {
 4293                    clear_linked_edit_ranges = true;
 4294                }
 4295            }
 4296
 4297            new_selections.push((selection.map(|_| anchor), 0));
 4298            edits.push((selection.start..selection.end, text.clone()));
 4299        }
 4300
 4301        drop(snapshot);
 4302
 4303        self.transact(window, cx, |this, window, cx| {
 4304            if clear_linked_edit_ranges {
 4305                this.linked_edit_ranges.clear();
 4306            }
 4307            let initial_buffer_versions =
 4308                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4309
 4310            this.buffer.update(cx, |buffer, cx| {
 4311                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4312            });
 4313            for (buffer, edits) in linked_edits {
 4314                buffer.update(cx, |buffer, cx| {
 4315                    let snapshot = buffer.snapshot();
 4316                    let edits = edits
 4317                        .into_iter()
 4318                        .map(|(range, text)| {
 4319                            use text::ToPoint as TP;
 4320                            let end_point = TP::to_point(&range.end, &snapshot);
 4321                            let start_point = TP::to_point(&range.start, &snapshot);
 4322                            (start_point..end_point, text)
 4323                        })
 4324                        .sorted_by_key(|(range, _)| range.start);
 4325                    buffer.edit(edits, None, cx);
 4326                })
 4327            }
 4328            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4329            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4330            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4331            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4332                .zip(new_selection_deltas)
 4333                .map(|(selection, delta)| Selection {
 4334                    id: selection.id,
 4335                    start: selection.start + delta,
 4336                    end: selection.end + delta,
 4337                    reversed: selection.reversed,
 4338                    goal: SelectionGoal::None,
 4339                })
 4340                .collect::<Vec<_>>();
 4341
 4342            let mut i = 0;
 4343            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4344                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4345                let start = map.buffer_snapshot.anchor_before(position);
 4346                let end = map.buffer_snapshot.anchor_after(position);
 4347                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4348                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4349                        Ordering::Less => i += 1,
 4350                        Ordering::Greater => break,
 4351                        Ordering::Equal => {
 4352                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4353                                Ordering::Less => i += 1,
 4354                                Ordering::Equal => break,
 4355                                Ordering::Greater => break,
 4356                            }
 4357                        }
 4358                    }
 4359                }
 4360                this.autoclose_regions.insert(
 4361                    i,
 4362                    AutocloseRegion {
 4363                        selection_id,
 4364                        range: start..end,
 4365                        pair,
 4366                    },
 4367                );
 4368            }
 4369
 4370            let had_active_edit_prediction = this.has_active_edit_prediction();
 4371            this.change_selections(
 4372                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4373                window,
 4374                cx,
 4375                |s| s.select(new_selections),
 4376            );
 4377
 4378            if !bracket_inserted
 4379                && let Some(on_type_format_task) =
 4380                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4381            {
 4382                on_type_format_task.detach_and_log_err(cx);
 4383            }
 4384
 4385            let editor_settings = EditorSettings::get_global(cx);
 4386            if bracket_inserted
 4387                && (editor_settings.auto_signature_help
 4388                    || editor_settings.show_signature_help_after_edits)
 4389            {
 4390                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4391            }
 4392
 4393            let trigger_in_words =
 4394                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4395            if this.hard_wrap.is_some() {
 4396                let latest: Range<Point> = this.selections.newest(cx).range();
 4397                if latest.is_empty()
 4398                    && this
 4399                        .buffer()
 4400                        .read(cx)
 4401                        .snapshot(cx)
 4402                        .line_len(MultiBufferRow(latest.start.row))
 4403                        == latest.start.column
 4404                {
 4405                    this.rewrap_impl(
 4406                        RewrapOptions {
 4407                            override_language_settings: true,
 4408                            preserve_existing_whitespace: true,
 4409                        },
 4410                        cx,
 4411                    )
 4412                }
 4413            }
 4414            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4415            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4416            this.refresh_edit_prediction(true, false, window, cx);
 4417            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4418        });
 4419    }
 4420
 4421    fn find_possible_emoji_shortcode_at_position(
 4422        snapshot: &MultiBufferSnapshot,
 4423        position: Point,
 4424    ) -> Option<String> {
 4425        let mut chars = Vec::new();
 4426        let mut found_colon = false;
 4427        for char in snapshot.reversed_chars_at(position).take(100) {
 4428            // Found a possible emoji shortcode in the middle of the buffer
 4429            if found_colon {
 4430                if char.is_whitespace() {
 4431                    chars.reverse();
 4432                    return Some(chars.iter().collect());
 4433                }
 4434                // If the previous character is not a whitespace, we are in the middle of a word
 4435                // and we only want to complete the shortcode if the word is made up of other emojis
 4436                let mut containing_word = String::new();
 4437                for ch in snapshot
 4438                    .reversed_chars_at(position)
 4439                    .skip(chars.len() + 1)
 4440                    .take(100)
 4441                {
 4442                    if ch.is_whitespace() {
 4443                        break;
 4444                    }
 4445                    containing_word.push(ch);
 4446                }
 4447                let containing_word = containing_word.chars().rev().collect::<String>();
 4448                if util::word_consists_of_emojis(containing_word.as_str()) {
 4449                    chars.reverse();
 4450                    return Some(chars.iter().collect());
 4451                }
 4452            }
 4453
 4454            if char.is_whitespace() || !char.is_ascii() {
 4455                return None;
 4456            }
 4457            if char == ':' {
 4458                found_colon = true;
 4459            } else {
 4460                chars.push(char);
 4461            }
 4462        }
 4463        // Found a possible emoji shortcode at the beginning of the buffer
 4464        chars.reverse();
 4465        Some(chars.iter().collect())
 4466    }
 4467
 4468    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4470        self.transact(window, cx, |this, window, cx| {
 4471            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4472                let selections = this.selections.all::<usize>(cx);
 4473                let multi_buffer = this.buffer.read(cx);
 4474                let buffer = multi_buffer.snapshot(cx);
 4475                selections
 4476                    .iter()
 4477                    .map(|selection| {
 4478                        let start_point = selection.start.to_point(&buffer);
 4479                        let mut existing_indent =
 4480                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4481                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4482                        let start = selection.start;
 4483                        let end = selection.end;
 4484                        let selection_is_empty = start == end;
 4485                        let language_scope = buffer.language_scope_at(start);
 4486                        let (
 4487                            comment_delimiter,
 4488                            doc_delimiter,
 4489                            insert_extra_newline,
 4490                            indent_on_newline,
 4491                            indent_on_extra_newline,
 4492                        ) = if let Some(language) = &language_scope {
 4493                            let mut insert_extra_newline =
 4494                                insert_extra_newline_brackets(&buffer, start..end, language)
 4495                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4496
 4497                            // Comment extension on newline is allowed only for cursor selections
 4498                            let comment_delimiter = maybe!({
 4499                                if !selection_is_empty {
 4500                                    return None;
 4501                                }
 4502
 4503                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4504                                    return None;
 4505                                }
 4506
 4507                                let delimiters = language.line_comment_prefixes();
 4508                                let max_len_of_delimiter =
 4509                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4510                                let (snapshot, range) =
 4511                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4512
 4513                                let num_of_whitespaces = snapshot
 4514                                    .chars_for_range(range.clone())
 4515                                    .take_while(|c| c.is_whitespace())
 4516                                    .count();
 4517                                let comment_candidate = snapshot
 4518                                    .chars_for_range(range.clone())
 4519                                    .skip(num_of_whitespaces)
 4520                                    .take(max_len_of_delimiter)
 4521                                    .collect::<String>();
 4522                                let (delimiter, trimmed_len) = delimiters
 4523                                    .iter()
 4524                                    .filter_map(|delimiter| {
 4525                                        let prefix = delimiter.trim_end();
 4526                                        if comment_candidate.starts_with(prefix) {
 4527                                            Some((delimiter, prefix.len()))
 4528                                        } else {
 4529                                            None
 4530                                        }
 4531                                    })
 4532                                    .max_by_key(|(_, len)| *len)?;
 4533
 4534                                if let Some(BlockCommentConfig {
 4535                                    start: block_start, ..
 4536                                }) = language.block_comment()
 4537                                {
 4538                                    let block_start_trimmed = block_start.trim_end();
 4539                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4540                                        let line_content = snapshot
 4541                                            .chars_for_range(range)
 4542                                            .skip(num_of_whitespaces)
 4543                                            .take(block_start_trimmed.len())
 4544                                            .collect::<String>();
 4545
 4546                                        if line_content.starts_with(block_start_trimmed) {
 4547                                            return None;
 4548                                        }
 4549                                    }
 4550                                }
 4551
 4552                                let cursor_is_placed_after_comment_marker =
 4553                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4554                                if cursor_is_placed_after_comment_marker {
 4555                                    Some(delimiter.clone())
 4556                                } else {
 4557                                    None
 4558                                }
 4559                            });
 4560
 4561                            let mut indent_on_newline = IndentSize::spaces(0);
 4562                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4563
 4564                            let doc_delimiter = maybe!({
 4565                                if !selection_is_empty {
 4566                                    return None;
 4567                                }
 4568
 4569                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4570                                    return None;
 4571                                }
 4572
 4573                                let BlockCommentConfig {
 4574                                    start: start_tag,
 4575                                    end: end_tag,
 4576                                    prefix: delimiter,
 4577                                    tab_size: len,
 4578                                } = language.documentation_comment()?;
 4579                                let is_within_block_comment = buffer
 4580                                    .language_scope_at(start_point)
 4581                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4582                                if !is_within_block_comment {
 4583                                    return None;
 4584                                }
 4585
 4586                                let (snapshot, range) =
 4587                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4588
 4589                                let num_of_whitespaces = snapshot
 4590                                    .chars_for_range(range.clone())
 4591                                    .take_while(|c| c.is_whitespace())
 4592                                    .count();
 4593
 4594                                // 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.
 4595                                let column = start_point.column;
 4596                                let cursor_is_after_start_tag = {
 4597                                    let start_tag_len = start_tag.len();
 4598                                    let start_tag_line = snapshot
 4599                                        .chars_for_range(range.clone())
 4600                                        .skip(num_of_whitespaces)
 4601                                        .take(start_tag_len)
 4602                                        .collect::<String>();
 4603                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4604                                        num_of_whitespaces + start_tag_len <= column as usize
 4605                                    } else {
 4606                                        false
 4607                                    }
 4608                                };
 4609
 4610                                let cursor_is_after_delimiter = {
 4611                                    let delimiter_trim = delimiter.trim_end();
 4612                                    let delimiter_line = snapshot
 4613                                        .chars_for_range(range.clone())
 4614                                        .skip(num_of_whitespaces)
 4615                                        .take(delimiter_trim.len())
 4616                                        .collect::<String>();
 4617                                    if delimiter_line.starts_with(delimiter_trim) {
 4618                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4619                                    } else {
 4620                                        false
 4621                                    }
 4622                                };
 4623
 4624                                let cursor_is_before_end_tag_if_exists = {
 4625                                    let mut char_position = 0u32;
 4626                                    let mut end_tag_offset = None;
 4627
 4628                                    'outer: for chunk in snapshot.text_for_range(range) {
 4629                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4630                                            let chars_before_match =
 4631                                                chunk[..byte_pos].chars().count() as u32;
 4632                                            end_tag_offset =
 4633                                                Some(char_position + chars_before_match);
 4634                                            break 'outer;
 4635                                        }
 4636                                        char_position += chunk.chars().count() as u32;
 4637                                    }
 4638
 4639                                    if let Some(end_tag_offset) = end_tag_offset {
 4640                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4641                                        if cursor_is_after_start_tag {
 4642                                            if cursor_is_before_end_tag {
 4643                                                insert_extra_newline = true;
 4644                                            }
 4645                                            let cursor_is_at_start_of_end_tag =
 4646                                                column == end_tag_offset;
 4647                                            if cursor_is_at_start_of_end_tag {
 4648                                                indent_on_extra_newline.len = *len;
 4649                                            }
 4650                                        }
 4651                                        cursor_is_before_end_tag
 4652                                    } else {
 4653                                        true
 4654                                    }
 4655                                };
 4656
 4657                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4658                                    && cursor_is_before_end_tag_if_exists
 4659                                {
 4660                                    if cursor_is_after_start_tag {
 4661                                        indent_on_newline.len = *len;
 4662                                    }
 4663                                    Some(delimiter.clone())
 4664                                } else {
 4665                                    None
 4666                                }
 4667                            });
 4668
 4669                            (
 4670                                comment_delimiter,
 4671                                doc_delimiter,
 4672                                insert_extra_newline,
 4673                                indent_on_newline,
 4674                                indent_on_extra_newline,
 4675                            )
 4676                        } else {
 4677                            (
 4678                                None,
 4679                                None,
 4680                                false,
 4681                                IndentSize::default(),
 4682                                IndentSize::default(),
 4683                            )
 4684                        };
 4685
 4686                        let prevent_auto_indent = doc_delimiter.is_some();
 4687                        let delimiter = comment_delimiter.or(doc_delimiter);
 4688
 4689                        let capacity_for_delimiter =
 4690                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4691                        let mut new_text = String::with_capacity(
 4692                            1 + capacity_for_delimiter
 4693                                + existing_indent.len as usize
 4694                                + indent_on_newline.len as usize
 4695                                + indent_on_extra_newline.len as usize,
 4696                        );
 4697                        new_text.push('\n');
 4698                        new_text.extend(existing_indent.chars());
 4699                        new_text.extend(indent_on_newline.chars());
 4700
 4701                        if let Some(delimiter) = &delimiter {
 4702                            new_text.push_str(delimiter);
 4703                        }
 4704
 4705                        if insert_extra_newline {
 4706                            new_text.push('\n');
 4707                            new_text.extend(existing_indent.chars());
 4708                            new_text.extend(indent_on_extra_newline.chars());
 4709                        }
 4710
 4711                        let anchor = buffer.anchor_after(end);
 4712                        let new_selection = selection.map(|_| anchor);
 4713                        (
 4714                            ((start..end, new_text), prevent_auto_indent),
 4715                            (insert_extra_newline, new_selection),
 4716                        )
 4717                    })
 4718                    .unzip()
 4719            };
 4720
 4721            let mut auto_indent_edits = Vec::new();
 4722            let mut edits = Vec::new();
 4723            for (edit, prevent_auto_indent) in edits_with_flags {
 4724                if prevent_auto_indent {
 4725                    edits.push(edit);
 4726                } else {
 4727                    auto_indent_edits.push(edit);
 4728                }
 4729            }
 4730            if !edits.is_empty() {
 4731                this.edit(edits, cx);
 4732            }
 4733            if !auto_indent_edits.is_empty() {
 4734                this.edit_with_autoindent(auto_indent_edits, cx);
 4735            }
 4736
 4737            let buffer = this.buffer.read(cx).snapshot(cx);
 4738            let new_selections = selection_info
 4739                .into_iter()
 4740                .map(|(extra_newline_inserted, new_selection)| {
 4741                    let mut cursor = new_selection.end.to_point(&buffer);
 4742                    if extra_newline_inserted {
 4743                        cursor.row -= 1;
 4744                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4745                    }
 4746                    new_selection.map(|_| cursor)
 4747                })
 4748                .collect();
 4749
 4750            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4751            this.refresh_edit_prediction(true, false, window, cx);
 4752        });
 4753    }
 4754
 4755    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4756        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4757
 4758        let buffer = self.buffer.read(cx);
 4759        let snapshot = buffer.snapshot(cx);
 4760
 4761        let mut edits = Vec::new();
 4762        let mut rows = Vec::new();
 4763
 4764        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4765            let cursor = selection.head();
 4766            let row = cursor.row;
 4767
 4768            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4769
 4770            let newline = "\n".to_string();
 4771            edits.push((start_of_line..start_of_line, newline));
 4772
 4773            rows.push(row + rows_inserted as u32);
 4774        }
 4775
 4776        self.transact(window, cx, |editor, window, cx| {
 4777            editor.edit(edits, cx);
 4778
 4779            editor.change_selections(Default::default(), window, cx, |s| {
 4780                let mut index = 0;
 4781                s.move_cursors_with(|map, _, _| {
 4782                    let row = rows[index];
 4783                    index += 1;
 4784
 4785                    let point = Point::new(row, 0);
 4786                    let boundary = map.next_line_boundary(point).1;
 4787                    let clipped = map.clip_point(boundary, Bias::Left);
 4788
 4789                    (clipped, SelectionGoal::None)
 4790                });
 4791            });
 4792
 4793            let mut indent_edits = Vec::new();
 4794            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4795            for row in rows {
 4796                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4797                for (row, indent) in indents {
 4798                    if indent.len == 0 {
 4799                        continue;
 4800                    }
 4801
 4802                    let text = match indent.kind {
 4803                        IndentKind::Space => " ".repeat(indent.len as usize),
 4804                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4805                    };
 4806                    let point = Point::new(row.0, 0);
 4807                    indent_edits.push((point..point, text));
 4808                }
 4809            }
 4810            editor.edit(indent_edits, cx);
 4811        });
 4812    }
 4813
 4814    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4816
 4817        let buffer = self.buffer.read(cx);
 4818        let snapshot = buffer.snapshot(cx);
 4819
 4820        let mut edits = Vec::new();
 4821        let mut rows = Vec::new();
 4822        let mut rows_inserted = 0;
 4823
 4824        for selection in self.selections.all_adjusted(cx) {
 4825            let cursor = selection.head();
 4826            let row = cursor.row;
 4827
 4828            let point = Point::new(row + 1, 0);
 4829            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4830
 4831            let newline = "\n".to_string();
 4832            edits.push((start_of_line..start_of_line, newline));
 4833
 4834            rows_inserted += 1;
 4835            rows.push(row + rows_inserted);
 4836        }
 4837
 4838        self.transact(window, cx, |editor, window, cx| {
 4839            editor.edit(edits, cx);
 4840
 4841            editor.change_selections(Default::default(), window, cx, |s| {
 4842                let mut index = 0;
 4843                s.move_cursors_with(|map, _, _| {
 4844                    let row = rows[index];
 4845                    index += 1;
 4846
 4847                    let point = Point::new(row, 0);
 4848                    let boundary = map.next_line_boundary(point).1;
 4849                    let clipped = map.clip_point(boundary, Bias::Left);
 4850
 4851                    (clipped, SelectionGoal::None)
 4852                });
 4853            });
 4854
 4855            let mut indent_edits = Vec::new();
 4856            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4857            for row in rows {
 4858                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4859                for (row, indent) in indents {
 4860                    if indent.len == 0 {
 4861                        continue;
 4862                    }
 4863
 4864                    let text = match indent.kind {
 4865                        IndentKind::Space => " ".repeat(indent.len as usize),
 4866                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4867                    };
 4868                    let point = Point::new(row.0, 0);
 4869                    indent_edits.push((point..point, text));
 4870                }
 4871            }
 4872            editor.edit(indent_edits, cx);
 4873        });
 4874    }
 4875
 4876    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4877        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4878            original_indent_columns: Vec::new(),
 4879        });
 4880        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4881    }
 4882
 4883    fn insert_with_autoindent_mode(
 4884        &mut self,
 4885        text: &str,
 4886        autoindent_mode: Option<AutoindentMode>,
 4887        window: &mut Window,
 4888        cx: &mut Context<Self>,
 4889    ) {
 4890        if self.read_only(cx) {
 4891            return;
 4892        }
 4893
 4894        let text: Arc<str> = text.into();
 4895        self.transact(window, cx, |this, window, cx| {
 4896            let old_selections = this.selections.all_adjusted(cx);
 4897            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4898                let anchors = {
 4899                    let snapshot = buffer.read(cx);
 4900                    old_selections
 4901                        .iter()
 4902                        .map(|s| {
 4903                            let anchor = snapshot.anchor_after(s.head());
 4904                            s.map(|_| anchor)
 4905                        })
 4906                        .collect::<Vec<_>>()
 4907                };
 4908                buffer.edit(
 4909                    old_selections
 4910                        .iter()
 4911                        .map(|s| (s.start..s.end, text.clone())),
 4912                    autoindent_mode,
 4913                    cx,
 4914                );
 4915                anchors
 4916            });
 4917
 4918            this.change_selections(Default::default(), window, cx, |s| {
 4919                s.select_anchors(selection_anchors);
 4920            });
 4921
 4922            cx.notify();
 4923        });
 4924    }
 4925
 4926    fn trigger_completion_on_input(
 4927        &mut self,
 4928        text: &str,
 4929        trigger_in_words: bool,
 4930        window: &mut Window,
 4931        cx: &mut Context<Self>,
 4932    ) {
 4933        let completions_source = self
 4934            .context_menu
 4935            .borrow()
 4936            .as_ref()
 4937            .and_then(|menu| match menu {
 4938                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4939                CodeContextMenu::CodeActions(_) => None,
 4940            });
 4941
 4942        match completions_source {
 4943            Some(CompletionsMenuSource::Words { .. }) => {
 4944                self.open_or_update_completions_menu(
 4945                    Some(CompletionsMenuSource::Words {
 4946                        ignore_threshold: false,
 4947                    }),
 4948                    None,
 4949                    window,
 4950                    cx,
 4951                );
 4952            }
 4953            Some(CompletionsMenuSource::Normal)
 4954            | Some(CompletionsMenuSource::SnippetChoices)
 4955            | None
 4956                if self.is_completion_trigger(
 4957                    text,
 4958                    trigger_in_words,
 4959                    completions_source.is_some(),
 4960                    cx,
 4961                ) =>
 4962            {
 4963                self.show_completions(
 4964                    &ShowCompletions {
 4965                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4966                    },
 4967                    window,
 4968                    cx,
 4969                )
 4970            }
 4971            _ => {
 4972                self.hide_context_menu(window, cx);
 4973            }
 4974        }
 4975    }
 4976
 4977    fn is_completion_trigger(
 4978        &self,
 4979        text: &str,
 4980        trigger_in_words: bool,
 4981        menu_is_open: bool,
 4982        cx: &mut Context<Self>,
 4983    ) -> bool {
 4984        let position = self.selections.newest_anchor().head();
 4985        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4986            return false;
 4987        };
 4988
 4989        if let Some(completion_provider) = &self.completion_provider {
 4990            completion_provider.is_completion_trigger(
 4991                &buffer,
 4992                position.text_anchor,
 4993                text,
 4994                trigger_in_words,
 4995                menu_is_open,
 4996                cx,
 4997            )
 4998        } else {
 4999            false
 5000        }
 5001    }
 5002
 5003    /// If any empty selections is touching the start of its innermost containing autoclose
 5004    /// region, expand it to select the brackets.
 5005    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5006        let selections = self.selections.all::<usize>(cx);
 5007        let buffer = self.buffer.read(cx).read(cx);
 5008        let new_selections = self
 5009            .selections_with_autoclose_regions(selections, &buffer)
 5010            .map(|(mut selection, region)| {
 5011                if !selection.is_empty() {
 5012                    return selection;
 5013                }
 5014
 5015                if let Some(region) = region {
 5016                    let mut range = region.range.to_offset(&buffer);
 5017                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5018                        range.start -= region.pair.start.len();
 5019                        if buffer.contains_str_at(range.start, &region.pair.start)
 5020                            && buffer.contains_str_at(range.end, &region.pair.end)
 5021                        {
 5022                            range.end += region.pair.end.len();
 5023                            selection.start = range.start;
 5024                            selection.end = range.end;
 5025
 5026                            return selection;
 5027                        }
 5028                    }
 5029                }
 5030
 5031                let always_treat_brackets_as_autoclosed = buffer
 5032                    .language_settings_at(selection.start, cx)
 5033                    .always_treat_brackets_as_autoclosed;
 5034
 5035                if !always_treat_brackets_as_autoclosed {
 5036                    return selection;
 5037                }
 5038
 5039                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5040                    for (pair, enabled) in scope.brackets() {
 5041                        if !enabled || !pair.close {
 5042                            continue;
 5043                        }
 5044
 5045                        if buffer.contains_str_at(selection.start, &pair.end) {
 5046                            let pair_start_len = pair.start.len();
 5047                            if buffer.contains_str_at(
 5048                                selection.start.saturating_sub(pair_start_len),
 5049                                &pair.start,
 5050                            ) {
 5051                                selection.start -= pair_start_len;
 5052                                selection.end += pair.end.len();
 5053
 5054                                return selection;
 5055                            }
 5056                        }
 5057                    }
 5058                }
 5059
 5060                selection
 5061            })
 5062            .collect();
 5063
 5064        drop(buffer);
 5065        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5066            selections.select(new_selections)
 5067        });
 5068    }
 5069
 5070    /// Iterate the given selections, and for each one, find the smallest surrounding
 5071    /// autoclose region. This uses the ordering of the selections and the autoclose
 5072    /// regions to avoid repeated comparisons.
 5073    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5074        &'a self,
 5075        selections: impl IntoIterator<Item = Selection<D>>,
 5076        buffer: &'a MultiBufferSnapshot,
 5077    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5078        let mut i = 0;
 5079        let mut regions = self.autoclose_regions.as_slice();
 5080        selections.into_iter().map(move |selection| {
 5081            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5082
 5083            let mut enclosing = None;
 5084            while let Some(pair_state) = regions.get(i) {
 5085                if pair_state.range.end.to_offset(buffer) < range.start {
 5086                    regions = &regions[i + 1..];
 5087                    i = 0;
 5088                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5089                    break;
 5090                } else {
 5091                    if pair_state.selection_id == selection.id {
 5092                        enclosing = Some(pair_state);
 5093                    }
 5094                    i += 1;
 5095                }
 5096            }
 5097
 5098            (selection, enclosing)
 5099        })
 5100    }
 5101
 5102    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5103    fn invalidate_autoclose_regions(
 5104        &mut self,
 5105        mut selections: &[Selection<Anchor>],
 5106        buffer: &MultiBufferSnapshot,
 5107    ) {
 5108        self.autoclose_regions.retain(|state| {
 5109            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5110                return false;
 5111            }
 5112
 5113            let mut i = 0;
 5114            while let Some(selection) = selections.get(i) {
 5115                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5116                    selections = &selections[1..];
 5117                    continue;
 5118                }
 5119                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5120                    break;
 5121                }
 5122                if selection.id == state.selection_id {
 5123                    return true;
 5124                } else {
 5125                    i += 1;
 5126                }
 5127            }
 5128            false
 5129        });
 5130    }
 5131
 5132    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5133        let offset = position.to_offset(buffer);
 5134        let (word_range, kind) =
 5135            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5136        if offset > word_range.start && kind == Some(CharKind::Word) {
 5137            Some(
 5138                buffer
 5139                    .text_for_range(word_range.start..offset)
 5140                    .collect::<String>(),
 5141            )
 5142        } else {
 5143            None
 5144        }
 5145    }
 5146
 5147    pub fn toggle_inline_values(
 5148        &mut self,
 5149        _: &ToggleInlineValues,
 5150        _: &mut Window,
 5151        cx: &mut Context<Self>,
 5152    ) {
 5153        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5154
 5155        self.refresh_inline_values(cx);
 5156    }
 5157
 5158    pub fn toggle_inlay_hints(
 5159        &mut self,
 5160        _: &ToggleInlayHints,
 5161        _: &mut Window,
 5162        cx: &mut Context<Self>,
 5163    ) {
 5164        self.refresh_inlay_hints(
 5165            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5166            cx,
 5167        );
 5168    }
 5169
 5170    pub fn inlay_hints_enabled(&self) -> bool {
 5171        self.inlay_hint_cache.enabled
 5172    }
 5173
 5174    pub fn inline_values_enabled(&self) -> bool {
 5175        self.inline_value_cache.enabled
 5176    }
 5177
 5178    #[cfg(any(test, feature = "test-support"))]
 5179    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5180        self.display_map
 5181            .read(cx)
 5182            .current_inlays()
 5183            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5184            .cloned()
 5185            .collect()
 5186    }
 5187
 5188    #[cfg(any(test, feature = "test-support"))]
 5189    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5190        self.display_map
 5191            .read(cx)
 5192            .current_inlays()
 5193            .cloned()
 5194            .collect()
 5195    }
 5196
 5197    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5198        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5199            return;
 5200        }
 5201
 5202        let reason_description = reason.description();
 5203        let ignore_debounce = matches!(
 5204            reason,
 5205            InlayHintRefreshReason::SettingsChange(_)
 5206                | InlayHintRefreshReason::Toggle(_)
 5207                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5208                | InlayHintRefreshReason::ModifiersChanged(_)
 5209        );
 5210        let (invalidate_cache, required_languages) = match reason {
 5211            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5212                match self.inlay_hint_cache.modifiers_override(enabled) {
 5213                    Some(enabled) => {
 5214                        if enabled {
 5215                            (InvalidationStrategy::RefreshRequested, None)
 5216                        } else {
 5217                            self.splice_inlays(
 5218                                &self
 5219                                    .visible_inlay_hints(cx)
 5220                                    .iter()
 5221                                    .map(|inlay| inlay.id)
 5222                                    .collect::<Vec<InlayId>>(),
 5223                                Vec::new(),
 5224                                cx,
 5225                            );
 5226                            return;
 5227                        }
 5228                    }
 5229                    None => return,
 5230                }
 5231            }
 5232            InlayHintRefreshReason::Toggle(enabled) => {
 5233                if self.inlay_hint_cache.toggle(enabled) {
 5234                    if enabled {
 5235                        (InvalidationStrategy::RefreshRequested, None)
 5236                    } else {
 5237                        self.splice_inlays(
 5238                            &self
 5239                                .visible_inlay_hints(cx)
 5240                                .iter()
 5241                                .map(|inlay| inlay.id)
 5242                                .collect::<Vec<InlayId>>(),
 5243                            Vec::new(),
 5244                            cx,
 5245                        );
 5246                        return;
 5247                    }
 5248                } else {
 5249                    return;
 5250                }
 5251            }
 5252            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5253                match self.inlay_hint_cache.update_settings(
 5254                    &self.buffer,
 5255                    new_settings,
 5256                    self.visible_inlay_hints(cx),
 5257                    cx,
 5258                ) {
 5259                    ControlFlow::Break(Some(InlaySplice {
 5260                        to_remove,
 5261                        to_insert,
 5262                    })) => {
 5263                        self.splice_inlays(&to_remove, to_insert, cx);
 5264                        return;
 5265                    }
 5266                    ControlFlow::Break(None) => return,
 5267                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5268                }
 5269            }
 5270            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5271                if let Some(InlaySplice {
 5272                    to_remove,
 5273                    to_insert,
 5274                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5275                {
 5276                    self.splice_inlays(&to_remove, to_insert, cx);
 5277                }
 5278                self.display_map.update(cx, |display_map, _| {
 5279                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5280                });
 5281                return;
 5282            }
 5283            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5284            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5285                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5286            }
 5287            InlayHintRefreshReason::RefreshRequested => {
 5288                (InvalidationStrategy::RefreshRequested, None)
 5289            }
 5290        };
 5291
 5292        if let Some(InlaySplice {
 5293            to_remove,
 5294            to_insert,
 5295        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5296            reason_description,
 5297            self.visible_excerpts(required_languages.as_ref(), cx),
 5298            invalidate_cache,
 5299            ignore_debounce,
 5300            cx,
 5301        ) {
 5302            self.splice_inlays(&to_remove, to_insert, cx);
 5303        }
 5304    }
 5305
 5306    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5307        self.display_map
 5308            .read(cx)
 5309            .current_inlays()
 5310            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5311            .cloned()
 5312            .collect()
 5313    }
 5314
 5315    pub fn visible_excerpts(
 5316        &self,
 5317        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5318        cx: &mut Context<Editor>,
 5319    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5320        let Some(project) = self.project() else {
 5321            return HashMap::default();
 5322        };
 5323        let project = project.read(cx);
 5324        let multi_buffer = self.buffer().read(cx);
 5325        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5326        let multi_buffer_visible_start = self
 5327            .scroll_manager
 5328            .anchor()
 5329            .anchor
 5330            .to_point(&multi_buffer_snapshot);
 5331        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5332            multi_buffer_visible_start
 5333                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5334            Bias::Left,
 5335        );
 5336        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5337        multi_buffer_snapshot
 5338            .range_to_buffer_ranges(multi_buffer_visible_range)
 5339            .into_iter()
 5340            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5341            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5342                let buffer_file = project::File::from_dyn(buffer.file())?;
 5343                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5344                let worktree_entry = buffer_worktree
 5345                    .read(cx)
 5346                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5347                if worktree_entry.is_ignored {
 5348                    return None;
 5349                }
 5350
 5351                let language = buffer.language()?;
 5352                if let Some(restrict_to_languages) = restrict_to_languages
 5353                    && !restrict_to_languages.contains(language)
 5354                {
 5355                    return None;
 5356                }
 5357                Some((
 5358                    excerpt_id,
 5359                    (
 5360                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5361                        buffer.version().clone(),
 5362                        excerpt_visible_range,
 5363                    ),
 5364                ))
 5365            })
 5366            .collect()
 5367    }
 5368
 5369    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5370        TextLayoutDetails {
 5371            text_system: window.text_system().clone(),
 5372            editor_style: self.style.clone().unwrap(),
 5373            rem_size: window.rem_size(),
 5374            scroll_anchor: self.scroll_manager.anchor(),
 5375            visible_rows: self.visible_line_count(),
 5376            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5377        }
 5378    }
 5379
 5380    pub fn splice_inlays(
 5381        &self,
 5382        to_remove: &[InlayId],
 5383        to_insert: Vec<Inlay>,
 5384        cx: &mut Context<Self>,
 5385    ) {
 5386        self.display_map.update(cx, |display_map, cx| {
 5387            display_map.splice_inlays(to_remove, to_insert, cx)
 5388        });
 5389        cx.notify();
 5390    }
 5391
 5392    fn trigger_on_type_formatting(
 5393        &self,
 5394        input: String,
 5395        window: &mut Window,
 5396        cx: &mut Context<Self>,
 5397    ) -> Option<Task<Result<()>>> {
 5398        if input.len() != 1 {
 5399            return None;
 5400        }
 5401
 5402        let project = self.project()?;
 5403        let position = self.selections.newest_anchor().head();
 5404        let (buffer, buffer_position) = self
 5405            .buffer
 5406            .read(cx)
 5407            .text_anchor_for_position(position, cx)?;
 5408
 5409        let settings = language_settings::language_settings(
 5410            buffer
 5411                .read(cx)
 5412                .language_at(buffer_position)
 5413                .map(|l| l.name()),
 5414            buffer.read(cx).file(),
 5415            cx,
 5416        );
 5417        if !settings.use_on_type_format {
 5418            return None;
 5419        }
 5420
 5421        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5422        // hence we do LSP request & edit on host side only — add formats to host's history.
 5423        let push_to_lsp_host_history = true;
 5424        // If this is not the host, append its history with new edits.
 5425        let push_to_client_history = project.read(cx).is_via_collab();
 5426
 5427        let on_type_formatting = project.update(cx, |project, cx| {
 5428            project.on_type_format(
 5429                buffer.clone(),
 5430                buffer_position,
 5431                input,
 5432                push_to_lsp_host_history,
 5433                cx,
 5434            )
 5435        });
 5436        Some(cx.spawn_in(window, async move |editor, cx| {
 5437            if let Some(transaction) = on_type_formatting.await? {
 5438                if push_to_client_history {
 5439                    buffer
 5440                        .update(cx, |buffer, _| {
 5441                            buffer.push_transaction(transaction, Instant::now());
 5442                            buffer.finalize_last_transaction();
 5443                        })
 5444                        .ok();
 5445                }
 5446                editor.update(cx, |editor, cx| {
 5447                    editor.refresh_document_highlights(cx);
 5448                })?;
 5449            }
 5450            Ok(())
 5451        }))
 5452    }
 5453
 5454    pub fn show_word_completions(
 5455        &mut self,
 5456        _: &ShowWordCompletions,
 5457        window: &mut Window,
 5458        cx: &mut Context<Self>,
 5459    ) {
 5460        self.open_or_update_completions_menu(
 5461            Some(CompletionsMenuSource::Words {
 5462                ignore_threshold: true,
 5463            }),
 5464            None,
 5465            window,
 5466            cx,
 5467        );
 5468    }
 5469
 5470    pub fn show_completions(
 5471        &mut self,
 5472        options: &ShowCompletions,
 5473        window: &mut Window,
 5474        cx: &mut Context<Self>,
 5475    ) {
 5476        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5477    }
 5478
 5479    fn open_or_update_completions_menu(
 5480        &mut self,
 5481        requested_source: Option<CompletionsMenuSource>,
 5482        trigger: Option<&str>,
 5483        window: &mut Window,
 5484        cx: &mut Context<Self>,
 5485    ) {
 5486        if self.pending_rename.is_some() {
 5487            return;
 5488        }
 5489
 5490        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5491
 5492        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5493        // inserted and selected. To handle that case, the start of the selection is used so that
 5494        // the menu starts with all choices.
 5495        let position = self
 5496            .selections
 5497            .newest_anchor()
 5498            .start
 5499            .bias_right(&multibuffer_snapshot);
 5500        if position.diff_base_anchor.is_some() {
 5501            return;
 5502        }
 5503        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5504        let Some(buffer) = buffer_position
 5505            .buffer_id
 5506            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5507        else {
 5508            return;
 5509        };
 5510        let buffer_snapshot = buffer.read(cx).snapshot();
 5511
 5512        let query: Option<Arc<String>> =
 5513            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5514                .map(|query| query.into());
 5515
 5516        drop(multibuffer_snapshot);
 5517
 5518        // Hide the current completions menu when query is empty. Without this, cached
 5519        // completions from before the trigger char may be reused (#32774).
 5520        if query.is_none() {
 5521            let menu_is_open = matches!(
 5522                self.context_menu.borrow().as_ref(),
 5523                Some(CodeContextMenu::Completions(_))
 5524            );
 5525            if menu_is_open {
 5526                self.hide_context_menu(window, cx);
 5527            }
 5528        }
 5529
 5530        let mut ignore_word_threshold = false;
 5531        let provider = match requested_source {
 5532            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5533            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5534                ignore_word_threshold = ignore_threshold;
 5535                None
 5536            }
 5537            Some(CompletionsMenuSource::SnippetChoices) => {
 5538                log::error!("bug: SnippetChoices requested_source is not handled");
 5539                None
 5540            }
 5541        };
 5542
 5543        let sort_completions = provider
 5544            .as_ref()
 5545            .is_some_and(|provider| provider.sort_completions());
 5546
 5547        let filter_completions = provider
 5548            .as_ref()
 5549            .is_none_or(|provider| provider.filter_completions());
 5550
 5551        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5552            if filter_completions {
 5553                menu.filter(query.clone(), provider.clone(), window, cx);
 5554            }
 5555            // When `is_incomplete` is false, no need to re-query completions when the current query
 5556            // is a suffix of the initial query.
 5557            if !menu.is_incomplete {
 5558                // If the new query is a suffix of the old query (typing more characters) and
 5559                // the previous result was complete, the existing completions can be filtered.
 5560                //
 5561                // Note that this is always true for snippet completions.
 5562                let query_matches = match (&menu.initial_query, &query) {
 5563                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5564                    (None, _) => true,
 5565                    _ => false,
 5566                };
 5567                if query_matches {
 5568                    let position_matches = if menu.initial_position == position {
 5569                        true
 5570                    } else {
 5571                        let snapshot = self.buffer.read(cx).read(cx);
 5572                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5573                    };
 5574                    if position_matches {
 5575                        return;
 5576                    }
 5577                }
 5578            }
 5579        };
 5580
 5581        let trigger_kind = match trigger {
 5582            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5583                CompletionTriggerKind::TRIGGER_CHARACTER
 5584            }
 5585            _ => CompletionTriggerKind::INVOKED,
 5586        };
 5587        let completion_context = CompletionContext {
 5588            trigger_character: trigger.and_then(|trigger| {
 5589                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5590                    Some(String::from(trigger))
 5591                } else {
 5592                    None
 5593                }
 5594            }),
 5595            trigger_kind,
 5596        };
 5597
 5598        let Anchor {
 5599            excerpt_id: buffer_excerpt_id,
 5600            text_anchor: buffer_position,
 5601            ..
 5602        } = buffer_position;
 5603
 5604        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5605            buffer_snapshot.surrounding_word(buffer_position, None)
 5606        {
 5607            let word_to_exclude = buffer_snapshot
 5608                .text_for_range(word_range.clone())
 5609                .collect::<String>();
 5610            (
 5611                buffer_snapshot.anchor_before(word_range.start)
 5612                    ..buffer_snapshot.anchor_after(buffer_position),
 5613                Some(word_to_exclude),
 5614            )
 5615        } else {
 5616            (buffer_position..buffer_position, None)
 5617        };
 5618
 5619        let language = buffer_snapshot
 5620            .language_at(buffer_position)
 5621            .map(|language| language.name());
 5622
 5623        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5624            .completions
 5625            .clone();
 5626
 5627        let show_completion_documentation = buffer_snapshot
 5628            .settings_at(buffer_position, cx)
 5629            .show_completion_documentation;
 5630
 5631        // The document can be large, so stay in reasonable bounds when searching for words,
 5632        // otherwise completion pop-up might be slow to appear.
 5633        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5634        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5635        let min_word_search = buffer_snapshot.clip_point(
 5636            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5637            Bias::Left,
 5638        );
 5639        let max_word_search = buffer_snapshot.clip_point(
 5640            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5641            Bias::Right,
 5642        );
 5643        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5644            ..buffer_snapshot.point_to_offset(max_word_search);
 5645
 5646        let skip_digits = query
 5647            .as_ref()
 5648            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5649
 5650        let omit_word_completions = !self.word_completions_enabled
 5651            || (!ignore_word_threshold
 5652                && match &query {
 5653                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5654                    None => completion_settings.words_min_length != 0,
 5655                });
 5656
 5657        let (mut words, provider_responses) = match &provider {
 5658            Some(provider) => {
 5659                let provider_responses = provider.completions(
 5660                    buffer_excerpt_id,
 5661                    &buffer,
 5662                    buffer_position,
 5663                    completion_context,
 5664                    window,
 5665                    cx,
 5666                );
 5667
 5668                let words = match (omit_word_completions, completion_settings.words) {
 5669                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5670                        Task::ready(BTreeMap::default())
 5671                    }
 5672                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5673                        .background_spawn(async move {
 5674                            buffer_snapshot.words_in_range(WordsQuery {
 5675                                fuzzy_contents: None,
 5676                                range: word_search_range,
 5677                                skip_digits,
 5678                            })
 5679                        }),
 5680                };
 5681
 5682                (words, provider_responses)
 5683            }
 5684            None => {
 5685                let words = if omit_word_completions {
 5686                    Task::ready(BTreeMap::default())
 5687                } else {
 5688                    cx.background_spawn(async move {
 5689                        buffer_snapshot.words_in_range(WordsQuery {
 5690                            fuzzy_contents: None,
 5691                            range: word_search_range,
 5692                            skip_digits,
 5693                        })
 5694                    })
 5695                };
 5696                (words, Task::ready(Ok(Vec::new())))
 5697            }
 5698        };
 5699
 5700        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5701
 5702        let id = post_inc(&mut self.next_completion_id);
 5703        let task = cx.spawn_in(window, async move |editor, cx| {
 5704            let Ok(()) = editor.update(cx, |this, _| {
 5705                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5706            }) else {
 5707                return;
 5708            };
 5709
 5710            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5711            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5712            let mut completions = Vec::new();
 5713            let mut is_incomplete = false;
 5714            let mut display_options: Option<CompletionDisplayOptions> = None;
 5715            if let Some(provider_responses) = provider_responses.await.log_err()
 5716                && !provider_responses.is_empty()
 5717            {
 5718                for response in provider_responses {
 5719                    completions.extend(response.completions);
 5720                    is_incomplete = is_incomplete || response.is_incomplete;
 5721                    match display_options.as_mut() {
 5722                        None => {
 5723                            display_options = Some(response.display_options);
 5724                        }
 5725                        Some(options) => options.merge(&response.display_options),
 5726                    }
 5727                }
 5728                if completion_settings.words == WordsCompletionMode::Fallback {
 5729                    words = Task::ready(BTreeMap::default());
 5730                }
 5731            }
 5732            let display_options = display_options.unwrap_or_default();
 5733
 5734            let mut words = words.await;
 5735            if let Some(word_to_exclude) = &word_to_exclude {
 5736                words.remove(word_to_exclude);
 5737            }
 5738            for lsp_completion in &completions {
 5739                words.remove(&lsp_completion.new_text);
 5740            }
 5741            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5742                replace_range: word_replace_range.clone(),
 5743                new_text: word.clone(),
 5744                label: CodeLabel::plain(word, None),
 5745                icon_path: None,
 5746                documentation: None,
 5747                source: CompletionSource::BufferWord {
 5748                    word_range,
 5749                    resolved: false,
 5750                },
 5751                insert_text_mode: Some(InsertTextMode::AS_IS),
 5752                confirm: None,
 5753            }));
 5754
 5755            let menu = if completions.is_empty() {
 5756                None
 5757            } else {
 5758                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5759                    let languages = editor
 5760                        .workspace
 5761                        .as_ref()
 5762                        .and_then(|(workspace, _)| workspace.upgrade())
 5763                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5764                    let menu = CompletionsMenu::new(
 5765                        id,
 5766                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5767                        sort_completions,
 5768                        show_completion_documentation,
 5769                        position,
 5770                        query.clone(),
 5771                        is_incomplete,
 5772                        buffer.clone(),
 5773                        completions.into(),
 5774                        display_options,
 5775                        snippet_sort_order,
 5776                        languages,
 5777                        language,
 5778                        cx,
 5779                    );
 5780
 5781                    let query = if filter_completions { query } else { None };
 5782                    let matches_task = if let Some(query) = query {
 5783                        menu.do_async_filtering(query, cx)
 5784                    } else {
 5785                        Task::ready(menu.unfiltered_matches())
 5786                    };
 5787                    (menu, matches_task)
 5788                }) else {
 5789                    return;
 5790                };
 5791
 5792                let matches = matches_task.await;
 5793
 5794                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5795                    // Newer menu already set, so exit.
 5796                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5797                        editor.context_menu.borrow().as_ref()
 5798                        && prev_menu.id > id
 5799                    {
 5800                        return;
 5801                    };
 5802
 5803                    // Only valid to take prev_menu because it the new menu is immediately set
 5804                    // below, or the menu is hidden.
 5805                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5806                        editor.context_menu.borrow_mut().take()
 5807                    {
 5808                        let position_matches =
 5809                            if prev_menu.initial_position == menu.initial_position {
 5810                                true
 5811                            } else {
 5812                                let snapshot = editor.buffer.read(cx).read(cx);
 5813                                prev_menu.initial_position.to_offset(&snapshot)
 5814                                    == menu.initial_position.to_offset(&snapshot)
 5815                            };
 5816                        if position_matches {
 5817                            // Preserve markdown cache before `set_filter_results` because it will
 5818                            // try to populate the documentation cache.
 5819                            menu.preserve_markdown_cache(prev_menu);
 5820                        }
 5821                    };
 5822
 5823                    menu.set_filter_results(matches, provider, window, cx);
 5824                }) else {
 5825                    return;
 5826                };
 5827
 5828                menu.visible().then_some(menu)
 5829            };
 5830
 5831            editor
 5832                .update_in(cx, |editor, window, cx| {
 5833                    if editor.focus_handle.is_focused(window)
 5834                        && let Some(menu) = menu
 5835                    {
 5836                        *editor.context_menu.borrow_mut() =
 5837                            Some(CodeContextMenu::Completions(menu));
 5838
 5839                        crate::hover_popover::hide_hover(editor, cx);
 5840                        if editor.show_edit_predictions_in_menu() {
 5841                            editor.update_visible_edit_prediction(window, cx);
 5842                        } else {
 5843                            editor.discard_edit_prediction(false, cx);
 5844                        }
 5845
 5846                        cx.notify();
 5847                        return;
 5848                    }
 5849
 5850                    if editor.completion_tasks.len() <= 1 {
 5851                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5852                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5853                        // If it was already hidden and we don't show edit predictions in the menu,
 5854                        // we should also show the edit prediction when available.
 5855                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5856                            editor.update_visible_edit_prediction(window, cx);
 5857                        }
 5858                    }
 5859                })
 5860                .ok();
 5861        });
 5862
 5863        self.completion_tasks.push((id, task));
 5864    }
 5865
 5866    #[cfg(feature = "test-support")]
 5867    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5868        let menu = self.context_menu.borrow();
 5869        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5870            let completions = menu.completions.borrow();
 5871            Some(completions.to_vec())
 5872        } else {
 5873            None
 5874        }
 5875    }
 5876
 5877    pub fn with_completions_menu_matching_id<R>(
 5878        &self,
 5879        id: CompletionId,
 5880        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5881    ) -> R {
 5882        let mut context_menu = self.context_menu.borrow_mut();
 5883        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5884            return f(None);
 5885        };
 5886        if completions_menu.id != id {
 5887            return f(None);
 5888        }
 5889        f(Some(completions_menu))
 5890    }
 5891
 5892    pub fn confirm_completion(
 5893        &mut self,
 5894        action: &ConfirmCompletion,
 5895        window: &mut Window,
 5896        cx: &mut Context<Self>,
 5897    ) -> Option<Task<Result<()>>> {
 5898        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5899        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5900    }
 5901
 5902    pub fn confirm_completion_insert(
 5903        &mut self,
 5904        _: &ConfirmCompletionInsert,
 5905        window: &mut Window,
 5906        cx: &mut Context<Self>,
 5907    ) -> Option<Task<Result<()>>> {
 5908        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5909        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5910    }
 5911
 5912    pub fn confirm_completion_replace(
 5913        &mut self,
 5914        _: &ConfirmCompletionReplace,
 5915        window: &mut Window,
 5916        cx: &mut Context<Self>,
 5917    ) -> Option<Task<Result<()>>> {
 5918        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5919        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5920    }
 5921
 5922    pub fn compose_completion(
 5923        &mut self,
 5924        action: &ComposeCompletion,
 5925        window: &mut Window,
 5926        cx: &mut Context<Self>,
 5927    ) -> Option<Task<Result<()>>> {
 5928        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5929        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5930    }
 5931
 5932    fn do_completion(
 5933        &mut self,
 5934        item_ix: Option<usize>,
 5935        intent: CompletionIntent,
 5936        window: &mut Window,
 5937        cx: &mut Context<Editor>,
 5938    ) -> Option<Task<Result<()>>> {
 5939        use language::ToOffset as _;
 5940
 5941        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5942        else {
 5943            return None;
 5944        };
 5945
 5946        let candidate_id = {
 5947            let entries = completions_menu.entries.borrow();
 5948            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5949            if self.show_edit_predictions_in_menu() {
 5950                self.discard_edit_prediction(true, cx);
 5951            }
 5952            mat.candidate_id
 5953        };
 5954
 5955        let completion = completions_menu
 5956            .completions
 5957            .borrow()
 5958            .get(candidate_id)?
 5959            .clone();
 5960        cx.stop_propagation();
 5961
 5962        let buffer_handle = completions_menu.buffer.clone();
 5963
 5964        let CompletionEdit {
 5965            new_text,
 5966            snippet,
 5967            replace_range,
 5968        } = process_completion_for_edit(
 5969            &completion,
 5970            intent,
 5971            &buffer_handle,
 5972            &completions_menu.initial_position.text_anchor,
 5973            cx,
 5974        );
 5975
 5976        let buffer = buffer_handle.read(cx);
 5977        let snapshot = self.buffer.read(cx).snapshot(cx);
 5978        let newest_anchor = self.selections.newest_anchor();
 5979        let replace_range_multibuffer = {
 5980            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5981            let multibuffer_anchor = snapshot
 5982                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5983                .unwrap()
 5984                ..snapshot
 5985                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5986                    .unwrap();
 5987            multibuffer_anchor.start.to_offset(&snapshot)
 5988                ..multibuffer_anchor.end.to_offset(&snapshot)
 5989        };
 5990        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5991            return None;
 5992        }
 5993
 5994        let old_text = buffer
 5995            .text_for_range(replace_range.clone())
 5996            .collect::<String>();
 5997        let lookbehind = newest_anchor
 5998            .start
 5999            .text_anchor
 6000            .to_offset(buffer)
 6001            .saturating_sub(replace_range.start);
 6002        let lookahead = replace_range
 6003            .end
 6004            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6005        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6006        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6007
 6008        let selections = self.selections.all::<usize>(cx);
 6009        let mut ranges = Vec::new();
 6010        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6011
 6012        for selection in &selections {
 6013            let range = if selection.id == newest_anchor.id {
 6014                replace_range_multibuffer.clone()
 6015            } else {
 6016                let mut range = selection.range();
 6017
 6018                // if prefix is present, don't duplicate it
 6019                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6020                    range.start = range.start.saturating_sub(lookbehind);
 6021
 6022                    // if suffix is also present, mimic the newest cursor and replace it
 6023                    if selection.id != newest_anchor.id
 6024                        && snapshot.contains_str_at(range.end, suffix)
 6025                    {
 6026                        range.end += lookahead;
 6027                    }
 6028                }
 6029                range
 6030            };
 6031
 6032            ranges.push(range.clone());
 6033
 6034            if !self.linked_edit_ranges.is_empty() {
 6035                let start_anchor = snapshot.anchor_before(range.start);
 6036                let end_anchor = snapshot.anchor_after(range.end);
 6037                if let Some(ranges) = self
 6038                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6039                {
 6040                    for (buffer, edits) in ranges {
 6041                        linked_edits
 6042                            .entry(buffer.clone())
 6043                            .or_default()
 6044                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6045                    }
 6046                }
 6047            }
 6048        }
 6049
 6050        let common_prefix_len = old_text
 6051            .chars()
 6052            .zip(new_text.chars())
 6053            .take_while(|(a, b)| a == b)
 6054            .map(|(a, _)| a.len_utf8())
 6055            .sum::<usize>();
 6056
 6057        cx.emit(EditorEvent::InputHandled {
 6058            utf16_range_to_replace: None,
 6059            text: new_text[common_prefix_len..].into(),
 6060        });
 6061
 6062        self.transact(window, cx, |editor, window, cx| {
 6063            if let Some(mut snippet) = snippet {
 6064                snippet.text = new_text.to_string();
 6065                editor
 6066                    .insert_snippet(&ranges, snippet, window, cx)
 6067                    .log_err();
 6068            } else {
 6069                editor.buffer.update(cx, |multi_buffer, cx| {
 6070                    let auto_indent = match completion.insert_text_mode {
 6071                        Some(InsertTextMode::AS_IS) => None,
 6072                        _ => editor.autoindent_mode.clone(),
 6073                    };
 6074                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6075                    multi_buffer.edit(edits, auto_indent, cx);
 6076                });
 6077            }
 6078            for (buffer, edits) in linked_edits {
 6079                buffer.update(cx, |buffer, cx| {
 6080                    let snapshot = buffer.snapshot();
 6081                    let edits = edits
 6082                        .into_iter()
 6083                        .map(|(range, text)| {
 6084                            use text::ToPoint as TP;
 6085                            let end_point = TP::to_point(&range.end, &snapshot);
 6086                            let start_point = TP::to_point(&range.start, &snapshot);
 6087                            (start_point..end_point, text)
 6088                        })
 6089                        .sorted_by_key(|(range, _)| range.start);
 6090                    buffer.edit(edits, None, cx);
 6091                })
 6092            }
 6093
 6094            editor.refresh_edit_prediction(true, false, window, cx);
 6095        });
 6096        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6097
 6098        let show_new_completions_on_confirm = completion
 6099            .confirm
 6100            .as_ref()
 6101            .is_some_and(|confirm| confirm(intent, window, cx));
 6102        if show_new_completions_on_confirm {
 6103            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6104        }
 6105
 6106        let provider = self.completion_provider.as_ref()?;
 6107        drop(completion);
 6108        let apply_edits = provider.apply_additional_edits_for_completion(
 6109            buffer_handle,
 6110            completions_menu.completions.clone(),
 6111            candidate_id,
 6112            true,
 6113            cx,
 6114        );
 6115
 6116        let editor_settings = EditorSettings::get_global(cx);
 6117        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6118            // After the code completion is finished, users often want to know what signatures are needed.
 6119            // so we should automatically call signature_help
 6120            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6121        }
 6122
 6123        Some(cx.foreground_executor().spawn(async move {
 6124            apply_edits.await?;
 6125            Ok(())
 6126        }))
 6127    }
 6128
 6129    pub fn toggle_code_actions(
 6130        &mut self,
 6131        action: &ToggleCodeActions,
 6132        window: &mut Window,
 6133        cx: &mut Context<Self>,
 6134    ) {
 6135        let quick_launch = action.quick_launch;
 6136        let mut context_menu = self.context_menu.borrow_mut();
 6137        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6138            if code_actions.deployed_from == action.deployed_from {
 6139                // Toggle if we're selecting the same one
 6140                *context_menu = None;
 6141                cx.notify();
 6142                return;
 6143            } else {
 6144                // Otherwise, clear it and start a new one
 6145                *context_menu = None;
 6146                cx.notify();
 6147            }
 6148        }
 6149        drop(context_menu);
 6150        let snapshot = self.snapshot(window, cx);
 6151        let deployed_from = action.deployed_from.clone();
 6152        let action = action.clone();
 6153        self.completion_tasks.clear();
 6154        self.discard_edit_prediction(false, cx);
 6155
 6156        let multibuffer_point = match &action.deployed_from {
 6157            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6158                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6159            }
 6160            _ => self.selections.newest::<Point>(cx).head(),
 6161        };
 6162        let Some((buffer, buffer_row)) = snapshot
 6163            .buffer_snapshot
 6164            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6165            .and_then(|(buffer_snapshot, range)| {
 6166                self.buffer()
 6167                    .read(cx)
 6168                    .buffer(buffer_snapshot.remote_id())
 6169                    .map(|buffer| (buffer, range.start.row))
 6170            })
 6171        else {
 6172            return;
 6173        };
 6174        let buffer_id = buffer.read(cx).remote_id();
 6175        let tasks = self
 6176            .tasks
 6177            .get(&(buffer_id, buffer_row))
 6178            .map(|t| Arc::new(t.to_owned()));
 6179
 6180        if !self.focus_handle.is_focused(window) {
 6181            return;
 6182        }
 6183        let project = self.project.clone();
 6184
 6185        let code_actions_task = match deployed_from {
 6186            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6187            _ => self.code_actions(buffer_row, window, cx),
 6188        };
 6189
 6190        let runnable_task = match deployed_from {
 6191            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6192            _ => {
 6193                let mut task_context_task = Task::ready(None);
 6194                if let Some(tasks) = &tasks
 6195                    && let Some(project) = project
 6196                {
 6197                    task_context_task =
 6198                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6199                }
 6200
 6201                cx.spawn_in(window, {
 6202                    let buffer = buffer.clone();
 6203                    async move |editor, cx| {
 6204                        let task_context = task_context_task.await;
 6205
 6206                        let resolved_tasks =
 6207                            tasks
 6208                                .zip(task_context.clone())
 6209                                .map(|(tasks, task_context)| ResolvedTasks {
 6210                                    templates: tasks.resolve(&task_context).collect(),
 6211                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6212                                        multibuffer_point.row,
 6213                                        tasks.column,
 6214                                    )),
 6215                                });
 6216                        let debug_scenarios = editor
 6217                            .update(cx, |editor, cx| {
 6218                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6219                            })?
 6220                            .await;
 6221                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6222                    }
 6223                })
 6224            }
 6225        };
 6226
 6227        cx.spawn_in(window, async move |editor, cx| {
 6228            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6229            let code_actions = code_actions_task.await;
 6230            let spawn_straight_away = quick_launch
 6231                && resolved_tasks
 6232                    .as_ref()
 6233                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6234                && code_actions
 6235                    .as_ref()
 6236                    .is_none_or(|actions| actions.is_empty())
 6237                && debug_scenarios.is_empty();
 6238
 6239            editor.update_in(cx, |editor, window, cx| {
 6240                crate::hover_popover::hide_hover(editor, cx);
 6241                let actions = CodeActionContents::new(
 6242                    resolved_tasks,
 6243                    code_actions,
 6244                    debug_scenarios,
 6245                    task_context.unwrap_or_default(),
 6246                );
 6247
 6248                // Don't show the menu if there are no actions available
 6249                if actions.is_empty() {
 6250                    cx.notify();
 6251                    return Task::ready(Ok(()));
 6252                }
 6253
 6254                *editor.context_menu.borrow_mut() =
 6255                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6256                        buffer,
 6257                        actions,
 6258                        selected_item: Default::default(),
 6259                        scroll_handle: UniformListScrollHandle::default(),
 6260                        deployed_from,
 6261                    }));
 6262                cx.notify();
 6263                if spawn_straight_away
 6264                    && let Some(task) = editor.confirm_code_action(
 6265                        &ConfirmCodeAction { item_ix: Some(0) },
 6266                        window,
 6267                        cx,
 6268                    )
 6269                {
 6270                    return task;
 6271                }
 6272
 6273                Task::ready(Ok(()))
 6274            })
 6275        })
 6276        .detach_and_log_err(cx);
 6277    }
 6278
 6279    fn debug_scenarios(
 6280        &mut self,
 6281        resolved_tasks: &Option<ResolvedTasks>,
 6282        buffer: &Entity<Buffer>,
 6283        cx: &mut App,
 6284    ) -> Task<Vec<task::DebugScenario>> {
 6285        maybe!({
 6286            let project = self.project()?;
 6287            let dap_store = project.read(cx).dap_store();
 6288            let mut scenarios = vec![];
 6289            let resolved_tasks = resolved_tasks.as_ref()?;
 6290            let buffer = buffer.read(cx);
 6291            let language = buffer.language()?;
 6292            let file = buffer.file();
 6293            let debug_adapter = language_settings(language.name().into(), file, cx)
 6294                .debuggers
 6295                .first()
 6296                .map(SharedString::from)
 6297                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6298
 6299            dap_store.update(cx, |dap_store, cx| {
 6300                for (_, task) in &resolved_tasks.templates {
 6301                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6302                        task.original_task().clone(),
 6303                        debug_adapter.clone().into(),
 6304                        task.display_label().to_owned().into(),
 6305                        cx,
 6306                    );
 6307                    scenarios.push(maybe_scenario);
 6308                }
 6309            });
 6310            Some(cx.background_spawn(async move {
 6311                futures::future::join_all(scenarios)
 6312                    .await
 6313                    .into_iter()
 6314                    .flatten()
 6315                    .collect::<Vec<_>>()
 6316            }))
 6317        })
 6318        .unwrap_or_else(|| Task::ready(vec![]))
 6319    }
 6320
 6321    fn code_actions(
 6322        &mut self,
 6323        buffer_row: u32,
 6324        window: &mut Window,
 6325        cx: &mut Context<Self>,
 6326    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6327        let mut task = self.code_actions_task.take();
 6328        cx.spawn_in(window, async move |editor, cx| {
 6329            while let Some(prev_task) = task {
 6330                prev_task.await.log_err();
 6331                task = editor
 6332                    .update(cx, |this, _| this.code_actions_task.take())
 6333                    .ok()?;
 6334            }
 6335
 6336            editor
 6337                .update(cx, |editor, cx| {
 6338                    editor
 6339                        .available_code_actions
 6340                        .clone()
 6341                        .and_then(|(location, code_actions)| {
 6342                            let snapshot = location.buffer.read(cx).snapshot();
 6343                            let point_range = location.range.to_point(&snapshot);
 6344                            let point_range = point_range.start.row..=point_range.end.row;
 6345                            if point_range.contains(&buffer_row) {
 6346                                Some(code_actions)
 6347                            } else {
 6348                                None
 6349                            }
 6350                        })
 6351                })
 6352                .ok()
 6353                .flatten()
 6354        })
 6355    }
 6356
 6357    pub fn confirm_code_action(
 6358        &mut self,
 6359        action: &ConfirmCodeAction,
 6360        window: &mut Window,
 6361        cx: &mut Context<Self>,
 6362    ) -> Option<Task<Result<()>>> {
 6363        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6364
 6365        let actions_menu =
 6366            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6367                menu
 6368            } else {
 6369                return None;
 6370            };
 6371
 6372        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6373        let action = actions_menu.actions.get(action_ix)?;
 6374        let title = action.label();
 6375        let buffer = actions_menu.buffer;
 6376        let workspace = self.workspace()?;
 6377
 6378        match action {
 6379            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6380                workspace.update(cx, |workspace, cx| {
 6381                    workspace.schedule_resolved_task(
 6382                        task_source_kind,
 6383                        resolved_task,
 6384                        false,
 6385                        window,
 6386                        cx,
 6387                    );
 6388
 6389                    Some(Task::ready(Ok(())))
 6390                })
 6391            }
 6392            CodeActionsItem::CodeAction {
 6393                excerpt_id,
 6394                action,
 6395                provider,
 6396            } => {
 6397                let apply_code_action =
 6398                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6399                let workspace = workspace.downgrade();
 6400                Some(cx.spawn_in(window, async move |editor, cx| {
 6401                    let project_transaction = apply_code_action.await?;
 6402                    Self::open_project_transaction(
 6403                        &editor,
 6404                        workspace,
 6405                        project_transaction,
 6406                        title,
 6407                        cx,
 6408                    )
 6409                    .await
 6410                }))
 6411            }
 6412            CodeActionsItem::DebugScenario(scenario) => {
 6413                let context = actions_menu.actions.context;
 6414
 6415                workspace.update(cx, |workspace, cx| {
 6416                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6417                    workspace.start_debug_session(
 6418                        scenario,
 6419                        context,
 6420                        Some(buffer),
 6421                        None,
 6422                        window,
 6423                        cx,
 6424                    );
 6425                });
 6426                Some(Task::ready(Ok(())))
 6427            }
 6428        }
 6429    }
 6430
 6431    pub async fn open_project_transaction(
 6432        editor: &WeakEntity<Editor>,
 6433        workspace: WeakEntity<Workspace>,
 6434        transaction: ProjectTransaction,
 6435        title: String,
 6436        cx: &mut AsyncWindowContext,
 6437    ) -> Result<()> {
 6438        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6439        cx.update(|_, cx| {
 6440            entries.sort_unstable_by_key(|(buffer, _)| {
 6441                buffer.read(cx).file().map(|f| f.path().clone())
 6442            });
 6443        })?;
 6444        if entries.is_empty() {
 6445            return Ok(());
 6446        }
 6447
 6448        // If the project transaction's edits are all contained within this editor, then
 6449        // avoid opening a new editor to display them.
 6450
 6451        if let [(buffer, transaction)] = &*entries {
 6452            let excerpt = editor.update(cx, |editor, cx| {
 6453                editor
 6454                    .buffer()
 6455                    .read(cx)
 6456                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6457            })?;
 6458            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6459                && excerpted_buffer == *buffer
 6460            {
 6461                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6462                    let excerpt_range = excerpt_range.to_offset(buffer);
 6463                    buffer
 6464                        .edited_ranges_for_transaction::<usize>(transaction)
 6465                        .all(|range| {
 6466                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6467                        })
 6468                })?;
 6469
 6470                if all_edits_within_excerpt {
 6471                    return Ok(());
 6472                }
 6473            }
 6474        }
 6475
 6476        let mut ranges_to_highlight = Vec::new();
 6477        let excerpt_buffer = cx.new(|cx| {
 6478            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6479            for (buffer_handle, transaction) in &entries {
 6480                let edited_ranges = buffer_handle
 6481                    .read(cx)
 6482                    .edited_ranges_for_transaction::<Point>(transaction)
 6483                    .collect::<Vec<_>>();
 6484                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6485                    PathKey::for_buffer(buffer_handle, cx),
 6486                    buffer_handle.clone(),
 6487                    edited_ranges,
 6488                    multibuffer_context_lines(cx),
 6489                    cx,
 6490                );
 6491
 6492                ranges_to_highlight.extend(ranges);
 6493            }
 6494            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6495            multibuffer
 6496        })?;
 6497
 6498        workspace.update_in(cx, |workspace, window, cx| {
 6499            let project = workspace.project().clone();
 6500            let editor =
 6501                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6502            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6503            editor.update(cx, |editor, cx| {
 6504                editor.highlight_background::<Self>(
 6505                    &ranges_to_highlight,
 6506                    |theme| theme.colors().editor_highlighted_line_background,
 6507                    cx,
 6508                );
 6509            });
 6510        })?;
 6511
 6512        Ok(())
 6513    }
 6514
 6515    pub fn clear_code_action_providers(&mut self) {
 6516        self.code_action_providers.clear();
 6517        self.available_code_actions.take();
 6518    }
 6519
 6520    pub fn add_code_action_provider(
 6521        &mut self,
 6522        provider: Rc<dyn CodeActionProvider>,
 6523        window: &mut Window,
 6524        cx: &mut Context<Self>,
 6525    ) {
 6526        if self
 6527            .code_action_providers
 6528            .iter()
 6529            .any(|existing_provider| existing_provider.id() == provider.id())
 6530        {
 6531            return;
 6532        }
 6533
 6534        self.code_action_providers.push(provider);
 6535        self.refresh_code_actions(window, cx);
 6536    }
 6537
 6538    pub fn remove_code_action_provider(
 6539        &mut self,
 6540        id: Arc<str>,
 6541        window: &mut Window,
 6542        cx: &mut Context<Self>,
 6543    ) {
 6544        self.code_action_providers
 6545            .retain(|provider| provider.id() != id);
 6546        self.refresh_code_actions(window, cx);
 6547    }
 6548
 6549    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6550        !self.code_action_providers.is_empty()
 6551            && EditorSettings::get_global(cx).toolbar.code_actions
 6552    }
 6553
 6554    pub fn has_available_code_actions(&self) -> bool {
 6555        self.available_code_actions
 6556            .as_ref()
 6557            .is_some_and(|(_, actions)| !actions.is_empty())
 6558    }
 6559
 6560    fn render_inline_code_actions(
 6561        &self,
 6562        icon_size: ui::IconSize,
 6563        display_row: DisplayRow,
 6564        is_active: bool,
 6565        cx: &mut Context<Self>,
 6566    ) -> AnyElement {
 6567        let show_tooltip = !self.context_menu_visible();
 6568        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6569            .icon_size(icon_size)
 6570            .shape(ui::IconButtonShape::Square)
 6571            .icon_color(ui::Color::Hidden)
 6572            .toggle_state(is_active)
 6573            .when(show_tooltip, |this| {
 6574                this.tooltip({
 6575                    let focus_handle = self.focus_handle.clone();
 6576                    move |window, cx| {
 6577                        Tooltip::for_action_in(
 6578                            "Toggle Code Actions",
 6579                            &ToggleCodeActions {
 6580                                deployed_from: None,
 6581                                quick_launch: false,
 6582                            },
 6583                            &focus_handle,
 6584                            window,
 6585                            cx,
 6586                        )
 6587                    }
 6588                })
 6589            })
 6590            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6591                window.focus(&editor.focus_handle(cx));
 6592                editor.toggle_code_actions(
 6593                    &crate::actions::ToggleCodeActions {
 6594                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6595                            display_row,
 6596                        )),
 6597                        quick_launch: false,
 6598                    },
 6599                    window,
 6600                    cx,
 6601                );
 6602            }))
 6603            .into_any_element()
 6604    }
 6605
 6606    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6607        &self.context_menu
 6608    }
 6609
 6610    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6611        let newest_selection = self.selections.newest_anchor().clone();
 6612        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6613        let buffer = self.buffer.read(cx);
 6614        if newest_selection.head().diff_base_anchor.is_some() {
 6615            return None;
 6616        }
 6617        let (start_buffer, start) =
 6618            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6619        let (end_buffer, end) =
 6620            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6621        if start_buffer != end_buffer {
 6622            return None;
 6623        }
 6624
 6625        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6626            cx.background_executor()
 6627                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6628                .await;
 6629
 6630            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6631                let providers = this.code_action_providers.clone();
 6632                let tasks = this
 6633                    .code_action_providers
 6634                    .iter()
 6635                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6636                    .collect::<Vec<_>>();
 6637                (providers, tasks)
 6638            })?;
 6639
 6640            let mut actions = Vec::new();
 6641            for (provider, provider_actions) in
 6642                providers.into_iter().zip(future::join_all(tasks).await)
 6643            {
 6644                if let Some(provider_actions) = provider_actions.log_err() {
 6645                    actions.extend(provider_actions.into_iter().map(|action| {
 6646                        AvailableCodeAction {
 6647                            excerpt_id: newest_selection.start.excerpt_id,
 6648                            action,
 6649                            provider: provider.clone(),
 6650                        }
 6651                    }));
 6652                }
 6653            }
 6654
 6655            this.update(cx, |this, cx| {
 6656                this.available_code_actions = if actions.is_empty() {
 6657                    None
 6658                } else {
 6659                    Some((
 6660                        Location {
 6661                            buffer: start_buffer,
 6662                            range: start..end,
 6663                        },
 6664                        actions.into(),
 6665                    ))
 6666                };
 6667                cx.notify();
 6668            })
 6669        }));
 6670        None
 6671    }
 6672
 6673    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6674        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6675            self.show_git_blame_inline = false;
 6676
 6677            self.show_git_blame_inline_delay_task =
 6678                Some(cx.spawn_in(window, async move |this, cx| {
 6679                    cx.background_executor().timer(delay).await;
 6680
 6681                    this.update(cx, |this, cx| {
 6682                        this.show_git_blame_inline = true;
 6683                        cx.notify();
 6684                    })
 6685                    .log_err();
 6686                }));
 6687        }
 6688    }
 6689
 6690    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6691        let snapshot = self.snapshot(window, cx);
 6692        let cursor = self.selections.newest::<Point>(cx).head();
 6693        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6694        else {
 6695            return;
 6696        };
 6697
 6698        let Some(blame) = self.blame.as_ref() else {
 6699            return;
 6700        };
 6701
 6702        let row_info = RowInfo {
 6703            buffer_id: Some(buffer.remote_id()),
 6704            buffer_row: Some(point.row),
 6705            ..Default::default()
 6706        };
 6707        let Some((buffer, blame_entry)) = blame
 6708            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6709            .flatten()
 6710        else {
 6711            return;
 6712        };
 6713
 6714        let anchor = self.selections.newest_anchor().head();
 6715        let position = self.to_pixel_point(anchor, &snapshot, window);
 6716        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6717            self.show_blame_popover(
 6718                buffer,
 6719                &blame_entry,
 6720                position + last_bounds.origin,
 6721                true,
 6722                cx,
 6723            );
 6724        };
 6725    }
 6726
 6727    fn show_blame_popover(
 6728        &mut self,
 6729        buffer: BufferId,
 6730        blame_entry: &BlameEntry,
 6731        position: gpui::Point<Pixels>,
 6732        ignore_timeout: bool,
 6733        cx: &mut Context<Self>,
 6734    ) {
 6735        if let Some(state) = &mut self.inline_blame_popover {
 6736            state.hide_task.take();
 6737        } else {
 6738            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6739            let blame_entry = blame_entry.clone();
 6740            let show_task = cx.spawn(async move |editor, cx| {
 6741                if !ignore_timeout {
 6742                    cx.background_executor()
 6743                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6744                        .await;
 6745                }
 6746                editor
 6747                    .update(cx, |editor, cx| {
 6748                        editor.inline_blame_popover_show_task.take();
 6749                        let Some(blame) = editor.blame.as_ref() else {
 6750                            return;
 6751                        };
 6752                        let blame = blame.read(cx);
 6753                        let details = blame.details_for_entry(buffer, &blame_entry);
 6754                        let markdown = cx.new(|cx| {
 6755                            Markdown::new(
 6756                                details
 6757                                    .as_ref()
 6758                                    .map(|message| message.message.clone())
 6759                                    .unwrap_or_default(),
 6760                                None,
 6761                                None,
 6762                                cx,
 6763                            )
 6764                        });
 6765                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6766                            position,
 6767                            hide_task: None,
 6768                            popover_bounds: None,
 6769                            popover_state: InlineBlamePopoverState {
 6770                                scroll_handle: ScrollHandle::new(),
 6771                                commit_message: details,
 6772                                markdown,
 6773                            },
 6774                            keyboard_grace: ignore_timeout,
 6775                        });
 6776                        cx.notify();
 6777                    })
 6778                    .ok();
 6779            });
 6780            self.inline_blame_popover_show_task = Some(show_task);
 6781        }
 6782    }
 6783
 6784    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6785        self.inline_blame_popover_show_task.take();
 6786        if let Some(state) = &mut self.inline_blame_popover {
 6787            let hide_task = cx.spawn(async move |editor, cx| {
 6788                cx.background_executor()
 6789                    .timer(std::time::Duration::from_millis(100))
 6790                    .await;
 6791                editor
 6792                    .update(cx, |editor, cx| {
 6793                        editor.inline_blame_popover.take();
 6794                        cx.notify();
 6795                    })
 6796                    .ok();
 6797            });
 6798            state.hide_task = Some(hide_task);
 6799        }
 6800    }
 6801
 6802    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6803        if self.pending_rename.is_some() {
 6804            return None;
 6805        }
 6806
 6807        let provider = self.semantics_provider.clone()?;
 6808        let buffer = self.buffer.read(cx);
 6809        let newest_selection = self.selections.newest_anchor().clone();
 6810        let cursor_position = newest_selection.head();
 6811        let (cursor_buffer, cursor_buffer_position) =
 6812            buffer.text_anchor_for_position(cursor_position, cx)?;
 6813        let (tail_buffer, tail_buffer_position) =
 6814            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6815        if cursor_buffer != tail_buffer {
 6816            return None;
 6817        }
 6818
 6819        let snapshot = cursor_buffer.read(cx).snapshot();
 6820        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6821        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6822        if start_word_range != end_word_range {
 6823            self.document_highlights_task.take();
 6824            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6825            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6826            return None;
 6827        }
 6828
 6829        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6830        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6831            cx.background_executor()
 6832                .timer(Duration::from_millis(debounce))
 6833                .await;
 6834
 6835            let highlights = if let Some(highlights) = cx
 6836                .update(|cx| {
 6837                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6838                })
 6839                .ok()
 6840                .flatten()
 6841            {
 6842                highlights.await.log_err()
 6843            } else {
 6844                None
 6845            };
 6846
 6847            if let Some(highlights) = highlights {
 6848                this.update(cx, |this, cx| {
 6849                    if this.pending_rename.is_some() {
 6850                        return;
 6851                    }
 6852
 6853                    let buffer = this.buffer.read(cx);
 6854                    if buffer
 6855                        .text_anchor_for_position(cursor_position, cx)
 6856                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6857                    {
 6858                        return;
 6859                    }
 6860
 6861                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6862                    let mut write_ranges = Vec::new();
 6863                    let mut read_ranges = Vec::new();
 6864                    for highlight in highlights {
 6865                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6866                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6867                        {
 6868                            let start = highlight
 6869                                .range
 6870                                .start
 6871                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6872                            let end = highlight
 6873                                .range
 6874                                .end
 6875                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6876                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6877                                continue;
 6878                            }
 6879
 6880                            let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
 6881                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6882                                write_ranges.push(range);
 6883                            } else {
 6884                                read_ranges.push(range);
 6885                            }
 6886                        }
 6887                    }
 6888
 6889                    this.highlight_background::<DocumentHighlightRead>(
 6890                        &read_ranges,
 6891                        |theme| theme.colors().editor_document_highlight_read_background,
 6892                        cx,
 6893                    );
 6894                    this.highlight_background::<DocumentHighlightWrite>(
 6895                        &write_ranges,
 6896                        |theme| theme.colors().editor_document_highlight_write_background,
 6897                        cx,
 6898                    );
 6899                    cx.notify();
 6900                })
 6901                .log_err();
 6902            }
 6903        }));
 6904        None
 6905    }
 6906
 6907    fn prepare_highlight_query_from_selection(
 6908        &mut self,
 6909        cx: &mut Context<Editor>,
 6910    ) -> Option<(String, Range<Anchor>)> {
 6911        if matches!(self.mode, EditorMode::SingleLine) {
 6912            return None;
 6913        }
 6914        if !EditorSettings::get_global(cx).selection_highlight {
 6915            return None;
 6916        }
 6917        if self.selections.count() != 1 || self.selections.line_mode() {
 6918            return None;
 6919        }
 6920        let selection = self.selections.newest::<Point>(cx);
 6921        if selection.is_empty() || selection.start.row != selection.end.row {
 6922            return None;
 6923        }
 6924        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6925        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6926        let query = multi_buffer_snapshot
 6927            .text_for_range(selection_anchor_range.clone())
 6928            .collect::<String>();
 6929        if query.trim().is_empty() {
 6930            return None;
 6931        }
 6932        Some((query, selection_anchor_range))
 6933    }
 6934
 6935    fn update_selection_occurrence_highlights(
 6936        &mut self,
 6937        query_text: String,
 6938        query_range: Range<Anchor>,
 6939        multi_buffer_range_to_query: Range<Point>,
 6940        use_debounce: bool,
 6941        window: &mut Window,
 6942        cx: &mut Context<Editor>,
 6943    ) -> Task<()> {
 6944        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6945        cx.spawn_in(window, async move |editor, cx| {
 6946            if use_debounce {
 6947                cx.background_executor()
 6948                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6949                    .await;
 6950            }
 6951            let match_task = cx.background_spawn(async move {
 6952                let buffer_ranges = multi_buffer_snapshot
 6953                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6954                    .into_iter()
 6955                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6956                let mut match_ranges = Vec::new();
 6957                let Ok(regex) = project::search::SearchQuery::text(
 6958                    query_text.clone(),
 6959                    false,
 6960                    false,
 6961                    false,
 6962                    Default::default(),
 6963                    Default::default(),
 6964                    false,
 6965                    None,
 6966                ) else {
 6967                    return Vec::default();
 6968                };
 6969                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6970                    match_ranges.extend(
 6971                        regex
 6972                            .search(buffer_snapshot, Some(search_range.clone()))
 6973                            .await
 6974                            .into_iter()
 6975                            .filter_map(|match_range| {
 6976                                let match_start = buffer_snapshot
 6977                                    .anchor_after(search_range.start + match_range.start);
 6978                                let match_end = buffer_snapshot
 6979                                    .anchor_before(search_range.start + match_range.end);
 6980                                let match_anchor_range = Anchor::range_in_buffer(
 6981                                    excerpt_id,
 6982                                    buffer_snapshot.remote_id(),
 6983                                    match_start..match_end,
 6984                                );
 6985                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6986                            }),
 6987                    );
 6988                }
 6989                match_ranges
 6990            });
 6991            let match_ranges = match_task.await;
 6992            editor
 6993                .update_in(cx, |editor, _, cx| {
 6994                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6995                    if !match_ranges.is_empty() {
 6996                        editor.highlight_background::<SelectedTextHighlight>(
 6997                            &match_ranges,
 6998                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6999                            cx,
 7000                        )
 7001                    }
 7002                })
 7003                .log_err();
 7004        })
 7005    }
 7006
 7007    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7008        struct NewlineFold;
 7009        let type_id = std::any::TypeId::of::<NewlineFold>();
 7010        if !self.mode.is_single_line() {
 7011            return;
 7012        }
 7013        let snapshot = self.snapshot(window, cx);
 7014        if snapshot.buffer_snapshot.max_point().row == 0 {
 7015            return;
 7016        }
 7017        let task = cx.background_spawn(async move {
 7018            let new_newlines = snapshot
 7019                .buffer_chars_at(0)
 7020                .filter_map(|(c, i)| {
 7021                    if c == '\n' {
 7022                        Some(
 7023                            snapshot.buffer_snapshot.anchor_after(i)
 7024                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7025                        )
 7026                    } else {
 7027                        None
 7028                    }
 7029                })
 7030                .collect::<Vec<_>>();
 7031            let existing_newlines = snapshot
 7032                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7033                .filter_map(|fold| {
 7034                    if fold.placeholder.type_tag == Some(type_id) {
 7035                        Some(fold.range.start..fold.range.end)
 7036                    } else {
 7037                        None
 7038                    }
 7039                })
 7040                .collect::<Vec<_>>();
 7041
 7042            (new_newlines, existing_newlines)
 7043        });
 7044        self.folding_newlines = cx.spawn(async move |this, cx| {
 7045            let (new_newlines, existing_newlines) = task.await;
 7046            if new_newlines == existing_newlines {
 7047                return;
 7048            }
 7049            let placeholder = FoldPlaceholder {
 7050                render: Arc::new(move |_, _, cx| {
 7051                    div()
 7052                        .bg(cx.theme().status().hint_background)
 7053                        .border_b_1()
 7054                        .size_full()
 7055                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7056                        .border_color(cx.theme().status().hint)
 7057                        .child("\\n")
 7058                        .into_any()
 7059                }),
 7060                constrain_width: false,
 7061                merge_adjacent: false,
 7062                type_tag: Some(type_id),
 7063            };
 7064            let creases = new_newlines
 7065                .into_iter()
 7066                .map(|range| Crease::simple(range, placeholder.clone()))
 7067                .collect();
 7068            this.update(cx, |this, cx| {
 7069                this.display_map.update(cx, |display_map, cx| {
 7070                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7071                    display_map.fold(creases, cx);
 7072                });
 7073            })
 7074            .ok();
 7075        });
 7076    }
 7077
 7078    fn refresh_selected_text_highlights(
 7079        &mut self,
 7080        on_buffer_edit: bool,
 7081        window: &mut Window,
 7082        cx: &mut Context<Editor>,
 7083    ) {
 7084        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7085        else {
 7086            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7087            self.quick_selection_highlight_task.take();
 7088            self.debounced_selection_highlight_task.take();
 7089            return;
 7090        };
 7091        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7092        if on_buffer_edit
 7093            || self
 7094                .quick_selection_highlight_task
 7095                .as_ref()
 7096                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7097        {
 7098            let multi_buffer_visible_start = self
 7099                .scroll_manager
 7100                .anchor()
 7101                .anchor
 7102                .to_point(&multi_buffer_snapshot);
 7103            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7104                multi_buffer_visible_start
 7105                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7106                Bias::Left,
 7107            );
 7108            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7109            self.quick_selection_highlight_task = Some((
 7110                query_range.clone(),
 7111                self.update_selection_occurrence_highlights(
 7112                    query_text.clone(),
 7113                    query_range.clone(),
 7114                    multi_buffer_visible_range,
 7115                    false,
 7116                    window,
 7117                    cx,
 7118                ),
 7119            ));
 7120        }
 7121        if on_buffer_edit
 7122            || self
 7123                .debounced_selection_highlight_task
 7124                .as_ref()
 7125                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7126        {
 7127            let multi_buffer_start = multi_buffer_snapshot
 7128                .anchor_before(0)
 7129                .to_point(&multi_buffer_snapshot);
 7130            let multi_buffer_end = multi_buffer_snapshot
 7131                .anchor_after(multi_buffer_snapshot.len())
 7132                .to_point(&multi_buffer_snapshot);
 7133            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7134            self.debounced_selection_highlight_task = Some((
 7135                query_range.clone(),
 7136                self.update_selection_occurrence_highlights(
 7137                    query_text,
 7138                    query_range,
 7139                    multi_buffer_full_range,
 7140                    true,
 7141                    window,
 7142                    cx,
 7143                ),
 7144            ));
 7145        }
 7146    }
 7147
 7148    pub fn refresh_edit_prediction(
 7149        &mut self,
 7150        debounce: bool,
 7151        user_requested: bool,
 7152        window: &mut Window,
 7153        cx: &mut Context<Self>,
 7154    ) -> Option<()> {
 7155        if DisableAiSettings::get_global(cx).disable_ai {
 7156            return None;
 7157        }
 7158
 7159        let provider = self.edit_prediction_provider()?;
 7160        let cursor = self.selections.newest_anchor().head();
 7161        let (buffer, cursor_buffer_position) =
 7162            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7163
 7164        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7165            self.discard_edit_prediction(false, cx);
 7166            return None;
 7167        }
 7168
 7169        self.update_visible_edit_prediction(window, cx);
 7170
 7171        if !user_requested
 7172            && (!self.should_show_edit_predictions()
 7173                || !self.is_focused(window)
 7174                || buffer.read(cx).is_empty())
 7175        {
 7176            self.discard_edit_prediction(false, cx);
 7177            return None;
 7178        }
 7179
 7180        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7181        Some(())
 7182    }
 7183
 7184    fn show_edit_predictions_in_menu(&self) -> bool {
 7185        match self.edit_prediction_settings {
 7186            EditPredictionSettings::Disabled => false,
 7187            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7188        }
 7189    }
 7190
 7191    pub fn edit_predictions_enabled(&self) -> bool {
 7192        match self.edit_prediction_settings {
 7193            EditPredictionSettings::Disabled => false,
 7194            EditPredictionSettings::Enabled { .. } => true,
 7195        }
 7196    }
 7197
 7198    fn edit_prediction_requires_modifier(&self) -> bool {
 7199        match self.edit_prediction_settings {
 7200            EditPredictionSettings::Disabled => false,
 7201            EditPredictionSettings::Enabled {
 7202                preview_requires_modifier,
 7203                ..
 7204            } => preview_requires_modifier,
 7205        }
 7206    }
 7207
 7208    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7209        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7210            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7211            self.discard_edit_prediction(false, cx);
 7212        } else {
 7213            let selection = self.selections.newest_anchor();
 7214            let cursor = selection.head();
 7215
 7216            if let Some((buffer, cursor_buffer_position)) =
 7217                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7218            {
 7219                self.edit_prediction_settings =
 7220                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7221            }
 7222        }
 7223    }
 7224
 7225    fn edit_prediction_settings_at_position(
 7226        &self,
 7227        buffer: &Entity<Buffer>,
 7228        buffer_position: language::Anchor,
 7229        cx: &App,
 7230    ) -> EditPredictionSettings {
 7231        if !self.mode.is_full()
 7232            || !self.show_edit_predictions_override.unwrap_or(true)
 7233            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7234        {
 7235            return EditPredictionSettings::Disabled;
 7236        }
 7237
 7238        let buffer = buffer.read(cx);
 7239
 7240        let file = buffer.file();
 7241
 7242        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7243            return EditPredictionSettings::Disabled;
 7244        };
 7245
 7246        let by_provider = matches!(
 7247            self.menu_edit_predictions_policy,
 7248            MenuEditPredictionsPolicy::ByProvider
 7249        );
 7250
 7251        let show_in_menu = by_provider
 7252            && self
 7253                .edit_prediction_provider
 7254                .as_ref()
 7255                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7256
 7257        let preview_requires_modifier =
 7258            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7259
 7260        EditPredictionSettings::Enabled {
 7261            show_in_menu,
 7262            preview_requires_modifier,
 7263        }
 7264    }
 7265
 7266    fn should_show_edit_predictions(&self) -> bool {
 7267        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7268    }
 7269
 7270    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7271        matches!(
 7272            self.edit_prediction_preview,
 7273            EditPredictionPreview::Active { .. }
 7274        )
 7275    }
 7276
 7277    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7278        let cursor = self.selections.newest_anchor().head();
 7279        if let Some((buffer, cursor_position)) =
 7280            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7281        {
 7282            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7283        } else {
 7284            false
 7285        }
 7286    }
 7287
 7288    pub fn supports_minimap(&self, cx: &App) -> bool {
 7289        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7290    }
 7291
 7292    fn edit_predictions_enabled_in_buffer(
 7293        &self,
 7294        buffer: &Entity<Buffer>,
 7295        buffer_position: language::Anchor,
 7296        cx: &App,
 7297    ) -> bool {
 7298        maybe!({
 7299            if self.read_only(cx) {
 7300                return Some(false);
 7301            }
 7302            let provider = self.edit_prediction_provider()?;
 7303            if !provider.is_enabled(buffer, buffer_position, cx) {
 7304                return Some(false);
 7305            }
 7306            let buffer = buffer.read(cx);
 7307            let Some(file) = buffer.file() else {
 7308                return Some(true);
 7309            };
 7310            let settings = all_language_settings(Some(file), cx);
 7311            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7312        })
 7313        .unwrap_or(false)
 7314    }
 7315
 7316    fn cycle_edit_prediction(
 7317        &mut self,
 7318        direction: Direction,
 7319        window: &mut Window,
 7320        cx: &mut Context<Self>,
 7321    ) -> Option<()> {
 7322        let provider = self.edit_prediction_provider()?;
 7323        let cursor = self.selections.newest_anchor().head();
 7324        let (buffer, cursor_buffer_position) =
 7325            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7326        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7327            return None;
 7328        }
 7329
 7330        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7331        self.update_visible_edit_prediction(window, cx);
 7332
 7333        Some(())
 7334    }
 7335
 7336    pub fn show_edit_prediction(
 7337        &mut self,
 7338        _: &ShowEditPrediction,
 7339        window: &mut Window,
 7340        cx: &mut Context<Self>,
 7341    ) {
 7342        if !self.has_active_edit_prediction() {
 7343            self.refresh_edit_prediction(false, true, window, cx);
 7344            return;
 7345        }
 7346
 7347        self.update_visible_edit_prediction(window, cx);
 7348    }
 7349
 7350    pub fn display_cursor_names(
 7351        &mut self,
 7352        _: &DisplayCursorNames,
 7353        window: &mut Window,
 7354        cx: &mut Context<Self>,
 7355    ) {
 7356        self.show_cursor_names(window, cx);
 7357    }
 7358
 7359    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7360        self.show_cursor_names = true;
 7361        cx.notify();
 7362        cx.spawn_in(window, async move |this, cx| {
 7363            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7364            this.update(cx, |this, cx| {
 7365                this.show_cursor_names = false;
 7366                cx.notify()
 7367            })
 7368            .ok()
 7369        })
 7370        .detach();
 7371    }
 7372
 7373    pub fn next_edit_prediction(
 7374        &mut self,
 7375        _: &NextEditPrediction,
 7376        window: &mut Window,
 7377        cx: &mut Context<Self>,
 7378    ) {
 7379        if self.has_active_edit_prediction() {
 7380            self.cycle_edit_prediction(Direction::Next, window, cx);
 7381        } else {
 7382            let is_copilot_disabled = self
 7383                .refresh_edit_prediction(false, true, window, cx)
 7384                .is_none();
 7385            if is_copilot_disabled {
 7386                cx.propagate();
 7387            }
 7388        }
 7389    }
 7390
 7391    pub fn previous_edit_prediction(
 7392        &mut self,
 7393        _: &PreviousEditPrediction,
 7394        window: &mut Window,
 7395        cx: &mut Context<Self>,
 7396    ) {
 7397        if self.has_active_edit_prediction() {
 7398            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7399        } else {
 7400            let is_copilot_disabled = self
 7401                .refresh_edit_prediction(false, true, window, cx)
 7402                .is_none();
 7403            if is_copilot_disabled {
 7404                cx.propagate();
 7405            }
 7406        }
 7407    }
 7408
 7409    pub fn accept_edit_prediction(
 7410        &mut self,
 7411        _: &AcceptEditPrediction,
 7412        window: &mut Window,
 7413        cx: &mut Context<Self>,
 7414    ) {
 7415        if self.show_edit_predictions_in_menu() {
 7416            self.hide_context_menu(window, cx);
 7417        }
 7418
 7419        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7420            return;
 7421        };
 7422
 7423        match &active_edit_prediction.completion {
 7424            EditPrediction::MoveWithin { target, .. } => {
 7425                let target = *target;
 7426
 7427                if let Some(position_map) = &self.last_position_map {
 7428                    if position_map
 7429                        .visible_row_range
 7430                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7431                        || !self.edit_prediction_requires_modifier()
 7432                    {
 7433                        self.unfold_ranges(&[target..target], true, false, cx);
 7434                        // Note that this is also done in vim's handler of the Tab action.
 7435                        self.change_selections(
 7436                            SelectionEffects::scroll(Autoscroll::newest()),
 7437                            window,
 7438                            cx,
 7439                            |selections| {
 7440                                selections.select_anchor_ranges([target..target]);
 7441                            },
 7442                        );
 7443                        self.clear_row_highlights::<EditPredictionPreview>();
 7444
 7445                        self.edit_prediction_preview
 7446                            .set_previous_scroll_position(None);
 7447                    } else {
 7448                        self.edit_prediction_preview
 7449                            .set_previous_scroll_position(Some(
 7450                                position_map.snapshot.scroll_anchor,
 7451                            ));
 7452
 7453                        self.highlight_rows::<EditPredictionPreview>(
 7454                            target..target,
 7455                            cx.theme().colors().editor_highlighted_line_background,
 7456                            RowHighlightOptions {
 7457                                autoscroll: true,
 7458                                ..Default::default()
 7459                            },
 7460                            cx,
 7461                        );
 7462                        self.request_autoscroll(Autoscroll::fit(), cx);
 7463                    }
 7464                }
 7465            }
 7466            EditPrediction::MoveOutside { snapshot, target } => {
 7467                if let Some(workspace) = self.workspace() {
 7468                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7469                        .detach_and_log_err(cx);
 7470                }
 7471            }
 7472            EditPrediction::Edit { edits, .. } => {
 7473                self.report_edit_prediction_event(
 7474                    active_edit_prediction.completion_id.clone(),
 7475                    true,
 7476                    cx,
 7477                );
 7478
 7479                if let Some(provider) = self.edit_prediction_provider() {
 7480                    provider.accept(cx);
 7481                }
 7482
 7483                // Store the transaction ID and selections before applying the edit
 7484                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7485
 7486                let snapshot = self.buffer.read(cx).snapshot(cx);
 7487                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7488
 7489                self.buffer.update(cx, |buffer, cx| {
 7490                    buffer.edit(edits.iter().cloned(), None, cx)
 7491                });
 7492
 7493                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7494                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7495                });
 7496
 7497                let selections = self.selections.disjoint_anchors_arc();
 7498                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7499                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7500                    if has_new_transaction {
 7501                        self.selection_history
 7502                            .insert_transaction(transaction_id_now, selections);
 7503                    }
 7504                }
 7505
 7506                self.update_visible_edit_prediction(window, cx);
 7507                if self.active_edit_prediction.is_none() {
 7508                    self.refresh_edit_prediction(true, true, window, cx);
 7509                }
 7510
 7511                cx.notify();
 7512            }
 7513        }
 7514
 7515        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7516    }
 7517
 7518    pub fn accept_partial_edit_prediction(
 7519        &mut self,
 7520        _: &AcceptPartialEditPrediction,
 7521        window: &mut Window,
 7522        cx: &mut Context<Self>,
 7523    ) {
 7524        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7525            return;
 7526        };
 7527        if self.selections.count() != 1 {
 7528            return;
 7529        }
 7530
 7531        match &active_edit_prediction.completion {
 7532            EditPrediction::MoveWithin { target, .. } => {
 7533                let target = *target;
 7534                self.change_selections(
 7535                    SelectionEffects::scroll(Autoscroll::newest()),
 7536                    window,
 7537                    cx,
 7538                    |selections| {
 7539                        selections.select_anchor_ranges([target..target]);
 7540                    },
 7541                );
 7542            }
 7543            EditPrediction::MoveOutside { snapshot, target } => {
 7544                if let Some(workspace) = self.workspace() {
 7545                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7546                        .detach_and_log_err(cx);
 7547                }
 7548            }
 7549            EditPrediction::Edit { edits, .. } => {
 7550                self.report_edit_prediction_event(
 7551                    active_edit_prediction.completion_id.clone(),
 7552                    true,
 7553                    cx,
 7554                );
 7555
 7556                // Find an insertion that starts at the cursor position.
 7557                let snapshot = self.buffer.read(cx).snapshot(cx);
 7558                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7559                let insertion = edits.iter().find_map(|(range, text)| {
 7560                    let range = range.to_offset(&snapshot);
 7561                    if range.is_empty() && range.start == cursor_offset {
 7562                        Some(text)
 7563                    } else {
 7564                        None
 7565                    }
 7566                });
 7567
 7568                if let Some(text) = insertion {
 7569                    let mut partial_completion = text
 7570                        .chars()
 7571                        .by_ref()
 7572                        .take_while(|c| c.is_alphabetic())
 7573                        .collect::<String>();
 7574                    if partial_completion.is_empty() {
 7575                        partial_completion = text
 7576                            .chars()
 7577                            .by_ref()
 7578                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7579                            .collect::<String>();
 7580                    }
 7581
 7582                    cx.emit(EditorEvent::InputHandled {
 7583                        utf16_range_to_replace: None,
 7584                        text: partial_completion.clone().into(),
 7585                    });
 7586
 7587                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7588
 7589                    self.refresh_edit_prediction(true, true, window, cx);
 7590                    cx.notify();
 7591                } else {
 7592                    self.accept_edit_prediction(&Default::default(), window, cx);
 7593                }
 7594            }
 7595        }
 7596    }
 7597
 7598    fn discard_edit_prediction(
 7599        &mut self,
 7600        should_report_edit_prediction_event: bool,
 7601        cx: &mut Context<Self>,
 7602    ) -> bool {
 7603        if should_report_edit_prediction_event {
 7604            let completion_id = self
 7605                .active_edit_prediction
 7606                .as_ref()
 7607                .and_then(|active_completion| active_completion.completion_id.clone());
 7608
 7609            self.report_edit_prediction_event(completion_id, false, cx);
 7610        }
 7611
 7612        if let Some(provider) = self.edit_prediction_provider() {
 7613            provider.discard(cx);
 7614        }
 7615
 7616        self.take_active_edit_prediction(cx)
 7617    }
 7618
 7619    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7620        let Some(provider) = self.edit_prediction_provider() else {
 7621            return;
 7622        };
 7623
 7624        let Some((_, buffer, _)) = self
 7625            .buffer
 7626            .read(cx)
 7627            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7628        else {
 7629            return;
 7630        };
 7631
 7632        let extension = buffer
 7633            .read(cx)
 7634            .file()
 7635            .and_then(|file| Some(file.path().extension()?.to_string()));
 7636
 7637        let event_type = match accepted {
 7638            true => "Edit Prediction Accepted",
 7639            false => "Edit Prediction Discarded",
 7640        };
 7641        telemetry::event!(
 7642            event_type,
 7643            provider = provider.name(),
 7644            prediction_id = id,
 7645            suggestion_accepted = accepted,
 7646            file_extension = extension,
 7647        );
 7648    }
 7649
 7650    fn open_editor_at_anchor(
 7651        snapshot: &language::BufferSnapshot,
 7652        target: language::Anchor,
 7653        workspace: &Entity<Workspace>,
 7654        window: &mut Window,
 7655        cx: &mut App,
 7656    ) -> Task<Result<()>> {
 7657        workspace.update(cx, |workspace, cx| {
 7658            let path = snapshot.file().map(|file| file.full_path(cx));
 7659            let Some(path) =
 7660                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7661            else {
 7662                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7663            };
 7664            let target = text::ToPoint::to_point(&target, snapshot);
 7665            let item = workspace.open_path(path, None, true, window, cx);
 7666            window.spawn(cx, async move |cx| {
 7667                let Some(editor) = item.await?.downcast::<Editor>() else {
 7668                    return Ok(());
 7669                };
 7670                editor
 7671                    .update_in(cx, |editor, window, cx| {
 7672                        editor.go_to_singleton_buffer_point(target, window, cx);
 7673                    })
 7674                    .ok();
 7675                anyhow::Ok(())
 7676            })
 7677        })
 7678    }
 7679
 7680    pub fn has_active_edit_prediction(&self) -> bool {
 7681        self.active_edit_prediction.is_some()
 7682    }
 7683
 7684    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7685        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7686            return false;
 7687        };
 7688
 7689        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7690        self.clear_highlights::<EditPredictionHighlight>(cx);
 7691        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7692        true
 7693    }
 7694
 7695    /// Returns true when we're displaying the edit prediction popover below the cursor
 7696    /// like we are not previewing and the LSP autocomplete menu is visible
 7697    /// or we are in `when_holding_modifier` mode.
 7698    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7699        if self.edit_prediction_preview_is_active()
 7700            || !self.show_edit_predictions_in_menu()
 7701            || !self.edit_predictions_enabled()
 7702        {
 7703            return false;
 7704        }
 7705
 7706        if self.has_visible_completions_menu() {
 7707            return true;
 7708        }
 7709
 7710        has_completion && self.edit_prediction_requires_modifier()
 7711    }
 7712
 7713    fn handle_modifiers_changed(
 7714        &mut self,
 7715        modifiers: Modifiers,
 7716        position_map: &PositionMap,
 7717        window: &mut Window,
 7718        cx: &mut Context<Self>,
 7719    ) {
 7720        if self.show_edit_predictions_in_menu() {
 7721            self.update_edit_prediction_preview(&modifiers, window, cx);
 7722        }
 7723
 7724        self.update_selection_mode(&modifiers, position_map, window, cx);
 7725
 7726        let mouse_position = window.mouse_position();
 7727        if !position_map.text_hitbox.is_hovered(window) {
 7728            return;
 7729        }
 7730
 7731        self.update_hovered_link(
 7732            position_map.point_for_position(mouse_position),
 7733            &position_map.snapshot,
 7734            modifiers,
 7735            window,
 7736            cx,
 7737        )
 7738    }
 7739
 7740    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7741        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7742        if invert {
 7743            match multi_cursor_setting {
 7744                MultiCursorModifier::Alt => modifiers.alt,
 7745                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7746            }
 7747        } else {
 7748            match multi_cursor_setting {
 7749                MultiCursorModifier::Alt => modifiers.secondary(),
 7750                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7751            }
 7752        }
 7753    }
 7754
 7755    fn columnar_selection_mode(
 7756        modifiers: &Modifiers,
 7757        cx: &mut Context<Self>,
 7758    ) -> Option<ColumnarMode> {
 7759        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7760            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7761                Some(ColumnarMode::FromMouse)
 7762            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7763                Some(ColumnarMode::FromSelection)
 7764            } else {
 7765                None
 7766            }
 7767        } else {
 7768            None
 7769        }
 7770    }
 7771
 7772    fn update_selection_mode(
 7773        &mut self,
 7774        modifiers: &Modifiers,
 7775        position_map: &PositionMap,
 7776        window: &mut Window,
 7777        cx: &mut Context<Self>,
 7778    ) {
 7779        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7780            return;
 7781        };
 7782        if self.selections.pending_anchor().is_none() {
 7783            return;
 7784        }
 7785
 7786        let mouse_position = window.mouse_position();
 7787        let point_for_position = position_map.point_for_position(mouse_position);
 7788        let position = point_for_position.previous_valid;
 7789
 7790        self.select(
 7791            SelectPhase::BeginColumnar {
 7792                position,
 7793                reset: false,
 7794                mode,
 7795                goal_column: point_for_position.exact_unclipped.column(),
 7796            },
 7797            window,
 7798            cx,
 7799        );
 7800    }
 7801
 7802    fn update_edit_prediction_preview(
 7803        &mut self,
 7804        modifiers: &Modifiers,
 7805        window: &mut Window,
 7806        cx: &mut Context<Self>,
 7807    ) {
 7808        let mut modifiers_held = false;
 7809        if let Some(accept_keystroke) = self
 7810            .accept_edit_prediction_keybind(false, window, cx)
 7811            .keystroke()
 7812        {
 7813            modifiers_held = modifiers_held
 7814                || (accept_keystroke.modifiers() == modifiers
 7815                    && accept_keystroke.modifiers().modified());
 7816        };
 7817        if let Some(accept_partial_keystroke) = self
 7818            .accept_edit_prediction_keybind(true, window, cx)
 7819            .keystroke()
 7820        {
 7821            modifiers_held = modifiers_held
 7822                || (accept_partial_keystroke.modifiers() == modifiers
 7823                    && accept_partial_keystroke.modifiers().modified());
 7824        }
 7825
 7826        if modifiers_held {
 7827            if matches!(
 7828                self.edit_prediction_preview,
 7829                EditPredictionPreview::Inactive { .. }
 7830            ) {
 7831                self.edit_prediction_preview = EditPredictionPreview::Active {
 7832                    previous_scroll_position: None,
 7833                    since: Instant::now(),
 7834                };
 7835
 7836                self.update_visible_edit_prediction(window, cx);
 7837                cx.notify();
 7838            }
 7839        } else if let EditPredictionPreview::Active {
 7840            previous_scroll_position,
 7841            since,
 7842        } = self.edit_prediction_preview
 7843        {
 7844            if let (Some(previous_scroll_position), Some(position_map)) =
 7845                (previous_scroll_position, self.last_position_map.as_ref())
 7846            {
 7847                self.set_scroll_position(
 7848                    previous_scroll_position
 7849                        .scroll_position(&position_map.snapshot.display_snapshot),
 7850                    window,
 7851                    cx,
 7852                );
 7853            }
 7854
 7855            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7856                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7857            };
 7858            self.clear_row_highlights::<EditPredictionPreview>();
 7859            self.update_visible_edit_prediction(window, cx);
 7860            cx.notify();
 7861        }
 7862    }
 7863
 7864    fn update_visible_edit_prediction(
 7865        &mut self,
 7866        _window: &mut Window,
 7867        cx: &mut Context<Self>,
 7868    ) -> Option<()> {
 7869        if DisableAiSettings::get_global(cx).disable_ai {
 7870            return None;
 7871        }
 7872
 7873        if self.ime_transaction.is_some() {
 7874            self.discard_edit_prediction(false, cx);
 7875            return None;
 7876        }
 7877
 7878        let selection = self.selections.newest_anchor();
 7879        let cursor = selection.head();
 7880        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7881        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7882        let excerpt_id = cursor.excerpt_id;
 7883
 7884        let show_in_menu = self.show_edit_predictions_in_menu();
 7885        let completions_menu_has_precedence = !show_in_menu
 7886            && (self.context_menu.borrow().is_some()
 7887                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7888
 7889        if completions_menu_has_precedence
 7890            || !offset_selection.is_empty()
 7891            || self
 7892                .active_edit_prediction
 7893                .as_ref()
 7894                .is_some_and(|completion| {
 7895                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7896                        return false;
 7897                    };
 7898                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7899                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7900                    !invalidation_range.contains(&offset_selection.head())
 7901                })
 7902        {
 7903            self.discard_edit_prediction(false, cx);
 7904            return None;
 7905        }
 7906
 7907        self.take_active_edit_prediction(cx);
 7908        let Some(provider) = self.edit_prediction_provider() else {
 7909            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7910            return None;
 7911        };
 7912
 7913        let (buffer, cursor_buffer_position) =
 7914            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7915
 7916        self.edit_prediction_settings =
 7917            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7918
 7919        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7920
 7921        if self.edit_prediction_indent_conflict {
 7922            let cursor_point = cursor.to_point(&multibuffer);
 7923
 7924            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7925
 7926            if let Some((_, indent)) = indents.iter().next()
 7927                && indent.len == cursor_point.column
 7928            {
 7929                self.edit_prediction_indent_conflict = false;
 7930            }
 7931        }
 7932
 7933        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7934
 7935        let (completion_id, edits, edit_preview) = match edit_prediction {
 7936            edit_prediction::EditPrediction::Local {
 7937                id,
 7938                edits,
 7939                edit_preview,
 7940            } => (id, edits, edit_preview),
 7941            edit_prediction::EditPrediction::Jump {
 7942                id,
 7943                snapshot,
 7944                target,
 7945            } => {
 7946                self.stale_edit_prediction_in_menu = None;
 7947                self.active_edit_prediction = Some(EditPredictionState {
 7948                    inlay_ids: vec![],
 7949                    completion: EditPrediction::MoveOutside { snapshot, target },
 7950                    completion_id: id,
 7951                    invalidation_range: None,
 7952                });
 7953                cx.notify();
 7954                return Some(());
 7955            }
 7956        };
 7957
 7958        let edits = edits
 7959            .into_iter()
 7960            .flat_map(|(range, new_text)| {
 7961                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7962                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7963                Some((start..end, new_text))
 7964            })
 7965            .collect::<Vec<_>>();
 7966        if edits.is_empty() {
 7967            return None;
 7968        }
 7969
 7970        let first_edit_start = edits.first().unwrap().0.start;
 7971        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7972        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7973
 7974        let last_edit_end = edits.last().unwrap().0.end;
 7975        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7976        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7977
 7978        let cursor_row = cursor.to_point(&multibuffer).row;
 7979
 7980        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7981
 7982        let mut inlay_ids = Vec::new();
 7983        let invalidation_row_range;
 7984        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7985            Some(cursor_row..edit_end_row)
 7986        } else if cursor_row > edit_end_row {
 7987            Some(edit_start_row..cursor_row)
 7988        } else {
 7989            None
 7990        };
 7991        let supports_jump = self
 7992            .edit_prediction_provider
 7993            .as_ref()
 7994            .map(|provider| provider.provider.supports_jump_to_edit())
 7995            .unwrap_or(true);
 7996
 7997        let is_move = supports_jump
 7998            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7999        let completion = if is_move {
 8000            invalidation_row_range =
 8001                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8002            let target = first_edit_start;
 8003            EditPrediction::MoveWithin { target, snapshot }
 8004        } else {
 8005            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8006                && !self.edit_predictions_hidden_for_vim_mode;
 8007
 8008            if show_completions_in_buffer {
 8009                if edits
 8010                    .iter()
 8011                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8012                {
 8013                    let mut inlays = Vec::new();
 8014                    for (range, new_text) in &edits {
 8015                        let inlay = Inlay::edit_prediction(
 8016                            post_inc(&mut self.next_inlay_id),
 8017                            range.start,
 8018                            new_text.as_str(),
 8019                        );
 8020                        inlay_ids.push(inlay.id);
 8021                        inlays.push(inlay);
 8022                    }
 8023
 8024                    self.splice_inlays(&[], inlays, cx);
 8025                } else {
 8026                    let background_color = cx.theme().status().deleted_background;
 8027                    self.highlight_text::<EditPredictionHighlight>(
 8028                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8029                        HighlightStyle {
 8030                            background_color: Some(background_color),
 8031                            ..Default::default()
 8032                        },
 8033                        cx,
 8034                    );
 8035                }
 8036            }
 8037
 8038            invalidation_row_range = edit_start_row..edit_end_row;
 8039
 8040            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8041                if provider.show_tab_accept_marker() {
 8042                    EditDisplayMode::TabAccept
 8043                } else {
 8044                    EditDisplayMode::Inline
 8045                }
 8046            } else {
 8047                EditDisplayMode::DiffPopover
 8048            };
 8049
 8050            EditPrediction::Edit {
 8051                edits,
 8052                edit_preview,
 8053                display_mode,
 8054                snapshot,
 8055            }
 8056        };
 8057
 8058        let invalidation_range = multibuffer
 8059            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8060            ..multibuffer.anchor_after(Point::new(
 8061                invalidation_row_range.end,
 8062                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8063            ));
 8064
 8065        self.stale_edit_prediction_in_menu = None;
 8066        self.active_edit_prediction = Some(EditPredictionState {
 8067            inlay_ids,
 8068            completion,
 8069            completion_id,
 8070            invalidation_range: Some(invalidation_range),
 8071        });
 8072
 8073        cx.notify();
 8074
 8075        Some(())
 8076    }
 8077
 8078    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8079        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8080    }
 8081
 8082    fn clear_tasks(&mut self) {
 8083        self.tasks.clear()
 8084    }
 8085
 8086    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8087        if self.tasks.insert(key, value).is_some() {
 8088            // This case should hopefully be rare, but just in case...
 8089            log::error!(
 8090                "multiple different run targets found on a single line, only the last target will be rendered"
 8091            )
 8092        }
 8093    }
 8094
 8095    /// Get all display points of breakpoints that will be rendered within editor
 8096    ///
 8097    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8098    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8099    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8100    fn active_breakpoints(
 8101        &self,
 8102        range: Range<DisplayRow>,
 8103        window: &mut Window,
 8104        cx: &mut Context<Self>,
 8105    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8106        let mut breakpoint_display_points = HashMap::default();
 8107
 8108        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8109            return breakpoint_display_points;
 8110        };
 8111
 8112        let snapshot = self.snapshot(window, cx);
 8113
 8114        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8115        let Some(project) = self.project() else {
 8116            return breakpoint_display_points;
 8117        };
 8118
 8119        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8120            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8121
 8122        for (buffer_snapshot, range, excerpt_id) in
 8123            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8124        {
 8125            let Some(buffer) = project
 8126                .read(cx)
 8127                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8128            else {
 8129                continue;
 8130            };
 8131            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8132                &buffer,
 8133                Some(
 8134                    buffer_snapshot.anchor_before(range.start)
 8135                        ..buffer_snapshot.anchor_after(range.end),
 8136                ),
 8137                buffer_snapshot,
 8138                cx,
 8139            );
 8140            for (breakpoint, state) in breakpoints {
 8141                let multi_buffer_anchor =
 8142                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8143                let position = multi_buffer_anchor
 8144                    .to_point(multi_buffer_snapshot)
 8145                    .to_display_point(&snapshot);
 8146
 8147                breakpoint_display_points.insert(
 8148                    position.row(),
 8149                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8150                );
 8151            }
 8152        }
 8153
 8154        breakpoint_display_points
 8155    }
 8156
 8157    fn breakpoint_context_menu(
 8158        &self,
 8159        anchor: Anchor,
 8160        window: &mut Window,
 8161        cx: &mut Context<Self>,
 8162    ) -> Entity<ui::ContextMenu> {
 8163        let weak_editor = cx.weak_entity();
 8164        let focus_handle = self.focus_handle(cx);
 8165
 8166        let row = self
 8167            .buffer
 8168            .read(cx)
 8169            .snapshot(cx)
 8170            .summary_for_anchor::<Point>(&anchor)
 8171            .row;
 8172
 8173        let breakpoint = self
 8174            .breakpoint_at_row(row, window, cx)
 8175            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8176
 8177        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8178            "Edit Log Breakpoint"
 8179        } else {
 8180            "Set Log Breakpoint"
 8181        };
 8182
 8183        let condition_breakpoint_msg = if breakpoint
 8184            .as_ref()
 8185            .is_some_and(|bp| bp.1.condition.is_some())
 8186        {
 8187            "Edit Condition Breakpoint"
 8188        } else {
 8189            "Set Condition Breakpoint"
 8190        };
 8191
 8192        let hit_condition_breakpoint_msg = if breakpoint
 8193            .as_ref()
 8194            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8195        {
 8196            "Edit Hit Condition Breakpoint"
 8197        } else {
 8198            "Set Hit Condition Breakpoint"
 8199        };
 8200
 8201        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8202            "Unset Breakpoint"
 8203        } else {
 8204            "Set Breakpoint"
 8205        };
 8206
 8207        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8208
 8209        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8210            BreakpointState::Enabled => Some("Disable"),
 8211            BreakpointState::Disabled => Some("Enable"),
 8212        });
 8213
 8214        let (anchor, breakpoint) =
 8215            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8216
 8217        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8218            menu.on_blur_subscription(Subscription::new(|| {}))
 8219                .context(focus_handle)
 8220                .when(run_to_cursor, |this| {
 8221                    let weak_editor = weak_editor.clone();
 8222                    this.entry("Run to cursor", None, move |window, cx| {
 8223                        weak_editor
 8224                            .update(cx, |editor, cx| {
 8225                                editor.change_selections(
 8226                                    SelectionEffects::no_scroll(),
 8227                                    window,
 8228                                    cx,
 8229                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8230                                );
 8231                            })
 8232                            .ok();
 8233
 8234                        window.dispatch_action(Box::new(RunToCursor), cx);
 8235                    })
 8236                    .separator()
 8237                })
 8238                .when_some(toggle_state_msg, |this, msg| {
 8239                    this.entry(msg, None, {
 8240                        let weak_editor = weak_editor.clone();
 8241                        let breakpoint = breakpoint.clone();
 8242                        move |_window, cx| {
 8243                            weak_editor
 8244                                .update(cx, |this, cx| {
 8245                                    this.edit_breakpoint_at_anchor(
 8246                                        anchor,
 8247                                        breakpoint.as_ref().clone(),
 8248                                        BreakpointEditAction::InvertState,
 8249                                        cx,
 8250                                    );
 8251                                })
 8252                                .log_err();
 8253                        }
 8254                    })
 8255                })
 8256                .entry(set_breakpoint_msg, None, {
 8257                    let weak_editor = weak_editor.clone();
 8258                    let breakpoint = breakpoint.clone();
 8259                    move |_window, cx| {
 8260                        weak_editor
 8261                            .update(cx, |this, cx| {
 8262                                this.edit_breakpoint_at_anchor(
 8263                                    anchor,
 8264                                    breakpoint.as_ref().clone(),
 8265                                    BreakpointEditAction::Toggle,
 8266                                    cx,
 8267                                );
 8268                            })
 8269                            .log_err();
 8270                    }
 8271                })
 8272                .entry(log_breakpoint_msg, None, {
 8273                    let breakpoint = breakpoint.clone();
 8274                    let weak_editor = weak_editor.clone();
 8275                    move |window, cx| {
 8276                        weak_editor
 8277                            .update(cx, |this, cx| {
 8278                                this.add_edit_breakpoint_block(
 8279                                    anchor,
 8280                                    breakpoint.as_ref(),
 8281                                    BreakpointPromptEditAction::Log,
 8282                                    window,
 8283                                    cx,
 8284                                );
 8285                            })
 8286                            .log_err();
 8287                    }
 8288                })
 8289                .entry(condition_breakpoint_msg, None, {
 8290                    let breakpoint = breakpoint.clone();
 8291                    let weak_editor = weak_editor.clone();
 8292                    move |window, cx| {
 8293                        weak_editor
 8294                            .update(cx, |this, cx| {
 8295                                this.add_edit_breakpoint_block(
 8296                                    anchor,
 8297                                    breakpoint.as_ref(),
 8298                                    BreakpointPromptEditAction::Condition,
 8299                                    window,
 8300                                    cx,
 8301                                );
 8302                            })
 8303                            .log_err();
 8304                    }
 8305                })
 8306                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8307                    weak_editor
 8308                        .update(cx, |this, cx| {
 8309                            this.add_edit_breakpoint_block(
 8310                                anchor,
 8311                                breakpoint.as_ref(),
 8312                                BreakpointPromptEditAction::HitCondition,
 8313                                window,
 8314                                cx,
 8315                            );
 8316                        })
 8317                        .log_err();
 8318                })
 8319        })
 8320    }
 8321
 8322    fn render_breakpoint(
 8323        &self,
 8324        position: Anchor,
 8325        row: DisplayRow,
 8326        breakpoint: &Breakpoint,
 8327        state: Option<BreakpointSessionState>,
 8328        cx: &mut Context<Self>,
 8329    ) -> IconButton {
 8330        let is_rejected = state.is_some_and(|s| !s.verified);
 8331        // Is it a breakpoint that shows up when hovering over gutter?
 8332        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8333            (false, false),
 8334            |PhantomBreakpointIndicator {
 8335                 is_active,
 8336                 display_row,
 8337                 collides_with_existing_breakpoint,
 8338             }| {
 8339                (
 8340                    is_active && display_row == row,
 8341                    collides_with_existing_breakpoint,
 8342                )
 8343            },
 8344        );
 8345
 8346        let (color, icon) = {
 8347            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8348                (false, false) => ui::IconName::DebugBreakpoint,
 8349                (true, false) => ui::IconName::DebugLogBreakpoint,
 8350                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8351                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8352            };
 8353
 8354            let color = if is_phantom {
 8355                Color::Hint
 8356            } else if is_rejected {
 8357                Color::Disabled
 8358            } else {
 8359                Color::Debugger
 8360            };
 8361
 8362            (color, icon)
 8363        };
 8364
 8365        let breakpoint = Arc::from(breakpoint.clone());
 8366
 8367        let alt_as_text = gpui::Keystroke {
 8368            modifiers: Modifiers::secondary_key(),
 8369            ..Default::default()
 8370        };
 8371        let primary_action_text = if breakpoint.is_disabled() {
 8372            "Enable breakpoint"
 8373        } else if is_phantom && !collides_with_existing {
 8374            "Set breakpoint"
 8375        } else {
 8376            "Unset breakpoint"
 8377        };
 8378        let focus_handle = self.focus_handle.clone();
 8379
 8380        let meta = if is_rejected {
 8381            SharedString::from("No executable code is associated with this line.")
 8382        } else if collides_with_existing && !breakpoint.is_disabled() {
 8383            SharedString::from(format!(
 8384                "{alt_as_text}-click to disable,\nright-click for more options."
 8385            ))
 8386        } else {
 8387            SharedString::from("Right-click for more options.")
 8388        };
 8389        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8390            .icon_size(IconSize::XSmall)
 8391            .size(ui::ButtonSize::None)
 8392            .when(is_rejected, |this| {
 8393                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8394            })
 8395            .icon_color(color)
 8396            .style(ButtonStyle::Transparent)
 8397            .on_click(cx.listener({
 8398                move |editor, event: &ClickEvent, window, cx| {
 8399                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8400                        BreakpointEditAction::InvertState
 8401                    } else {
 8402                        BreakpointEditAction::Toggle
 8403                    };
 8404
 8405                    window.focus(&editor.focus_handle(cx));
 8406                    editor.edit_breakpoint_at_anchor(
 8407                        position,
 8408                        breakpoint.as_ref().clone(),
 8409                        edit_action,
 8410                        cx,
 8411                    );
 8412                }
 8413            }))
 8414            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8415                editor.set_breakpoint_context_menu(
 8416                    row,
 8417                    Some(position),
 8418                    event.position(),
 8419                    window,
 8420                    cx,
 8421                );
 8422            }))
 8423            .tooltip(move |window, cx| {
 8424                Tooltip::with_meta_in(
 8425                    primary_action_text,
 8426                    Some(&ToggleBreakpoint),
 8427                    meta.clone(),
 8428                    &focus_handle,
 8429                    window,
 8430                    cx,
 8431                )
 8432            })
 8433    }
 8434
 8435    fn build_tasks_context(
 8436        project: &Entity<Project>,
 8437        buffer: &Entity<Buffer>,
 8438        buffer_row: u32,
 8439        tasks: &Arc<RunnableTasks>,
 8440        cx: &mut Context<Self>,
 8441    ) -> Task<Option<task::TaskContext>> {
 8442        let position = Point::new(buffer_row, tasks.column);
 8443        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8444        let location = Location {
 8445            buffer: buffer.clone(),
 8446            range: range_start..range_start,
 8447        };
 8448        // Fill in the environmental variables from the tree-sitter captures
 8449        let mut captured_task_variables = TaskVariables::default();
 8450        for (capture_name, value) in tasks.extra_variables.clone() {
 8451            captured_task_variables.insert(
 8452                task::VariableName::Custom(capture_name.into()),
 8453                value.clone(),
 8454            );
 8455        }
 8456        project.update(cx, |project, cx| {
 8457            project.task_store().update(cx, |task_store, cx| {
 8458                task_store.task_context_for_location(captured_task_variables, location, cx)
 8459            })
 8460        })
 8461    }
 8462
 8463    pub fn spawn_nearest_task(
 8464        &mut self,
 8465        action: &SpawnNearestTask,
 8466        window: &mut Window,
 8467        cx: &mut Context<Self>,
 8468    ) {
 8469        let Some((workspace, _)) = self.workspace.clone() else {
 8470            return;
 8471        };
 8472        let Some(project) = self.project.clone() else {
 8473            return;
 8474        };
 8475
 8476        // Try to find a closest, enclosing node using tree-sitter that has a task
 8477        let Some((buffer, buffer_row, tasks)) = self
 8478            .find_enclosing_node_task(cx)
 8479            // Or find the task that's closest in row-distance.
 8480            .or_else(|| self.find_closest_task(cx))
 8481        else {
 8482            return;
 8483        };
 8484
 8485        let reveal_strategy = action.reveal;
 8486        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8487        cx.spawn_in(window, async move |_, cx| {
 8488            let context = task_context.await?;
 8489            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8490
 8491            let resolved = &mut resolved_task.resolved;
 8492            resolved.reveal = reveal_strategy;
 8493
 8494            workspace
 8495                .update_in(cx, |workspace, window, cx| {
 8496                    workspace.schedule_resolved_task(
 8497                        task_source_kind,
 8498                        resolved_task,
 8499                        false,
 8500                        window,
 8501                        cx,
 8502                    );
 8503                })
 8504                .ok()
 8505        })
 8506        .detach();
 8507    }
 8508
 8509    fn find_closest_task(
 8510        &mut self,
 8511        cx: &mut Context<Self>,
 8512    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8513        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8514
 8515        let ((buffer_id, row), tasks) = self
 8516            .tasks
 8517            .iter()
 8518            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8519
 8520        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8521        let tasks = Arc::new(tasks.to_owned());
 8522        Some((buffer, *row, tasks))
 8523    }
 8524
 8525    fn find_enclosing_node_task(
 8526        &mut self,
 8527        cx: &mut Context<Self>,
 8528    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8529        let snapshot = self.buffer.read(cx).snapshot(cx);
 8530        let offset = self.selections.newest::<usize>(cx).head();
 8531        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8532        let buffer_id = excerpt.buffer().remote_id();
 8533
 8534        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8535        let mut cursor = layer.node().walk();
 8536
 8537        while cursor.goto_first_child_for_byte(offset).is_some() {
 8538            if cursor.node().end_byte() == offset {
 8539                cursor.goto_next_sibling();
 8540            }
 8541        }
 8542
 8543        // Ascend to the smallest ancestor that contains the range and has a task.
 8544        loop {
 8545            let node = cursor.node();
 8546            let node_range = node.byte_range();
 8547            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8548
 8549            // Check if this node contains our offset
 8550            if node_range.start <= offset && node_range.end >= offset {
 8551                // If it contains offset, check for task
 8552                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8553                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8554                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8555                }
 8556            }
 8557
 8558            if !cursor.goto_parent() {
 8559                break;
 8560            }
 8561        }
 8562        None
 8563    }
 8564
 8565    fn render_run_indicator(
 8566        &self,
 8567        _style: &EditorStyle,
 8568        is_active: bool,
 8569        row: DisplayRow,
 8570        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8571        cx: &mut Context<Self>,
 8572    ) -> IconButton {
 8573        let color = Color::Muted;
 8574        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8575
 8576        IconButton::new(
 8577            ("run_indicator", row.0 as usize),
 8578            ui::IconName::PlayOutlined,
 8579        )
 8580        .shape(ui::IconButtonShape::Square)
 8581        .icon_size(IconSize::XSmall)
 8582        .icon_color(color)
 8583        .toggle_state(is_active)
 8584        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8585            let quick_launch = match e {
 8586                ClickEvent::Keyboard(_) => true,
 8587                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8588            };
 8589
 8590            window.focus(&editor.focus_handle(cx));
 8591            editor.toggle_code_actions(
 8592                &ToggleCodeActions {
 8593                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8594                    quick_launch,
 8595                },
 8596                window,
 8597                cx,
 8598            );
 8599        }))
 8600        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8601            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8602        }))
 8603    }
 8604
 8605    pub fn context_menu_visible(&self) -> bool {
 8606        !self.edit_prediction_preview_is_active()
 8607            && self
 8608                .context_menu
 8609                .borrow()
 8610                .as_ref()
 8611                .is_some_and(|menu| menu.visible())
 8612    }
 8613
 8614    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8615        self.context_menu
 8616            .borrow()
 8617            .as_ref()
 8618            .map(|menu| menu.origin())
 8619    }
 8620
 8621    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8622        self.context_menu_options = Some(options);
 8623    }
 8624
 8625    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8626    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8627
 8628    fn render_edit_prediction_popover(
 8629        &mut self,
 8630        text_bounds: &Bounds<Pixels>,
 8631        content_origin: gpui::Point<Pixels>,
 8632        right_margin: Pixels,
 8633        editor_snapshot: &EditorSnapshot,
 8634        visible_row_range: Range<DisplayRow>,
 8635        scroll_top: ScrollOffset,
 8636        scroll_bottom: ScrollOffset,
 8637        line_layouts: &[LineWithInvisibles],
 8638        line_height: Pixels,
 8639        scroll_position: gpui::Point<ScrollOffset>,
 8640        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8641        newest_selection_head: Option<DisplayPoint>,
 8642        editor_width: Pixels,
 8643        style: &EditorStyle,
 8644        window: &mut Window,
 8645        cx: &mut App,
 8646    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8647        if self.mode().is_minimap() {
 8648            return None;
 8649        }
 8650        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8651
 8652        if self.edit_prediction_visible_in_cursor_popover(true) {
 8653            return None;
 8654        }
 8655
 8656        match &active_edit_prediction.completion {
 8657            EditPrediction::MoveWithin { target, .. } => {
 8658                let target_display_point = target.to_display_point(editor_snapshot);
 8659
 8660                if self.edit_prediction_requires_modifier() {
 8661                    if !self.edit_prediction_preview_is_active() {
 8662                        return None;
 8663                    }
 8664
 8665                    self.render_edit_prediction_modifier_jump_popover(
 8666                        text_bounds,
 8667                        content_origin,
 8668                        visible_row_range,
 8669                        line_layouts,
 8670                        line_height,
 8671                        scroll_pixel_position,
 8672                        newest_selection_head,
 8673                        target_display_point,
 8674                        window,
 8675                        cx,
 8676                    )
 8677                } else {
 8678                    self.render_edit_prediction_eager_jump_popover(
 8679                        text_bounds,
 8680                        content_origin,
 8681                        editor_snapshot,
 8682                        visible_row_range,
 8683                        scroll_top,
 8684                        scroll_bottom,
 8685                        line_height,
 8686                        scroll_pixel_position,
 8687                        target_display_point,
 8688                        editor_width,
 8689                        window,
 8690                        cx,
 8691                    )
 8692                }
 8693            }
 8694            EditPrediction::Edit {
 8695                display_mode: EditDisplayMode::Inline,
 8696                ..
 8697            } => None,
 8698            EditPrediction::Edit {
 8699                display_mode: EditDisplayMode::TabAccept,
 8700                edits,
 8701                ..
 8702            } => {
 8703                let range = &edits.first()?.0;
 8704                let target_display_point = range.end.to_display_point(editor_snapshot);
 8705
 8706                self.render_edit_prediction_end_of_line_popover(
 8707                    "Accept",
 8708                    editor_snapshot,
 8709                    visible_row_range,
 8710                    target_display_point,
 8711                    line_height,
 8712                    scroll_pixel_position,
 8713                    content_origin,
 8714                    editor_width,
 8715                    window,
 8716                    cx,
 8717                )
 8718            }
 8719            EditPrediction::Edit {
 8720                edits,
 8721                edit_preview,
 8722                display_mode: EditDisplayMode::DiffPopover,
 8723                snapshot,
 8724            } => self.render_edit_prediction_diff_popover(
 8725                text_bounds,
 8726                content_origin,
 8727                right_margin,
 8728                editor_snapshot,
 8729                visible_row_range,
 8730                line_layouts,
 8731                line_height,
 8732                scroll_position,
 8733                scroll_pixel_position,
 8734                newest_selection_head,
 8735                editor_width,
 8736                style,
 8737                edits,
 8738                edit_preview,
 8739                snapshot,
 8740                window,
 8741                cx,
 8742            ),
 8743            EditPrediction::MoveOutside { snapshot, .. } => {
 8744                let file_name = snapshot
 8745                    .file()
 8746                    .map(|file| file.file_name(cx))
 8747                    .unwrap_or("untitled");
 8748                let mut element = self
 8749                    .render_edit_prediction_line_popover(
 8750                        format!("Jump to {file_name}"),
 8751                        Some(IconName::ZedPredict),
 8752                        window,
 8753                        cx,
 8754                    )
 8755                    .into_any();
 8756
 8757                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8758                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8759                let origin_y = text_bounds.size.height - size.height - px(30.);
 8760                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8761                element.prepaint_at(origin, window, cx);
 8762
 8763                Some((element, origin))
 8764            }
 8765        }
 8766    }
 8767
 8768    fn render_edit_prediction_modifier_jump_popover(
 8769        &mut self,
 8770        text_bounds: &Bounds<Pixels>,
 8771        content_origin: gpui::Point<Pixels>,
 8772        visible_row_range: Range<DisplayRow>,
 8773        line_layouts: &[LineWithInvisibles],
 8774        line_height: Pixels,
 8775        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8776        newest_selection_head: Option<DisplayPoint>,
 8777        target_display_point: DisplayPoint,
 8778        window: &mut Window,
 8779        cx: &mut App,
 8780    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8781        let scrolled_content_origin =
 8782            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8783
 8784        const SCROLL_PADDING_Y: Pixels = px(12.);
 8785
 8786        if target_display_point.row() < visible_row_range.start {
 8787            return self.render_edit_prediction_scroll_popover(
 8788                |_| SCROLL_PADDING_Y,
 8789                IconName::ArrowUp,
 8790                visible_row_range,
 8791                line_layouts,
 8792                newest_selection_head,
 8793                scrolled_content_origin,
 8794                window,
 8795                cx,
 8796            );
 8797        } else if target_display_point.row() >= visible_row_range.end {
 8798            return self.render_edit_prediction_scroll_popover(
 8799                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8800                IconName::ArrowDown,
 8801                visible_row_range,
 8802                line_layouts,
 8803                newest_selection_head,
 8804                scrolled_content_origin,
 8805                window,
 8806                cx,
 8807            );
 8808        }
 8809
 8810        const POLE_WIDTH: Pixels = px(2.);
 8811
 8812        let line_layout =
 8813            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8814        let target_column = target_display_point.column() as usize;
 8815
 8816        let target_x = line_layout.x_for_index(target_column);
 8817        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8818            - scroll_pixel_position.y;
 8819
 8820        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8821
 8822        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8823        border_color.l += 0.001;
 8824
 8825        let mut element = v_flex()
 8826            .items_end()
 8827            .when(flag_on_right, |el| el.items_start())
 8828            .child(if flag_on_right {
 8829                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8830                    .rounded_bl(px(0.))
 8831                    .rounded_tl(px(0.))
 8832                    .border_l_2()
 8833                    .border_color(border_color)
 8834            } else {
 8835                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8836                    .rounded_br(px(0.))
 8837                    .rounded_tr(px(0.))
 8838                    .border_r_2()
 8839                    .border_color(border_color)
 8840            })
 8841            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8842            .into_any();
 8843
 8844        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8845
 8846        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8847            - point(
 8848                if flag_on_right {
 8849                    POLE_WIDTH
 8850                } else {
 8851                    size.width - POLE_WIDTH
 8852                },
 8853                size.height - line_height,
 8854            );
 8855
 8856        origin.x = origin.x.max(content_origin.x);
 8857
 8858        element.prepaint_at(origin, window, cx);
 8859
 8860        Some((element, origin))
 8861    }
 8862
 8863    fn render_edit_prediction_scroll_popover(
 8864        &mut self,
 8865        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8866        scroll_icon: IconName,
 8867        visible_row_range: Range<DisplayRow>,
 8868        line_layouts: &[LineWithInvisibles],
 8869        newest_selection_head: Option<DisplayPoint>,
 8870        scrolled_content_origin: gpui::Point<Pixels>,
 8871        window: &mut Window,
 8872        cx: &mut App,
 8873    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8874        let mut element = self
 8875            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8876            .into_any();
 8877
 8878        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8879
 8880        let cursor = newest_selection_head?;
 8881        let cursor_row_layout =
 8882            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8883        let cursor_column = cursor.column() as usize;
 8884
 8885        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8886
 8887        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8888
 8889        element.prepaint_at(origin, window, cx);
 8890        Some((element, origin))
 8891    }
 8892
 8893    fn render_edit_prediction_eager_jump_popover(
 8894        &mut self,
 8895        text_bounds: &Bounds<Pixels>,
 8896        content_origin: gpui::Point<Pixels>,
 8897        editor_snapshot: &EditorSnapshot,
 8898        visible_row_range: Range<DisplayRow>,
 8899        scroll_top: ScrollOffset,
 8900        scroll_bottom: ScrollOffset,
 8901        line_height: Pixels,
 8902        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8903        target_display_point: DisplayPoint,
 8904        editor_width: Pixels,
 8905        window: &mut Window,
 8906        cx: &mut App,
 8907    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8908        if target_display_point.row().as_f64() < scroll_top {
 8909            let mut element = self
 8910                .render_edit_prediction_line_popover(
 8911                    "Jump to Edit",
 8912                    Some(IconName::ArrowUp),
 8913                    window,
 8914                    cx,
 8915                )
 8916                .into_any();
 8917
 8918            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8919            let offset = point(
 8920                (text_bounds.size.width - size.width) / 2.,
 8921                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8922            );
 8923
 8924            let origin = text_bounds.origin + offset;
 8925            element.prepaint_at(origin, window, cx);
 8926            Some((element, origin))
 8927        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8928            let mut element = self
 8929                .render_edit_prediction_line_popover(
 8930                    "Jump to Edit",
 8931                    Some(IconName::ArrowDown),
 8932                    window,
 8933                    cx,
 8934                )
 8935                .into_any();
 8936
 8937            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8938            let offset = point(
 8939                (text_bounds.size.width - size.width) / 2.,
 8940                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8941            );
 8942
 8943            let origin = text_bounds.origin + offset;
 8944            element.prepaint_at(origin, window, cx);
 8945            Some((element, origin))
 8946        } else {
 8947            self.render_edit_prediction_end_of_line_popover(
 8948                "Jump to Edit",
 8949                editor_snapshot,
 8950                visible_row_range,
 8951                target_display_point,
 8952                line_height,
 8953                scroll_pixel_position,
 8954                content_origin,
 8955                editor_width,
 8956                window,
 8957                cx,
 8958            )
 8959        }
 8960    }
 8961
 8962    fn render_edit_prediction_end_of_line_popover(
 8963        self: &mut Editor,
 8964        label: &'static str,
 8965        editor_snapshot: &EditorSnapshot,
 8966        visible_row_range: Range<DisplayRow>,
 8967        target_display_point: DisplayPoint,
 8968        line_height: Pixels,
 8969        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8970        content_origin: gpui::Point<Pixels>,
 8971        editor_width: Pixels,
 8972        window: &mut Window,
 8973        cx: &mut App,
 8974    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8975        let target_line_end = DisplayPoint::new(
 8976            target_display_point.row(),
 8977            editor_snapshot.line_len(target_display_point.row()),
 8978        );
 8979
 8980        let mut element = self
 8981            .render_edit_prediction_line_popover(label, None, window, cx)
 8982            .into_any();
 8983
 8984        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8985
 8986        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8987
 8988        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8989        let mut origin = start_point
 8990            + line_origin
 8991            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8992        origin.x = origin.x.max(content_origin.x);
 8993
 8994        let max_x = content_origin.x + editor_width - size.width;
 8995
 8996        if origin.x > max_x {
 8997            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8998
 8999            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9000                origin.y += offset;
 9001                IconName::ArrowUp
 9002            } else {
 9003                origin.y -= offset;
 9004                IconName::ArrowDown
 9005            };
 9006
 9007            element = self
 9008                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9009                .into_any();
 9010
 9011            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9012
 9013            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9014        }
 9015
 9016        element.prepaint_at(origin, window, cx);
 9017        Some((element, origin))
 9018    }
 9019
 9020    fn render_edit_prediction_diff_popover(
 9021        self: &Editor,
 9022        text_bounds: &Bounds<Pixels>,
 9023        content_origin: gpui::Point<Pixels>,
 9024        right_margin: Pixels,
 9025        editor_snapshot: &EditorSnapshot,
 9026        visible_row_range: Range<DisplayRow>,
 9027        line_layouts: &[LineWithInvisibles],
 9028        line_height: Pixels,
 9029        scroll_position: gpui::Point<ScrollOffset>,
 9030        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9031        newest_selection_head: Option<DisplayPoint>,
 9032        editor_width: Pixels,
 9033        style: &EditorStyle,
 9034        edits: &Vec<(Range<Anchor>, String)>,
 9035        edit_preview: &Option<language::EditPreview>,
 9036        snapshot: &language::BufferSnapshot,
 9037        window: &mut Window,
 9038        cx: &mut App,
 9039    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9040        let edit_start = edits
 9041            .first()
 9042            .unwrap()
 9043            .0
 9044            .start
 9045            .to_display_point(editor_snapshot);
 9046        let edit_end = edits
 9047            .last()
 9048            .unwrap()
 9049            .0
 9050            .end
 9051            .to_display_point(editor_snapshot);
 9052
 9053        let is_visible = visible_row_range.contains(&edit_start.row())
 9054            || visible_row_range.contains(&edit_end.row());
 9055        if !is_visible {
 9056            return None;
 9057        }
 9058
 9059        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9060            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9061        } else {
 9062            // Fallback for providers without edit_preview
 9063            crate::edit_prediction_fallback_text(edits, cx)
 9064        };
 9065
 9066        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9067        let line_count = highlighted_edits.text.lines().count();
 9068
 9069        const BORDER_WIDTH: Pixels = px(1.);
 9070
 9071        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9072        let has_keybind = keybind.is_some();
 9073
 9074        let mut element = h_flex()
 9075            .items_start()
 9076            .child(
 9077                h_flex()
 9078                    .bg(cx.theme().colors().editor_background)
 9079                    .border(BORDER_WIDTH)
 9080                    .shadow_xs()
 9081                    .border_color(cx.theme().colors().border)
 9082                    .rounded_l_lg()
 9083                    .when(line_count > 1, |el| el.rounded_br_lg())
 9084                    .pr_1()
 9085                    .child(styled_text),
 9086            )
 9087            .child(
 9088                h_flex()
 9089                    .h(line_height + BORDER_WIDTH * 2.)
 9090                    .px_1p5()
 9091                    .gap_1()
 9092                    // Workaround: For some reason, there's a gap if we don't do this
 9093                    .ml(-BORDER_WIDTH)
 9094                    .shadow(vec![gpui::BoxShadow {
 9095                        color: gpui::black().opacity(0.05),
 9096                        offset: point(px(1.), px(1.)),
 9097                        blur_radius: px(2.),
 9098                        spread_radius: px(0.),
 9099                    }])
 9100                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9101                    .border(BORDER_WIDTH)
 9102                    .border_color(cx.theme().colors().border)
 9103                    .rounded_r_lg()
 9104                    .id("edit_prediction_diff_popover_keybind")
 9105                    .when(!has_keybind, |el| {
 9106                        let status_colors = cx.theme().status();
 9107
 9108                        el.bg(status_colors.error_background)
 9109                            .border_color(status_colors.error.opacity(0.6))
 9110                            .child(Icon::new(IconName::Info).color(Color::Error))
 9111                            .cursor_default()
 9112                            .hoverable_tooltip(move |_window, cx| {
 9113                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9114                            })
 9115                    })
 9116                    .children(keybind),
 9117            )
 9118            .into_any();
 9119
 9120        let longest_row =
 9121            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9122        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9123            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9124        } else {
 9125            layout_line(
 9126                longest_row,
 9127                editor_snapshot,
 9128                style,
 9129                editor_width,
 9130                |_| false,
 9131                window,
 9132                cx,
 9133            )
 9134            .width
 9135        };
 9136
 9137        let viewport_bounds =
 9138            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9139                right: -right_margin,
 9140                ..Default::default()
 9141            });
 9142
 9143        let x_after_longest = Pixels::from(
 9144            ScrollPixelOffset::from(
 9145                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9146            ) - scroll_pixel_position.x,
 9147        );
 9148
 9149        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9150
 9151        // Fully visible if it can be displayed within the window (allow overlapping other
 9152        // panes). However, this is only allowed if the popover starts within text_bounds.
 9153        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9154            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9155
 9156        let mut origin = if can_position_to_the_right {
 9157            point(
 9158                x_after_longest,
 9159                text_bounds.origin.y
 9160                    + Pixels::from(
 9161                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9162                            - scroll_pixel_position.y,
 9163                    ),
 9164            )
 9165        } else {
 9166            let cursor_row = newest_selection_head.map(|head| head.row());
 9167            let above_edit = edit_start
 9168                .row()
 9169                .0
 9170                .checked_sub(line_count as u32)
 9171                .map(DisplayRow);
 9172            let below_edit = Some(edit_end.row() + 1);
 9173            let above_cursor =
 9174                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9175            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9176
 9177            // Place the edit popover adjacent to the edit if there is a location
 9178            // available that is onscreen and does not obscure the cursor. Otherwise,
 9179            // place it adjacent to the cursor.
 9180            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9181                .into_iter()
 9182                .flatten()
 9183                .find(|&start_row| {
 9184                    let end_row = start_row + line_count as u32;
 9185                    visible_row_range.contains(&start_row)
 9186                        && visible_row_range.contains(&end_row)
 9187                        && cursor_row
 9188                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9189                })?;
 9190
 9191            content_origin
 9192                + point(
 9193                    Pixels::from(-scroll_pixel_position.x),
 9194                    Pixels::from(
 9195                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9196                    ),
 9197                )
 9198        };
 9199
 9200        origin.x -= BORDER_WIDTH;
 9201
 9202        window.defer_draw(element, origin, 1);
 9203
 9204        // Do not return an element, since it will already be drawn due to defer_draw.
 9205        None
 9206    }
 9207
 9208    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9209        px(30.)
 9210    }
 9211
 9212    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9213        if self.read_only(cx) {
 9214            cx.theme().players().read_only()
 9215        } else {
 9216            self.style.as_ref().unwrap().local_player
 9217        }
 9218    }
 9219
 9220    fn render_edit_prediction_accept_keybind(
 9221        &self,
 9222        window: &mut Window,
 9223        cx: &App,
 9224    ) -> Option<AnyElement> {
 9225        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9226        let accept_keystroke = accept_binding.keystroke()?;
 9227
 9228        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9229
 9230        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9231            Color::Accent
 9232        } else {
 9233            Color::Muted
 9234        };
 9235
 9236        h_flex()
 9237            .px_0p5()
 9238            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9239            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9240            .text_size(TextSize::XSmall.rems(cx))
 9241            .child(h_flex().children(ui::render_modifiers(
 9242                accept_keystroke.modifiers(),
 9243                PlatformStyle::platform(),
 9244                Some(modifiers_color),
 9245                Some(IconSize::XSmall.rems().into()),
 9246                true,
 9247            )))
 9248            .when(is_platform_style_mac, |parent| {
 9249                parent.child(accept_keystroke.key().to_string())
 9250            })
 9251            .when(!is_platform_style_mac, |parent| {
 9252                parent.child(
 9253                    Key::new(
 9254                        util::capitalize(accept_keystroke.key()),
 9255                        Some(Color::Default),
 9256                    )
 9257                    .size(Some(IconSize::XSmall.rems().into())),
 9258                )
 9259            })
 9260            .into_any()
 9261            .into()
 9262    }
 9263
 9264    fn render_edit_prediction_line_popover(
 9265        &self,
 9266        label: impl Into<SharedString>,
 9267        icon: Option<IconName>,
 9268        window: &mut Window,
 9269        cx: &App,
 9270    ) -> Stateful<Div> {
 9271        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9272
 9273        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9274        let has_keybind = keybind.is_some();
 9275
 9276        h_flex()
 9277            .id("ep-line-popover")
 9278            .py_0p5()
 9279            .pl_1()
 9280            .pr(padding_right)
 9281            .gap_1()
 9282            .rounded_md()
 9283            .border_1()
 9284            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9285            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9286            .shadow_xs()
 9287            .when(!has_keybind, |el| {
 9288                let status_colors = cx.theme().status();
 9289
 9290                el.bg(status_colors.error_background)
 9291                    .border_color(status_colors.error.opacity(0.6))
 9292                    .pl_2()
 9293                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9294                    .cursor_default()
 9295                    .hoverable_tooltip(move |_window, cx| {
 9296                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9297                    })
 9298            })
 9299            .children(keybind)
 9300            .child(
 9301                Label::new(label)
 9302                    .size(LabelSize::Small)
 9303                    .when(!has_keybind, |el| {
 9304                        el.color(cx.theme().status().error.into()).strikethrough()
 9305                    }),
 9306            )
 9307            .when(!has_keybind, |el| {
 9308                el.child(
 9309                    h_flex().ml_1().child(
 9310                        Icon::new(IconName::Info)
 9311                            .size(IconSize::Small)
 9312                            .color(cx.theme().status().error.into()),
 9313                    ),
 9314                )
 9315            })
 9316            .when_some(icon, |element, icon| {
 9317                element.child(
 9318                    div()
 9319                        .mt(px(1.5))
 9320                        .child(Icon::new(icon).size(IconSize::Small)),
 9321                )
 9322            })
 9323    }
 9324
 9325    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9326        let accent_color = cx.theme().colors().text_accent;
 9327        let editor_bg_color = cx.theme().colors().editor_background;
 9328        editor_bg_color.blend(accent_color.opacity(0.1))
 9329    }
 9330
 9331    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9332        let accent_color = cx.theme().colors().text_accent;
 9333        let editor_bg_color = cx.theme().colors().editor_background;
 9334        editor_bg_color.blend(accent_color.opacity(0.6))
 9335    }
 9336    fn get_prediction_provider_icon_name(
 9337        provider: &Option<RegisteredEditPredictionProvider>,
 9338    ) -> IconName {
 9339        match provider {
 9340            Some(provider) => match provider.provider.name() {
 9341                "copilot" => IconName::Copilot,
 9342                "supermaven" => IconName::Supermaven,
 9343                _ => IconName::ZedPredict,
 9344            },
 9345            None => IconName::ZedPredict,
 9346        }
 9347    }
 9348
 9349    fn render_edit_prediction_cursor_popover(
 9350        &self,
 9351        min_width: Pixels,
 9352        max_width: Pixels,
 9353        cursor_point: Point,
 9354        style: &EditorStyle,
 9355        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9356        _window: &Window,
 9357        cx: &mut Context<Editor>,
 9358    ) -> Option<AnyElement> {
 9359        let provider = self.edit_prediction_provider.as_ref()?;
 9360        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9361
 9362        let is_refreshing = provider.provider.is_refreshing(cx);
 9363
 9364        fn pending_completion_container(icon: IconName) -> Div {
 9365            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9366        }
 9367
 9368        let completion = match &self.active_edit_prediction {
 9369            Some(prediction) => {
 9370                if !self.has_visible_completions_menu() {
 9371                    const RADIUS: Pixels = px(6.);
 9372                    const BORDER_WIDTH: Pixels = px(1.);
 9373
 9374                    return Some(
 9375                        h_flex()
 9376                            .elevation_2(cx)
 9377                            .border(BORDER_WIDTH)
 9378                            .border_color(cx.theme().colors().border)
 9379                            .when(accept_keystroke.is_none(), |el| {
 9380                                el.border_color(cx.theme().status().error)
 9381                            })
 9382                            .rounded(RADIUS)
 9383                            .rounded_tl(px(0.))
 9384                            .overflow_hidden()
 9385                            .child(div().px_1p5().child(match &prediction.completion {
 9386                                EditPrediction::MoveWithin { target, snapshot } => {
 9387                                    use text::ToPoint as _;
 9388                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9389                                    {
 9390                                        Icon::new(IconName::ZedPredictDown)
 9391                                    } else {
 9392                                        Icon::new(IconName::ZedPredictUp)
 9393                                    }
 9394                                }
 9395                                EditPrediction::MoveOutside { .. } => {
 9396                                    // TODO [zeta2] custom icon for external jump?
 9397                                    Icon::new(provider_icon)
 9398                                }
 9399                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9400                            }))
 9401                            .child(
 9402                                h_flex()
 9403                                    .gap_1()
 9404                                    .py_1()
 9405                                    .px_2()
 9406                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9407                                    .border_l_1()
 9408                                    .border_color(cx.theme().colors().border)
 9409                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9410                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9411                                        el.child(
 9412                                            Label::new("Hold")
 9413                                                .size(LabelSize::Small)
 9414                                                .when(accept_keystroke.is_none(), |el| {
 9415                                                    el.strikethrough()
 9416                                                })
 9417                                                .line_height_style(LineHeightStyle::UiLabel),
 9418                                        )
 9419                                    })
 9420                                    .id("edit_prediction_cursor_popover_keybind")
 9421                                    .when(accept_keystroke.is_none(), |el| {
 9422                                        let status_colors = cx.theme().status();
 9423
 9424                                        el.bg(status_colors.error_background)
 9425                                            .border_color(status_colors.error.opacity(0.6))
 9426                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9427                                            .cursor_default()
 9428                                            .hoverable_tooltip(move |_window, cx| {
 9429                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9430                                                    .into()
 9431                                            })
 9432                                    })
 9433                                    .when_some(
 9434                                        accept_keystroke.as_ref(),
 9435                                        |el, accept_keystroke| {
 9436                                            el.child(h_flex().children(ui::render_modifiers(
 9437                                                accept_keystroke.modifiers(),
 9438                                                PlatformStyle::platform(),
 9439                                                Some(Color::Default),
 9440                                                Some(IconSize::XSmall.rems().into()),
 9441                                                false,
 9442                                            )))
 9443                                        },
 9444                                    ),
 9445                            )
 9446                            .into_any(),
 9447                    );
 9448                }
 9449
 9450                self.render_edit_prediction_cursor_popover_preview(
 9451                    prediction,
 9452                    cursor_point,
 9453                    style,
 9454                    cx,
 9455                )?
 9456            }
 9457
 9458            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9459                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9460                    stale_completion,
 9461                    cursor_point,
 9462                    style,
 9463                    cx,
 9464                )?,
 9465
 9466                None => pending_completion_container(provider_icon)
 9467                    .child(Label::new("...").size(LabelSize::Small)),
 9468            },
 9469
 9470            None => pending_completion_container(provider_icon)
 9471                .child(Label::new("...").size(LabelSize::Small)),
 9472        };
 9473
 9474        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9475            completion
 9476                .with_animation(
 9477                    "loading-completion",
 9478                    Animation::new(Duration::from_secs(2))
 9479                        .repeat()
 9480                        .with_easing(pulsating_between(0.4, 0.8)),
 9481                    |label, delta| label.opacity(delta),
 9482                )
 9483                .into_any_element()
 9484        } else {
 9485            completion.into_any_element()
 9486        };
 9487
 9488        let has_completion = self.active_edit_prediction.is_some();
 9489
 9490        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9491        Some(
 9492            h_flex()
 9493                .min_w(min_width)
 9494                .max_w(max_width)
 9495                .flex_1()
 9496                .elevation_2(cx)
 9497                .border_color(cx.theme().colors().border)
 9498                .child(
 9499                    div()
 9500                        .flex_1()
 9501                        .py_1()
 9502                        .px_2()
 9503                        .overflow_hidden()
 9504                        .child(completion),
 9505                )
 9506                .when_some(accept_keystroke, |el, accept_keystroke| {
 9507                    if !accept_keystroke.modifiers().modified() {
 9508                        return el;
 9509                    }
 9510
 9511                    el.child(
 9512                        h_flex()
 9513                            .h_full()
 9514                            .border_l_1()
 9515                            .rounded_r_lg()
 9516                            .border_color(cx.theme().colors().border)
 9517                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9518                            .gap_1()
 9519                            .py_1()
 9520                            .px_2()
 9521                            .child(
 9522                                h_flex()
 9523                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9524                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9525                                    .child(h_flex().children(ui::render_modifiers(
 9526                                        accept_keystroke.modifiers(),
 9527                                        PlatformStyle::platform(),
 9528                                        Some(if !has_completion {
 9529                                            Color::Muted
 9530                                        } else {
 9531                                            Color::Default
 9532                                        }),
 9533                                        None,
 9534                                        false,
 9535                                    ))),
 9536                            )
 9537                            .child(Label::new("Preview").into_any_element())
 9538                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9539                    )
 9540                })
 9541                .into_any(),
 9542        )
 9543    }
 9544
 9545    fn render_edit_prediction_cursor_popover_preview(
 9546        &self,
 9547        completion: &EditPredictionState,
 9548        cursor_point: Point,
 9549        style: &EditorStyle,
 9550        cx: &mut Context<Editor>,
 9551    ) -> Option<Div> {
 9552        use text::ToPoint as _;
 9553
 9554        fn render_relative_row_jump(
 9555            prefix: impl Into<String>,
 9556            current_row: u32,
 9557            target_row: u32,
 9558        ) -> Div {
 9559            let (row_diff, arrow) = if target_row < current_row {
 9560                (current_row - target_row, IconName::ArrowUp)
 9561            } else {
 9562                (target_row - current_row, IconName::ArrowDown)
 9563            };
 9564
 9565            h_flex()
 9566                .child(
 9567                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9568                        .color(Color::Muted)
 9569                        .size(LabelSize::Small),
 9570                )
 9571                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9572        }
 9573
 9574        let supports_jump = self
 9575            .edit_prediction_provider
 9576            .as_ref()
 9577            .map(|provider| provider.provider.supports_jump_to_edit())
 9578            .unwrap_or(true);
 9579
 9580        match &completion.completion {
 9581            EditPrediction::MoveWithin {
 9582                target, snapshot, ..
 9583            } => {
 9584                if !supports_jump {
 9585                    return None;
 9586                }
 9587
 9588                Some(
 9589                    h_flex()
 9590                        .px_2()
 9591                        .gap_2()
 9592                        .flex_1()
 9593                        .child(
 9594                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9595                                Icon::new(IconName::ZedPredictDown)
 9596                            } else {
 9597                                Icon::new(IconName::ZedPredictUp)
 9598                            },
 9599                        )
 9600                        .child(Label::new("Jump to Edit")),
 9601                )
 9602            }
 9603            EditPrediction::MoveOutside { snapshot, .. } => {
 9604                let file_name = snapshot
 9605                    .file()
 9606                    .map(|file| file.file_name(cx))
 9607                    .unwrap_or("untitled");
 9608                Some(
 9609                    h_flex()
 9610                        .px_2()
 9611                        .gap_2()
 9612                        .flex_1()
 9613                        .child(Icon::new(IconName::ZedPredict))
 9614                        .child(Label::new(format!("Jump to {file_name}"))),
 9615                )
 9616            }
 9617            EditPrediction::Edit {
 9618                edits,
 9619                edit_preview,
 9620                snapshot,
 9621                display_mode: _,
 9622            } => {
 9623                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9624
 9625                let (highlighted_edits, has_more_lines) =
 9626                    if let Some(edit_preview) = edit_preview.as_ref() {
 9627                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9628                            .first_line_preview()
 9629                    } else {
 9630                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9631                    };
 9632
 9633                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9634                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9635
 9636                let preview = h_flex()
 9637                    .gap_1()
 9638                    .min_w_16()
 9639                    .child(styled_text)
 9640                    .when(has_more_lines, |parent| parent.child(""));
 9641
 9642                let left = if supports_jump && first_edit_row != cursor_point.row {
 9643                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9644                        .into_any_element()
 9645                } else {
 9646                    let icon_name =
 9647                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9648                    Icon::new(icon_name).into_any_element()
 9649                };
 9650
 9651                Some(
 9652                    h_flex()
 9653                        .h_full()
 9654                        .flex_1()
 9655                        .gap_2()
 9656                        .pr_1()
 9657                        .overflow_x_hidden()
 9658                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9659                        .child(left)
 9660                        .child(preview),
 9661                )
 9662            }
 9663        }
 9664    }
 9665
 9666    pub fn render_context_menu(
 9667        &self,
 9668        style: &EditorStyle,
 9669        max_height_in_lines: u32,
 9670        window: &mut Window,
 9671        cx: &mut Context<Editor>,
 9672    ) -> Option<AnyElement> {
 9673        let menu = self.context_menu.borrow();
 9674        let menu = menu.as_ref()?;
 9675        if !menu.visible() {
 9676            return None;
 9677        };
 9678        Some(menu.render(style, max_height_in_lines, window, cx))
 9679    }
 9680
 9681    fn render_context_menu_aside(
 9682        &mut self,
 9683        max_size: Size<Pixels>,
 9684        window: &mut Window,
 9685        cx: &mut Context<Editor>,
 9686    ) -> Option<AnyElement> {
 9687        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9688            if menu.visible() {
 9689                menu.render_aside(max_size, window, cx)
 9690            } else {
 9691                None
 9692            }
 9693        })
 9694    }
 9695
 9696    fn hide_context_menu(
 9697        &mut self,
 9698        window: &mut Window,
 9699        cx: &mut Context<Self>,
 9700    ) -> Option<CodeContextMenu> {
 9701        cx.notify();
 9702        self.completion_tasks.clear();
 9703        let context_menu = self.context_menu.borrow_mut().take();
 9704        self.stale_edit_prediction_in_menu.take();
 9705        self.update_visible_edit_prediction(window, cx);
 9706        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9707            && let Some(completion_provider) = &self.completion_provider
 9708        {
 9709            completion_provider.selection_changed(None, window, cx);
 9710        }
 9711        context_menu
 9712    }
 9713
 9714    fn show_snippet_choices(
 9715        &mut self,
 9716        choices: &Vec<String>,
 9717        selection: Range<Anchor>,
 9718        cx: &mut Context<Self>,
 9719    ) {
 9720        let Some((_, buffer, _)) = self
 9721            .buffer()
 9722            .read(cx)
 9723            .excerpt_containing(selection.start, cx)
 9724        else {
 9725            return;
 9726        };
 9727        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9728        else {
 9729            return;
 9730        };
 9731        if buffer != end_buffer {
 9732            log::error!("expected anchor range to have matching buffer IDs");
 9733            return;
 9734        }
 9735
 9736        let id = post_inc(&mut self.next_completion_id);
 9737        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9738        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9739            CompletionsMenu::new_snippet_choices(
 9740                id,
 9741                true,
 9742                choices,
 9743                selection,
 9744                buffer,
 9745                snippet_sort_order,
 9746            ),
 9747        ));
 9748    }
 9749
 9750    pub fn insert_snippet(
 9751        &mut self,
 9752        insertion_ranges: &[Range<usize>],
 9753        snippet: Snippet,
 9754        window: &mut Window,
 9755        cx: &mut Context<Self>,
 9756    ) -> Result<()> {
 9757        struct Tabstop<T> {
 9758            is_end_tabstop: bool,
 9759            ranges: Vec<Range<T>>,
 9760            choices: Option<Vec<String>>,
 9761        }
 9762
 9763        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9764            let snippet_text: Arc<str> = snippet.text.clone().into();
 9765            let edits = insertion_ranges
 9766                .iter()
 9767                .cloned()
 9768                .map(|range| (range, snippet_text.clone()));
 9769            let autoindent_mode = AutoindentMode::Block {
 9770                original_indent_columns: Vec::new(),
 9771            };
 9772            buffer.edit(edits, Some(autoindent_mode), cx);
 9773
 9774            let snapshot = &*buffer.read(cx);
 9775            let snippet = &snippet;
 9776            snippet
 9777                .tabstops
 9778                .iter()
 9779                .map(|tabstop| {
 9780                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9781                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9782                    });
 9783                    let mut tabstop_ranges = tabstop
 9784                        .ranges
 9785                        .iter()
 9786                        .flat_map(|tabstop_range| {
 9787                            let mut delta = 0_isize;
 9788                            insertion_ranges.iter().map(move |insertion_range| {
 9789                                let insertion_start = insertion_range.start as isize + delta;
 9790                                delta +=
 9791                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9792
 9793                                let start = ((insertion_start + tabstop_range.start) as usize)
 9794                                    .min(snapshot.len());
 9795                                let end = ((insertion_start + tabstop_range.end) as usize)
 9796                                    .min(snapshot.len());
 9797                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9798                            })
 9799                        })
 9800                        .collect::<Vec<_>>();
 9801                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9802
 9803                    Tabstop {
 9804                        is_end_tabstop,
 9805                        ranges: tabstop_ranges,
 9806                        choices: tabstop.choices.clone(),
 9807                    }
 9808                })
 9809                .collect::<Vec<_>>()
 9810        });
 9811        if let Some(tabstop) = tabstops.first() {
 9812            self.change_selections(Default::default(), window, cx, |s| {
 9813                // Reverse order so that the first range is the newest created selection.
 9814                // Completions will use it and autoscroll will prioritize it.
 9815                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9816            });
 9817
 9818            if let Some(choices) = &tabstop.choices
 9819                && let Some(selection) = tabstop.ranges.first()
 9820            {
 9821                self.show_snippet_choices(choices, selection.clone(), cx)
 9822            }
 9823
 9824            // If we're already at the last tabstop and it's at the end of the snippet,
 9825            // we're done, we don't need to keep the state around.
 9826            if !tabstop.is_end_tabstop {
 9827                let choices = tabstops
 9828                    .iter()
 9829                    .map(|tabstop| tabstop.choices.clone())
 9830                    .collect();
 9831
 9832                let ranges = tabstops
 9833                    .into_iter()
 9834                    .map(|tabstop| tabstop.ranges)
 9835                    .collect::<Vec<_>>();
 9836
 9837                self.snippet_stack.push(SnippetState {
 9838                    active_index: 0,
 9839                    ranges,
 9840                    choices,
 9841                });
 9842            }
 9843
 9844            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9845            if self.autoclose_regions.is_empty() {
 9846                let snapshot = self.buffer.read(cx).snapshot(cx);
 9847                let mut all_selections = self.selections.all::<Point>(cx);
 9848                for selection in &mut all_selections {
 9849                    let selection_head = selection.head();
 9850                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9851                        continue;
 9852                    };
 9853
 9854                    let mut bracket_pair = None;
 9855                    let max_lookup_length = scope
 9856                        .brackets()
 9857                        .map(|(pair, _)| {
 9858                            pair.start
 9859                                .as_str()
 9860                                .chars()
 9861                                .count()
 9862                                .max(pair.end.as_str().chars().count())
 9863                        })
 9864                        .max();
 9865                    if let Some(max_lookup_length) = max_lookup_length {
 9866                        let next_text = snapshot
 9867                            .chars_at(selection_head)
 9868                            .take(max_lookup_length)
 9869                            .collect::<String>();
 9870                        let prev_text = snapshot
 9871                            .reversed_chars_at(selection_head)
 9872                            .take(max_lookup_length)
 9873                            .collect::<String>();
 9874
 9875                        for (pair, enabled) in scope.brackets() {
 9876                            if enabled
 9877                                && pair.close
 9878                                && prev_text.starts_with(pair.start.as_str())
 9879                                && next_text.starts_with(pair.end.as_str())
 9880                            {
 9881                                bracket_pair = Some(pair.clone());
 9882                                break;
 9883                            }
 9884                        }
 9885                    }
 9886
 9887                    if let Some(pair) = bracket_pair {
 9888                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9889                        let autoclose_enabled =
 9890                            self.use_autoclose && snapshot_settings.use_autoclose;
 9891                        if autoclose_enabled {
 9892                            let start = snapshot.anchor_after(selection_head);
 9893                            let end = snapshot.anchor_after(selection_head);
 9894                            self.autoclose_regions.push(AutocloseRegion {
 9895                                selection_id: selection.id,
 9896                                range: start..end,
 9897                                pair,
 9898                            });
 9899                        }
 9900                    }
 9901                }
 9902            }
 9903        }
 9904        Ok(())
 9905    }
 9906
 9907    pub fn move_to_next_snippet_tabstop(
 9908        &mut self,
 9909        window: &mut Window,
 9910        cx: &mut Context<Self>,
 9911    ) -> bool {
 9912        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9913    }
 9914
 9915    pub fn move_to_prev_snippet_tabstop(
 9916        &mut self,
 9917        window: &mut Window,
 9918        cx: &mut Context<Self>,
 9919    ) -> bool {
 9920        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9921    }
 9922
 9923    pub fn move_to_snippet_tabstop(
 9924        &mut self,
 9925        bias: Bias,
 9926        window: &mut Window,
 9927        cx: &mut Context<Self>,
 9928    ) -> bool {
 9929        if let Some(mut snippet) = self.snippet_stack.pop() {
 9930            match bias {
 9931                Bias::Left => {
 9932                    if snippet.active_index > 0 {
 9933                        snippet.active_index -= 1;
 9934                    } else {
 9935                        self.snippet_stack.push(snippet);
 9936                        return false;
 9937                    }
 9938                }
 9939                Bias::Right => {
 9940                    if snippet.active_index + 1 < snippet.ranges.len() {
 9941                        snippet.active_index += 1;
 9942                    } else {
 9943                        self.snippet_stack.push(snippet);
 9944                        return false;
 9945                    }
 9946                }
 9947            }
 9948            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9949                self.change_selections(Default::default(), window, cx, |s| {
 9950                    // Reverse order so that the first range is the newest created selection.
 9951                    // Completions will use it and autoscroll will prioritize it.
 9952                    s.select_ranges(current_ranges.iter().rev().cloned())
 9953                });
 9954
 9955                if let Some(choices) = &snippet.choices[snippet.active_index]
 9956                    && let Some(selection) = current_ranges.first()
 9957                {
 9958                    self.show_snippet_choices(choices, selection.clone(), cx);
 9959                }
 9960
 9961                // If snippet state is not at the last tabstop, push it back on the stack
 9962                if snippet.active_index + 1 < snippet.ranges.len() {
 9963                    self.snippet_stack.push(snippet);
 9964                }
 9965                return true;
 9966            }
 9967        }
 9968
 9969        false
 9970    }
 9971
 9972    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9973        self.transact(window, cx, |this, window, cx| {
 9974            this.select_all(&SelectAll, window, cx);
 9975            this.insert("", window, cx);
 9976        });
 9977    }
 9978
 9979    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9980        if self.read_only(cx) {
 9981            return;
 9982        }
 9983        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9984        self.transact(window, cx, |this, window, cx| {
 9985            this.select_autoclose_pair(window, cx);
 9986            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9987            if !this.linked_edit_ranges.is_empty() {
 9988                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9989                let snapshot = this.buffer.read(cx).snapshot(cx);
 9990
 9991                for selection in selections.iter() {
 9992                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9993                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9994                    if selection_start.buffer_id != selection_end.buffer_id {
 9995                        continue;
 9996                    }
 9997                    if let Some(ranges) =
 9998                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9999                    {
10000                        for (buffer, entries) in ranges {
10001                            linked_ranges.entry(buffer).or_default().extend(entries);
10002                        }
10003                    }
10004                }
10005            }
10006
10007            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10008            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10009            for selection in &mut selections {
10010                if selection.is_empty() {
10011                    let old_head = selection.head();
10012                    let mut new_head =
10013                        movement::left(&display_map, old_head.to_display_point(&display_map))
10014                            .to_point(&display_map);
10015                    if let Some((buffer, line_buffer_range)) = display_map
10016                        .buffer_snapshot
10017                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10018                    {
10019                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10020                        let indent_len = match indent_size.kind {
10021                            IndentKind::Space => {
10022                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10023                            }
10024                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10025                        };
10026                        if old_head.column <= indent_size.len && old_head.column > 0 {
10027                            let indent_len = indent_len.get();
10028                            new_head = cmp::min(
10029                                new_head,
10030                                MultiBufferPoint::new(
10031                                    old_head.row,
10032                                    ((old_head.column - 1) / indent_len) * indent_len,
10033                                ),
10034                            );
10035                        }
10036                    }
10037
10038                    selection.set_head(new_head, SelectionGoal::None);
10039                }
10040            }
10041
10042            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10043            this.insert("", window, cx);
10044            let empty_str: Arc<str> = Arc::from("");
10045            for (buffer, edits) in linked_ranges {
10046                let snapshot = buffer.read(cx).snapshot();
10047                use text::ToPoint as TP;
10048
10049                let edits = edits
10050                    .into_iter()
10051                    .map(|range| {
10052                        let end_point = TP::to_point(&range.end, &snapshot);
10053                        let mut start_point = TP::to_point(&range.start, &snapshot);
10054
10055                        if end_point == start_point {
10056                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10057                                .saturating_sub(1);
10058                            start_point =
10059                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10060                        };
10061
10062                        (start_point..end_point, empty_str.clone())
10063                    })
10064                    .sorted_by_key(|(range, _)| range.start)
10065                    .collect::<Vec<_>>();
10066                buffer.update(cx, |this, cx| {
10067                    this.edit(edits, None, cx);
10068                })
10069            }
10070            this.refresh_edit_prediction(true, false, window, cx);
10071            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
10072        });
10073    }
10074
10075    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10076        if self.read_only(cx) {
10077            return;
10078        }
10079        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10080        self.transact(window, cx, |this, window, cx| {
10081            this.change_selections(Default::default(), window, cx, |s| {
10082                s.move_with(|map, selection| {
10083                    if selection.is_empty() {
10084                        let cursor = movement::right(map, selection.head());
10085                        selection.end = cursor;
10086                        selection.reversed = true;
10087                        selection.goal = SelectionGoal::None;
10088                    }
10089                })
10090            });
10091            this.insert("", window, cx);
10092            this.refresh_edit_prediction(true, false, window, cx);
10093        });
10094    }
10095
10096    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10097        if self.mode.is_single_line() {
10098            cx.propagate();
10099            return;
10100        }
10101
10102        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10103        if self.move_to_prev_snippet_tabstop(window, cx) {
10104            return;
10105        }
10106        self.outdent(&Outdent, window, cx);
10107    }
10108
10109    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10110        if self.mode.is_single_line() {
10111            cx.propagate();
10112            return;
10113        }
10114
10115        if self.move_to_next_snippet_tabstop(window, cx) {
10116            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10117            return;
10118        }
10119        if self.read_only(cx) {
10120            return;
10121        }
10122        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10123        let mut selections = self.selections.all_adjusted(cx);
10124        let buffer = self.buffer.read(cx);
10125        let snapshot = buffer.snapshot(cx);
10126        let rows_iter = selections.iter().map(|s| s.head().row);
10127        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10128
10129        let has_some_cursor_in_whitespace = selections
10130            .iter()
10131            .filter(|selection| selection.is_empty())
10132            .any(|selection| {
10133                let cursor = selection.head();
10134                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10135                cursor.column < current_indent.len
10136            });
10137
10138        let mut edits = Vec::new();
10139        let mut prev_edited_row = 0;
10140        let mut row_delta = 0;
10141        for selection in &mut selections {
10142            if selection.start.row != prev_edited_row {
10143                row_delta = 0;
10144            }
10145            prev_edited_row = selection.end.row;
10146
10147            // If the selection is non-empty, then increase the indentation of the selected lines.
10148            if !selection.is_empty() {
10149                row_delta =
10150                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10151                continue;
10152            }
10153
10154            let cursor = selection.head();
10155            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10156            if let Some(suggested_indent) =
10157                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10158            {
10159                // Don't do anything if already at suggested indent
10160                // and there is any other cursor which is not
10161                if has_some_cursor_in_whitespace
10162                    && cursor.column == current_indent.len
10163                    && current_indent.len == suggested_indent.len
10164                {
10165                    continue;
10166                }
10167
10168                // Adjust line and move cursor to suggested indent
10169                // if cursor is not at suggested indent
10170                if cursor.column < suggested_indent.len
10171                    && cursor.column <= current_indent.len
10172                    && current_indent.len <= suggested_indent.len
10173                {
10174                    selection.start = Point::new(cursor.row, suggested_indent.len);
10175                    selection.end = selection.start;
10176                    if row_delta == 0 {
10177                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10178                            cursor.row,
10179                            current_indent,
10180                            suggested_indent,
10181                        ));
10182                        row_delta = suggested_indent.len - current_indent.len;
10183                    }
10184                    continue;
10185                }
10186
10187                // If current indent is more than suggested indent
10188                // only move cursor to current indent and skip indent
10189                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10190                    selection.start = Point::new(cursor.row, current_indent.len);
10191                    selection.end = selection.start;
10192                    continue;
10193                }
10194            }
10195
10196            // Otherwise, insert a hard or soft tab.
10197            let settings = buffer.language_settings_at(cursor, cx);
10198            let tab_size = if settings.hard_tabs {
10199                IndentSize::tab()
10200            } else {
10201                let tab_size = settings.tab_size.get();
10202                let indent_remainder = snapshot
10203                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10204                    .flat_map(str::chars)
10205                    .fold(row_delta % tab_size, |counter: u32, c| {
10206                        if c == '\t' {
10207                            0
10208                        } else {
10209                            (counter + 1) % tab_size
10210                        }
10211                    });
10212
10213                let chars_to_next_tab_stop = tab_size - indent_remainder;
10214                IndentSize::spaces(chars_to_next_tab_stop)
10215            };
10216            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10217            selection.end = selection.start;
10218            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10219            row_delta += tab_size.len;
10220        }
10221
10222        self.transact(window, cx, |this, window, cx| {
10223            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10224            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10225            this.refresh_edit_prediction(true, false, window, cx);
10226        });
10227    }
10228
10229    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10230        if self.read_only(cx) {
10231            return;
10232        }
10233        if self.mode.is_single_line() {
10234            cx.propagate();
10235            return;
10236        }
10237
10238        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10239        let mut selections = self.selections.all::<Point>(cx);
10240        let mut prev_edited_row = 0;
10241        let mut row_delta = 0;
10242        let mut edits = Vec::new();
10243        let buffer = self.buffer.read(cx);
10244        let snapshot = buffer.snapshot(cx);
10245        for selection in &mut selections {
10246            if selection.start.row != prev_edited_row {
10247                row_delta = 0;
10248            }
10249            prev_edited_row = selection.end.row;
10250
10251            row_delta =
10252                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10253        }
10254
10255        self.transact(window, cx, |this, window, cx| {
10256            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10257            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10258        });
10259    }
10260
10261    fn indent_selection(
10262        buffer: &MultiBuffer,
10263        snapshot: &MultiBufferSnapshot,
10264        selection: &mut Selection<Point>,
10265        edits: &mut Vec<(Range<Point>, String)>,
10266        delta_for_start_row: u32,
10267        cx: &App,
10268    ) -> u32 {
10269        let settings = buffer.language_settings_at(selection.start, cx);
10270        let tab_size = settings.tab_size.get();
10271        let indent_kind = if settings.hard_tabs {
10272            IndentKind::Tab
10273        } else {
10274            IndentKind::Space
10275        };
10276        let mut start_row = selection.start.row;
10277        let mut end_row = selection.end.row + 1;
10278
10279        // If a selection ends at the beginning of a line, don't indent
10280        // that last line.
10281        if selection.end.column == 0 && selection.end.row > selection.start.row {
10282            end_row -= 1;
10283        }
10284
10285        // Avoid re-indenting a row that has already been indented by a
10286        // previous selection, but still update this selection's column
10287        // to reflect that indentation.
10288        if delta_for_start_row > 0 {
10289            start_row += 1;
10290            selection.start.column += delta_for_start_row;
10291            if selection.end.row == selection.start.row {
10292                selection.end.column += delta_for_start_row;
10293            }
10294        }
10295
10296        let mut delta_for_end_row = 0;
10297        let has_multiple_rows = start_row + 1 != end_row;
10298        for row in start_row..end_row {
10299            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10300            let indent_delta = match (current_indent.kind, indent_kind) {
10301                (IndentKind::Space, IndentKind::Space) => {
10302                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10303                    IndentSize::spaces(columns_to_next_tab_stop)
10304                }
10305                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10306                (_, IndentKind::Tab) => IndentSize::tab(),
10307            };
10308
10309            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10310                0
10311            } else {
10312                selection.start.column
10313            };
10314            let row_start = Point::new(row, start);
10315            edits.push((
10316                row_start..row_start,
10317                indent_delta.chars().collect::<String>(),
10318            ));
10319
10320            // Update this selection's endpoints to reflect the indentation.
10321            if row == selection.start.row {
10322                selection.start.column += indent_delta.len;
10323            }
10324            if row == selection.end.row {
10325                selection.end.column += indent_delta.len;
10326                delta_for_end_row = indent_delta.len;
10327            }
10328        }
10329
10330        if selection.start.row == selection.end.row {
10331            delta_for_start_row + delta_for_end_row
10332        } else {
10333            delta_for_end_row
10334        }
10335    }
10336
10337    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10338        if self.read_only(cx) {
10339            return;
10340        }
10341        if self.mode.is_single_line() {
10342            cx.propagate();
10343            return;
10344        }
10345
10346        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10347        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10348        let selections = self.selections.all::<Point>(cx);
10349        let mut deletion_ranges = Vec::new();
10350        let mut last_outdent = None;
10351        {
10352            let buffer = self.buffer.read(cx);
10353            let snapshot = buffer.snapshot(cx);
10354            for selection in &selections {
10355                let settings = buffer.language_settings_at(selection.start, cx);
10356                let tab_size = settings.tab_size.get();
10357                let mut rows = selection.spanned_rows(false, &display_map);
10358
10359                // Avoid re-outdenting a row that has already been outdented by a
10360                // previous selection.
10361                if let Some(last_row) = last_outdent
10362                    && last_row == rows.start
10363                {
10364                    rows.start = rows.start.next_row();
10365                }
10366                let has_multiple_rows = rows.len() > 1;
10367                for row in rows.iter_rows() {
10368                    let indent_size = snapshot.indent_size_for_line(row);
10369                    if indent_size.len > 0 {
10370                        let deletion_len = match indent_size.kind {
10371                            IndentKind::Space => {
10372                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10373                                if columns_to_prev_tab_stop == 0 {
10374                                    tab_size
10375                                } else {
10376                                    columns_to_prev_tab_stop
10377                                }
10378                            }
10379                            IndentKind::Tab => 1,
10380                        };
10381                        let start = if has_multiple_rows
10382                            || deletion_len > selection.start.column
10383                            || indent_size.len < selection.start.column
10384                        {
10385                            0
10386                        } else {
10387                            selection.start.column - deletion_len
10388                        };
10389                        deletion_ranges.push(
10390                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10391                        );
10392                        last_outdent = Some(row);
10393                    }
10394                }
10395            }
10396        }
10397
10398        self.transact(window, cx, |this, window, cx| {
10399            this.buffer.update(cx, |buffer, cx| {
10400                let empty_str: Arc<str> = Arc::default();
10401                buffer.edit(
10402                    deletion_ranges
10403                        .into_iter()
10404                        .map(|range| (range, empty_str.clone())),
10405                    None,
10406                    cx,
10407                );
10408            });
10409            let selections = this.selections.all::<usize>(cx);
10410            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10411        });
10412    }
10413
10414    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10415        if self.read_only(cx) {
10416            return;
10417        }
10418        if self.mode.is_single_line() {
10419            cx.propagate();
10420            return;
10421        }
10422
10423        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10424        let selections = self
10425            .selections
10426            .all::<usize>(cx)
10427            .into_iter()
10428            .map(|s| s.range());
10429
10430        self.transact(window, cx, |this, window, cx| {
10431            this.buffer.update(cx, |buffer, cx| {
10432                buffer.autoindent_ranges(selections, cx);
10433            });
10434            let selections = this.selections.all::<usize>(cx);
10435            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10436        });
10437    }
10438
10439    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10440        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10441        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10442        let selections = self.selections.all::<Point>(cx);
10443
10444        let mut new_cursors = Vec::new();
10445        let mut edit_ranges = Vec::new();
10446        let mut selections = selections.iter().peekable();
10447        while let Some(selection) = selections.next() {
10448            let mut rows = selection.spanned_rows(false, &display_map);
10449            let goal_display_column = selection.head().to_display_point(&display_map).column();
10450
10451            // Accumulate contiguous regions of rows that we want to delete.
10452            while let Some(next_selection) = selections.peek() {
10453                let next_rows = next_selection.spanned_rows(false, &display_map);
10454                if next_rows.start <= rows.end {
10455                    rows.end = next_rows.end;
10456                    selections.next().unwrap();
10457                } else {
10458                    break;
10459                }
10460            }
10461
10462            let buffer = &display_map.buffer_snapshot;
10463            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10464            let edit_end;
10465            let cursor_buffer_row;
10466            if buffer.max_point().row >= rows.end.0 {
10467                // If there's a line after the range, delete the \n from the end of the row range
10468                // and position the cursor on the next line.
10469                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10470                cursor_buffer_row = rows.end;
10471            } else {
10472                // If there isn't a line after the range, delete the \n from the line before the
10473                // start of the row range and position the cursor there.
10474                edit_start = edit_start.saturating_sub(1);
10475                edit_end = buffer.len();
10476                cursor_buffer_row = rows.start.previous_row();
10477            }
10478
10479            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10480            *cursor.column_mut() =
10481                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10482
10483            new_cursors.push((
10484                selection.id,
10485                buffer.anchor_after(cursor.to_point(&display_map)),
10486            ));
10487            edit_ranges.push(edit_start..edit_end);
10488        }
10489
10490        self.transact(window, cx, |this, window, cx| {
10491            let buffer = this.buffer.update(cx, |buffer, cx| {
10492                let empty_str: Arc<str> = Arc::default();
10493                buffer.edit(
10494                    edit_ranges
10495                        .into_iter()
10496                        .map(|range| (range, empty_str.clone())),
10497                    None,
10498                    cx,
10499                );
10500                buffer.snapshot(cx)
10501            });
10502            let new_selections = new_cursors
10503                .into_iter()
10504                .map(|(id, cursor)| {
10505                    let cursor = cursor.to_point(&buffer);
10506                    Selection {
10507                        id,
10508                        start: cursor,
10509                        end: cursor,
10510                        reversed: false,
10511                        goal: SelectionGoal::None,
10512                    }
10513                })
10514                .collect();
10515
10516            this.change_selections(Default::default(), window, cx, |s| {
10517                s.select(new_selections);
10518            });
10519        });
10520    }
10521
10522    pub fn join_lines_impl(
10523        &mut self,
10524        insert_whitespace: bool,
10525        window: &mut Window,
10526        cx: &mut Context<Self>,
10527    ) {
10528        if self.read_only(cx) {
10529            return;
10530        }
10531        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10532        for selection in self.selections.all::<Point>(cx) {
10533            let start = MultiBufferRow(selection.start.row);
10534            // Treat single line selections as if they include the next line. Otherwise this action
10535            // would do nothing for single line selections individual cursors.
10536            let end = if selection.start.row == selection.end.row {
10537                MultiBufferRow(selection.start.row + 1)
10538            } else {
10539                MultiBufferRow(selection.end.row)
10540            };
10541
10542            if let Some(last_row_range) = row_ranges.last_mut()
10543                && start <= last_row_range.end
10544            {
10545                last_row_range.end = end;
10546                continue;
10547            }
10548            row_ranges.push(start..end);
10549        }
10550
10551        let snapshot = self.buffer.read(cx).snapshot(cx);
10552        let mut cursor_positions = Vec::new();
10553        for row_range in &row_ranges {
10554            let anchor = snapshot.anchor_before(Point::new(
10555                row_range.end.previous_row().0,
10556                snapshot.line_len(row_range.end.previous_row()),
10557            ));
10558            cursor_positions.push(anchor..anchor);
10559        }
10560
10561        self.transact(window, cx, |this, window, cx| {
10562            for row_range in row_ranges.into_iter().rev() {
10563                for row in row_range.iter_rows().rev() {
10564                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10565                    let next_line_row = row.next_row();
10566                    let indent = snapshot.indent_size_for_line(next_line_row);
10567                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10568
10569                    let replace =
10570                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10571                            " "
10572                        } else {
10573                            ""
10574                        };
10575
10576                    this.buffer.update(cx, |buffer, cx| {
10577                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10578                    });
10579                }
10580            }
10581
10582            this.change_selections(Default::default(), window, cx, |s| {
10583                s.select_anchor_ranges(cursor_positions)
10584            });
10585        });
10586    }
10587
10588    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10589        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10590        self.join_lines_impl(true, window, cx);
10591    }
10592
10593    pub fn sort_lines_case_sensitive(
10594        &mut self,
10595        _: &SortLinesCaseSensitive,
10596        window: &mut Window,
10597        cx: &mut Context<Self>,
10598    ) {
10599        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10600    }
10601
10602    pub fn sort_lines_by_length(
10603        &mut self,
10604        _: &SortLinesByLength,
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.chars().count())
10610        })
10611    }
10612
10613    pub fn sort_lines_case_insensitive(
10614        &mut self,
10615        _: &SortLinesCaseInsensitive,
10616        window: &mut Window,
10617        cx: &mut Context<Self>,
10618    ) {
10619        self.manipulate_immutable_lines(window, cx, |lines| {
10620            lines.sort_by_key(|line| line.to_lowercase())
10621        })
10622    }
10623
10624    pub fn unique_lines_case_insensitive(
10625        &mut self,
10626        _: &UniqueLinesCaseInsensitive,
10627        window: &mut Window,
10628        cx: &mut Context<Self>,
10629    ) {
10630        self.manipulate_immutable_lines(window, cx, |lines| {
10631            let mut seen = HashSet::default();
10632            lines.retain(|line| seen.insert(line.to_lowercase()));
10633        })
10634    }
10635
10636    pub fn unique_lines_case_sensitive(
10637        &mut self,
10638        _: &UniqueLinesCaseSensitive,
10639        window: &mut Window,
10640        cx: &mut Context<Self>,
10641    ) {
10642        self.manipulate_immutable_lines(window, cx, |lines| {
10643            let mut seen = HashSet::default();
10644            lines.retain(|line| seen.insert(*line));
10645        })
10646    }
10647
10648    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10649        let snapshot = self.buffer.read(cx).snapshot(cx);
10650        for selection in self.selections.disjoint_anchors_arc().iter() {
10651            if snapshot
10652                .language_at(selection.start)
10653                .and_then(|lang| lang.config().wrap_characters.as_ref())
10654                .is_some()
10655            {
10656                return true;
10657            }
10658        }
10659        false
10660    }
10661
10662    fn wrap_selections_in_tag(
10663        &mut self,
10664        _: &WrapSelectionsInTag,
10665        window: &mut Window,
10666        cx: &mut Context<Self>,
10667    ) {
10668        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10669
10670        let snapshot = self.buffer.read(cx).snapshot(cx);
10671
10672        let mut edits = Vec::new();
10673        let mut boundaries = Vec::new();
10674
10675        for selection in self.selections.all::<Point>(cx).iter() {
10676            let Some(wrap_config) = snapshot
10677                .language_at(selection.start)
10678                .and_then(|lang| lang.config().wrap_characters.clone())
10679            else {
10680                continue;
10681            };
10682
10683            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10684            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10685
10686            let start_before = snapshot.anchor_before(selection.start);
10687            let end_after = snapshot.anchor_after(selection.end);
10688
10689            edits.push((start_before..start_before, open_tag));
10690            edits.push((end_after..end_after, close_tag));
10691
10692            boundaries.push((
10693                start_before,
10694                end_after,
10695                wrap_config.start_prefix.len(),
10696                wrap_config.end_suffix.len(),
10697            ));
10698        }
10699
10700        if edits.is_empty() {
10701            return;
10702        }
10703
10704        self.transact(window, cx, |this, window, cx| {
10705            let buffer = this.buffer.update(cx, |buffer, cx| {
10706                buffer.edit(edits, None, cx);
10707                buffer.snapshot(cx)
10708            });
10709
10710            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10711            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10712                boundaries.into_iter()
10713            {
10714                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10715                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10716                new_selections.push(open_offset..open_offset);
10717                new_selections.push(close_offset..close_offset);
10718            }
10719
10720            this.change_selections(Default::default(), window, cx, |s| {
10721                s.select_ranges(new_selections);
10722            });
10723
10724            this.request_autoscroll(Autoscroll::fit(), cx);
10725        });
10726    }
10727
10728    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10729        let Some(project) = self.project.clone() else {
10730            return;
10731        };
10732        self.reload(project, window, cx)
10733            .detach_and_notify_err(window, cx);
10734    }
10735
10736    pub fn restore_file(
10737        &mut self,
10738        _: &::git::RestoreFile,
10739        window: &mut Window,
10740        cx: &mut Context<Self>,
10741    ) {
10742        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10743        let mut buffer_ids = HashSet::default();
10744        let snapshot = self.buffer().read(cx).snapshot(cx);
10745        for selection in self.selections.all::<usize>(cx) {
10746            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10747        }
10748
10749        let buffer = self.buffer().read(cx);
10750        let ranges = buffer_ids
10751            .into_iter()
10752            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10753            .collect::<Vec<_>>();
10754
10755        self.restore_hunks_in_ranges(ranges, window, cx);
10756    }
10757
10758    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10760        let selections = self
10761            .selections
10762            .all(cx)
10763            .into_iter()
10764            .map(|s| s.range())
10765            .collect();
10766        self.restore_hunks_in_ranges(selections, window, cx);
10767    }
10768
10769    pub fn restore_hunks_in_ranges(
10770        &mut self,
10771        ranges: Vec<Range<Point>>,
10772        window: &mut Window,
10773        cx: &mut Context<Editor>,
10774    ) {
10775        let mut revert_changes = HashMap::default();
10776        let chunk_by = self
10777            .snapshot(window, cx)
10778            .hunks_for_ranges(ranges)
10779            .into_iter()
10780            .chunk_by(|hunk| hunk.buffer_id);
10781        for (buffer_id, hunks) in &chunk_by {
10782            let hunks = hunks.collect::<Vec<_>>();
10783            for hunk in &hunks {
10784                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10785            }
10786            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10787        }
10788        drop(chunk_by);
10789        if !revert_changes.is_empty() {
10790            self.transact(window, cx, |editor, window, cx| {
10791                editor.restore(revert_changes, window, cx);
10792            });
10793        }
10794    }
10795
10796    pub fn open_active_item_in_terminal(
10797        &mut self,
10798        _: &OpenInTerminal,
10799        window: &mut Window,
10800        cx: &mut Context<Self>,
10801    ) {
10802        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10803            let project_path = buffer.read(cx).project_path(cx)?;
10804            let project = self.project()?.read(cx);
10805            let entry = project.entry_for_path(&project_path, cx)?;
10806            let parent = match &entry.canonical_path {
10807                Some(canonical_path) => canonical_path.to_path_buf(),
10808                None => project.absolute_path(&project_path, cx)?,
10809            }
10810            .parent()?
10811            .to_path_buf();
10812            Some(parent)
10813        }) {
10814            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10815        }
10816    }
10817
10818    fn set_breakpoint_context_menu(
10819        &mut self,
10820        display_row: DisplayRow,
10821        position: Option<Anchor>,
10822        clicked_point: gpui::Point<Pixels>,
10823        window: &mut Window,
10824        cx: &mut Context<Self>,
10825    ) {
10826        let source = self
10827            .buffer
10828            .read(cx)
10829            .snapshot(cx)
10830            .anchor_before(Point::new(display_row.0, 0u32));
10831
10832        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10833
10834        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10835            self,
10836            source,
10837            clicked_point,
10838            context_menu,
10839            window,
10840            cx,
10841        );
10842    }
10843
10844    fn add_edit_breakpoint_block(
10845        &mut self,
10846        anchor: Anchor,
10847        breakpoint: &Breakpoint,
10848        edit_action: BreakpointPromptEditAction,
10849        window: &mut Window,
10850        cx: &mut Context<Self>,
10851    ) {
10852        let weak_editor = cx.weak_entity();
10853        let bp_prompt = cx.new(|cx| {
10854            BreakpointPromptEditor::new(
10855                weak_editor,
10856                anchor,
10857                breakpoint.clone(),
10858                edit_action,
10859                window,
10860                cx,
10861            )
10862        });
10863
10864        let height = bp_prompt.update(cx, |this, cx| {
10865            this.prompt
10866                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10867        });
10868        let cloned_prompt = bp_prompt.clone();
10869        let blocks = vec![BlockProperties {
10870            style: BlockStyle::Sticky,
10871            placement: BlockPlacement::Above(anchor),
10872            height: Some(height),
10873            render: Arc::new(move |cx| {
10874                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10875                cloned_prompt.clone().into_any_element()
10876            }),
10877            priority: 0,
10878        }];
10879
10880        let focus_handle = bp_prompt.focus_handle(cx);
10881        window.focus(&focus_handle);
10882
10883        let block_ids = self.insert_blocks(blocks, None, cx);
10884        bp_prompt.update(cx, |prompt, _| {
10885            prompt.add_block_ids(block_ids);
10886        });
10887    }
10888
10889    pub(crate) fn breakpoint_at_row(
10890        &self,
10891        row: u32,
10892        window: &mut Window,
10893        cx: &mut Context<Self>,
10894    ) -> Option<(Anchor, Breakpoint)> {
10895        let snapshot = self.snapshot(window, cx);
10896        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10897
10898        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10899    }
10900
10901    pub(crate) fn breakpoint_at_anchor(
10902        &self,
10903        breakpoint_position: Anchor,
10904        snapshot: &EditorSnapshot,
10905        cx: &mut Context<Self>,
10906    ) -> Option<(Anchor, Breakpoint)> {
10907        let buffer = self
10908            .buffer
10909            .read(cx)
10910            .buffer_for_anchor(breakpoint_position, cx)?;
10911
10912        let enclosing_excerpt = breakpoint_position.excerpt_id;
10913        let buffer_snapshot = buffer.read(cx).snapshot();
10914
10915        let row = buffer_snapshot
10916            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10917            .row;
10918
10919        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10920        let anchor_end = snapshot
10921            .buffer_snapshot
10922            .anchor_after(Point::new(row, line_len));
10923
10924        self.breakpoint_store
10925            .as_ref()?
10926            .read_with(cx, |breakpoint_store, cx| {
10927                breakpoint_store
10928                    .breakpoints(
10929                        &buffer,
10930                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10931                        &buffer_snapshot,
10932                        cx,
10933                    )
10934                    .next()
10935                    .and_then(|(bp, _)| {
10936                        let breakpoint_row = buffer_snapshot
10937                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10938                            .row;
10939
10940                        if breakpoint_row == row {
10941                            snapshot
10942                                .buffer_snapshot
10943                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10944                                .map(|position| (position, bp.bp.clone()))
10945                        } else {
10946                            None
10947                        }
10948                    })
10949            })
10950    }
10951
10952    pub fn edit_log_breakpoint(
10953        &mut self,
10954        _: &EditLogBreakpoint,
10955        window: &mut Window,
10956        cx: &mut Context<Self>,
10957    ) {
10958        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10959            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10960                message: None,
10961                state: BreakpointState::Enabled,
10962                condition: None,
10963                hit_condition: None,
10964            });
10965
10966            self.add_edit_breakpoint_block(
10967                anchor,
10968                &breakpoint,
10969                BreakpointPromptEditAction::Log,
10970                window,
10971                cx,
10972            );
10973        }
10974    }
10975
10976    fn breakpoints_at_cursors(
10977        &self,
10978        window: &mut Window,
10979        cx: &mut Context<Self>,
10980    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10981        let snapshot = self.snapshot(window, cx);
10982        let cursors = self
10983            .selections
10984            .disjoint_anchors_arc()
10985            .iter()
10986            .map(|selection| {
10987                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10988
10989                let breakpoint_position = self
10990                    .breakpoint_at_row(cursor_position.row, window, cx)
10991                    .map(|bp| bp.0)
10992                    .unwrap_or_else(|| {
10993                        snapshot
10994                            .display_snapshot
10995                            .buffer_snapshot
10996                            .anchor_after(Point::new(cursor_position.row, 0))
10997                    });
10998
10999                let breakpoint = self
11000                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11001                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11002
11003                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11004            })
11005            // 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.
11006            .collect::<HashMap<Anchor, _>>();
11007
11008        cursors.into_iter().collect()
11009    }
11010
11011    pub fn enable_breakpoint(
11012        &mut self,
11013        _: &crate::actions::EnableBreakpoint,
11014        window: &mut Window,
11015        cx: &mut Context<Self>,
11016    ) {
11017        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11018            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11019                continue;
11020            };
11021            self.edit_breakpoint_at_anchor(
11022                anchor,
11023                breakpoint,
11024                BreakpointEditAction::InvertState,
11025                cx,
11026            );
11027        }
11028    }
11029
11030    pub fn disable_breakpoint(
11031        &mut self,
11032        _: &crate::actions::DisableBreakpoint,
11033        window: &mut Window,
11034        cx: &mut Context<Self>,
11035    ) {
11036        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11037            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11038                continue;
11039            };
11040            self.edit_breakpoint_at_anchor(
11041                anchor,
11042                breakpoint,
11043                BreakpointEditAction::InvertState,
11044                cx,
11045            );
11046        }
11047    }
11048
11049    pub fn toggle_breakpoint(
11050        &mut self,
11051        _: &crate::actions::ToggleBreakpoint,
11052        window: &mut Window,
11053        cx: &mut Context<Self>,
11054    ) {
11055        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11056            if let Some(breakpoint) = breakpoint {
11057                self.edit_breakpoint_at_anchor(
11058                    anchor,
11059                    breakpoint,
11060                    BreakpointEditAction::Toggle,
11061                    cx,
11062                );
11063            } else {
11064                self.edit_breakpoint_at_anchor(
11065                    anchor,
11066                    Breakpoint::new_standard(),
11067                    BreakpointEditAction::Toggle,
11068                    cx,
11069                );
11070            }
11071        }
11072    }
11073
11074    pub fn edit_breakpoint_at_anchor(
11075        &mut self,
11076        breakpoint_position: Anchor,
11077        breakpoint: Breakpoint,
11078        edit_action: BreakpointEditAction,
11079        cx: &mut Context<Self>,
11080    ) {
11081        let Some(breakpoint_store) = &self.breakpoint_store else {
11082            return;
11083        };
11084
11085        let Some(buffer) = self
11086            .buffer
11087            .read(cx)
11088            .buffer_for_anchor(breakpoint_position, cx)
11089        else {
11090            return;
11091        };
11092
11093        breakpoint_store.update(cx, |breakpoint_store, cx| {
11094            breakpoint_store.toggle_breakpoint(
11095                buffer,
11096                BreakpointWithPosition {
11097                    position: breakpoint_position.text_anchor,
11098                    bp: breakpoint,
11099                },
11100                edit_action,
11101                cx,
11102            );
11103        });
11104
11105        cx.notify();
11106    }
11107
11108    #[cfg(any(test, feature = "test-support"))]
11109    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11110        self.breakpoint_store.clone()
11111    }
11112
11113    pub fn prepare_restore_change(
11114        &self,
11115        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11116        hunk: &MultiBufferDiffHunk,
11117        cx: &mut App,
11118    ) -> Option<()> {
11119        if hunk.is_created_file() {
11120            return None;
11121        }
11122        let buffer = self.buffer.read(cx);
11123        let diff = buffer.diff_for(hunk.buffer_id)?;
11124        let buffer = buffer.buffer(hunk.buffer_id)?;
11125        let buffer = buffer.read(cx);
11126        let original_text = diff
11127            .read(cx)
11128            .base_text()
11129            .as_rope()
11130            .slice(hunk.diff_base_byte_range.clone());
11131        let buffer_snapshot = buffer.snapshot();
11132        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11133        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11134            probe
11135                .0
11136                .start
11137                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11138                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11139        }) {
11140            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11141            Some(())
11142        } else {
11143            None
11144        }
11145    }
11146
11147    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11148        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11149    }
11150
11151    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11152        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11153    }
11154
11155    fn manipulate_lines<M>(
11156        &mut self,
11157        window: &mut Window,
11158        cx: &mut Context<Self>,
11159        mut manipulate: M,
11160    ) where
11161        M: FnMut(&str) -> LineManipulationResult,
11162    {
11163        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11164
11165        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11166        let buffer = self.buffer.read(cx).snapshot(cx);
11167
11168        let mut edits = Vec::new();
11169
11170        let selections = self.selections.all::<Point>(cx);
11171        let mut selections = selections.iter().peekable();
11172        let mut contiguous_row_selections = Vec::new();
11173        let mut new_selections = Vec::new();
11174        let mut added_lines = 0;
11175        let mut removed_lines = 0;
11176
11177        while let Some(selection) = selections.next() {
11178            let (start_row, end_row) = consume_contiguous_rows(
11179                &mut contiguous_row_selections,
11180                selection,
11181                &display_map,
11182                &mut selections,
11183            );
11184
11185            let start_point = Point::new(start_row.0, 0);
11186            let end_point = Point::new(
11187                end_row.previous_row().0,
11188                buffer.line_len(end_row.previous_row()),
11189            );
11190            let text = buffer
11191                .text_for_range(start_point..end_point)
11192                .collect::<String>();
11193
11194            let LineManipulationResult {
11195                new_text,
11196                line_count_before,
11197                line_count_after,
11198            } = manipulate(&text);
11199
11200            edits.push((start_point..end_point, new_text));
11201
11202            // Selections must change based on added and removed line count
11203            let start_row =
11204                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11205            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11206            new_selections.push(Selection {
11207                id: selection.id,
11208                start: start_row,
11209                end: end_row,
11210                goal: SelectionGoal::None,
11211                reversed: selection.reversed,
11212            });
11213
11214            if line_count_after > line_count_before {
11215                added_lines += line_count_after - line_count_before;
11216            } else if line_count_before > line_count_after {
11217                removed_lines += line_count_before - line_count_after;
11218            }
11219        }
11220
11221        self.transact(window, cx, |this, window, cx| {
11222            let buffer = this.buffer.update(cx, |buffer, cx| {
11223                buffer.edit(edits, None, cx);
11224                buffer.snapshot(cx)
11225            });
11226
11227            // Recalculate offsets on newly edited buffer
11228            let new_selections = new_selections
11229                .iter()
11230                .map(|s| {
11231                    let start_point = Point::new(s.start.0, 0);
11232                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11233                    Selection {
11234                        id: s.id,
11235                        start: buffer.point_to_offset(start_point),
11236                        end: buffer.point_to_offset(end_point),
11237                        goal: s.goal,
11238                        reversed: s.reversed,
11239                    }
11240                })
11241                .collect();
11242
11243            this.change_selections(Default::default(), window, cx, |s| {
11244                s.select(new_selections);
11245            });
11246
11247            this.request_autoscroll(Autoscroll::fit(), cx);
11248        });
11249    }
11250
11251    fn manipulate_immutable_lines<Fn>(
11252        &mut self,
11253        window: &mut Window,
11254        cx: &mut Context<Self>,
11255        mut callback: Fn,
11256    ) where
11257        Fn: FnMut(&mut Vec<&str>),
11258    {
11259        self.manipulate_lines(window, cx, |text| {
11260            let mut lines: Vec<&str> = text.split('\n').collect();
11261            let line_count_before = lines.len();
11262
11263            callback(&mut lines);
11264
11265            LineManipulationResult {
11266                new_text: lines.join("\n"),
11267                line_count_before,
11268                line_count_after: lines.len(),
11269            }
11270        });
11271    }
11272
11273    fn manipulate_mutable_lines<Fn>(
11274        &mut self,
11275        window: &mut Window,
11276        cx: &mut Context<Self>,
11277        mut callback: Fn,
11278    ) where
11279        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11280    {
11281        self.manipulate_lines(window, cx, |text| {
11282            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11283            let line_count_before = lines.len();
11284
11285            callback(&mut lines);
11286
11287            LineManipulationResult {
11288                new_text: lines.join("\n"),
11289                line_count_before,
11290                line_count_after: lines.len(),
11291            }
11292        });
11293    }
11294
11295    pub fn convert_indentation_to_spaces(
11296        &mut self,
11297        _: &ConvertIndentationToSpaces,
11298        window: &mut Window,
11299        cx: &mut Context<Self>,
11300    ) {
11301        let settings = self.buffer.read(cx).language_settings(cx);
11302        let tab_size = settings.tab_size.get() as usize;
11303
11304        self.manipulate_mutable_lines(window, cx, |lines| {
11305            // Allocates a reasonably sized scratch buffer once for the whole loop
11306            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11307            // Avoids recomputing spaces that could be inserted many times
11308            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11309                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11310                .collect();
11311
11312            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11313                let mut chars = line.as_ref().chars();
11314                let mut col = 0;
11315                let mut changed = false;
11316
11317                for ch in chars.by_ref() {
11318                    match ch {
11319                        ' ' => {
11320                            reindented_line.push(' ');
11321                            col += 1;
11322                        }
11323                        '\t' => {
11324                            // \t are converted to spaces depending on the current column
11325                            let spaces_len = tab_size - (col % tab_size);
11326                            reindented_line.extend(&space_cache[spaces_len - 1]);
11327                            col += spaces_len;
11328                            changed = true;
11329                        }
11330                        _ => {
11331                            // If we dont append before break, the character is consumed
11332                            reindented_line.push(ch);
11333                            break;
11334                        }
11335                    }
11336                }
11337
11338                if !changed {
11339                    reindented_line.clear();
11340                    continue;
11341                }
11342                // Append the rest of the line and replace old reference with new one
11343                reindented_line.extend(chars);
11344                *line = Cow::Owned(reindented_line.clone());
11345                reindented_line.clear();
11346            }
11347        });
11348    }
11349
11350    pub fn convert_indentation_to_tabs(
11351        &mut self,
11352        _: &ConvertIndentationToTabs,
11353        window: &mut Window,
11354        cx: &mut Context<Self>,
11355    ) {
11356        let settings = self.buffer.read(cx).language_settings(cx);
11357        let tab_size = settings.tab_size.get() as usize;
11358
11359        self.manipulate_mutable_lines(window, cx, |lines| {
11360            // Allocates a reasonably sized buffer once for the whole loop
11361            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11362            // Avoids recomputing spaces that could be inserted many times
11363            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11364                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11365                .collect();
11366
11367            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11368                let mut chars = line.chars();
11369                let mut spaces_count = 0;
11370                let mut first_non_indent_char = None;
11371                let mut changed = false;
11372
11373                for ch in chars.by_ref() {
11374                    match ch {
11375                        ' ' => {
11376                            // Keep track of spaces. Append \t when we reach tab_size
11377                            spaces_count += 1;
11378                            changed = true;
11379                            if spaces_count == tab_size {
11380                                reindented_line.push('\t');
11381                                spaces_count = 0;
11382                            }
11383                        }
11384                        '\t' => {
11385                            reindented_line.push('\t');
11386                            spaces_count = 0;
11387                        }
11388                        _ => {
11389                            // Dont append it yet, we might have remaining spaces
11390                            first_non_indent_char = Some(ch);
11391                            break;
11392                        }
11393                    }
11394                }
11395
11396                if !changed {
11397                    reindented_line.clear();
11398                    continue;
11399                }
11400                // Remaining spaces that didn't make a full tab stop
11401                if spaces_count > 0 {
11402                    reindented_line.extend(&space_cache[spaces_count - 1]);
11403                }
11404                // If we consume an extra character that was not indentation, add it back
11405                if let Some(extra_char) = first_non_indent_char {
11406                    reindented_line.push(extra_char);
11407                }
11408                // Append the rest of the line and replace old reference with new one
11409                reindented_line.extend(chars);
11410                *line = Cow::Owned(reindented_line.clone());
11411                reindented_line.clear();
11412            }
11413        });
11414    }
11415
11416    pub fn convert_to_upper_case(
11417        &mut self,
11418        _: &ConvertToUpperCase,
11419        window: &mut Window,
11420        cx: &mut Context<Self>,
11421    ) {
11422        self.manipulate_text(window, cx, |text| text.to_uppercase())
11423    }
11424
11425    pub fn convert_to_lower_case(
11426        &mut self,
11427        _: &ConvertToLowerCase,
11428        window: &mut Window,
11429        cx: &mut Context<Self>,
11430    ) {
11431        self.manipulate_text(window, cx, |text| text.to_lowercase())
11432    }
11433
11434    pub fn convert_to_title_case(
11435        &mut self,
11436        _: &ConvertToTitleCase,
11437        window: &mut Window,
11438        cx: &mut Context<Self>,
11439    ) {
11440        self.manipulate_text(window, cx, |text| {
11441            text.split('\n')
11442                .map(|line| line.to_case(Case::Title))
11443                .join("\n")
11444        })
11445    }
11446
11447    pub fn convert_to_snake_case(
11448        &mut self,
11449        _: &ConvertToSnakeCase,
11450        window: &mut Window,
11451        cx: &mut Context<Self>,
11452    ) {
11453        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11454    }
11455
11456    pub fn convert_to_kebab_case(
11457        &mut self,
11458        _: &ConvertToKebabCase,
11459        window: &mut Window,
11460        cx: &mut Context<Self>,
11461    ) {
11462        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11463    }
11464
11465    pub fn convert_to_upper_camel_case(
11466        &mut self,
11467        _: &ConvertToUpperCamelCase,
11468        window: &mut Window,
11469        cx: &mut Context<Self>,
11470    ) {
11471        self.manipulate_text(window, cx, |text| {
11472            text.split('\n')
11473                .map(|line| line.to_case(Case::UpperCamel))
11474                .join("\n")
11475        })
11476    }
11477
11478    pub fn convert_to_lower_camel_case(
11479        &mut self,
11480        _: &ConvertToLowerCamelCase,
11481        window: &mut Window,
11482        cx: &mut Context<Self>,
11483    ) {
11484        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11485    }
11486
11487    pub fn convert_to_opposite_case(
11488        &mut self,
11489        _: &ConvertToOppositeCase,
11490        window: &mut Window,
11491        cx: &mut Context<Self>,
11492    ) {
11493        self.manipulate_text(window, cx, |text| {
11494            text.chars()
11495                .fold(String::with_capacity(text.len()), |mut t, c| {
11496                    if c.is_uppercase() {
11497                        t.extend(c.to_lowercase());
11498                    } else {
11499                        t.extend(c.to_uppercase());
11500                    }
11501                    t
11502                })
11503        })
11504    }
11505
11506    pub fn convert_to_sentence_case(
11507        &mut self,
11508        _: &ConvertToSentenceCase,
11509        window: &mut Window,
11510        cx: &mut Context<Self>,
11511    ) {
11512        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11513    }
11514
11515    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11516        self.manipulate_text(window, cx, |text| {
11517            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11518            if has_upper_case_characters {
11519                text.to_lowercase()
11520            } else {
11521                text.to_uppercase()
11522            }
11523        })
11524    }
11525
11526    pub fn convert_to_rot13(
11527        &mut self,
11528        _: &ConvertToRot13,
11529        window: &mut Window,
11530        cx: &mut Context<Self>,
11531    ) {
11532        self.manipulate_text(window, cx, |text| {
11533            text.chars()
11534                .map(|c| match c {
11535                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11536                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11537                    _ => c,
11538                })
11539                .collect()
11540        })
11541    }
11542
11543    pub fn convert_to_rot47(
11544        &mut self,
11545        _: &ConvertToRot47,
11546        window: &mut Window,
11547        cx: &mut Context<Self>,
11548    ) {
11549        self.manipulate_text(window, cx, |text| {
11550            text.chars()
11551                .map(|c| {
11552                    let code_point = c as u32;
11553                    if code_point >= 33 && code_point <= 126 {
11554                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11555                    }
11556                    c
11557                })
11558                .collect()
11559        })
11560    }
11561
11562    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11563    where
11564        Fn: FnMut(&str) -> String,
11565    {
11566        let buffer = self.buffer.read(cx).snapshot(cx);
11567
11568        let mut new_selections = Vec::new();
11569        let mut edits = Vec::new();
11570        let mut selection_adjustment = 0i32;
11571
11572        for selection in self.selections.all_adjusted(cx) {
11573            let selection_is_empty = selection.is_empty();
11574
11575            let (start, end) = if selection_is_empty {
11576                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11577                (word_range.start, word_range.end)
11578            } else {
11579                (
11580                    buffer.point_to_offset(selection.start),
11581                    buffer.point_to_offset(selection.end),
11582                )
11583            };
11584
11585            let text = buffer.text_for_range(start..end).collect::<String>();
11586            let old_length = text.len() as i32;
11587            let text = callback(&text);
11588
11589            new_selections.push(Selection {
11590                start: (start as i32 - selection_adjustment) as usize,
11591                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11592                goal: SelectionGoal::None,
11593                id: selection.id,
11594                reversed: selection.reversed,
11595            });
11596
11597            selection_adjustment += old_length - text.len() as i32;
11598
11599            edits.push((start..end, text));
11600        }
11601
11602        self.transact(window, cx, |this, window, cx| {
11603            this.buffer.update(cx, |buffer, cx| {
11604                buffer.edit(edits, None, cx);
11605            });
11606
11607            this.change_selections(Default::default(), window, cx, |s| {
11608                s.select(new_selections);
11609            });
11610
11611            this.request_autoscroll(Autoscroll::fit(), cx);
11612        });
11613    }
11614
11615    pub fn move_selection_on_drop(
11616        &mut self,
11617        selection: &Selection<Anchor>,
11618        target: DisplayPoint,
11619        is_cut: bool,
11620        window: &mut Window,
11621        cx: &mut Context<Self>,
11622    ) {
11623        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11624        let buffer = &display_map.buffer_snapshot;
11625        let mut edits = Vec::new();
11626        let insert_point = display_map
11627            .clip_point(target, Bias::Left)
11628            .to_point(&display_map);
11629        let text = buffer
11630            .text_for_range(selection.start..selection.end)
11631            .collect::<String>();
11632        if is_cut {
11633            edits.push(((selection.start..selection.end), String::new()));
11634        }
11635        let insert_anchor = buffer.anchor_before(insert_point);
11636        edits.push(((insert_anchor..insert_anchor), text));
11637        let last_edit_start = insert_anchor.bias_left(buffer);
11638        let last_edit_end = insert_anchor.bias_right(buffer);
11639        self.transact(window, cx, |this, window, cx| {
11640            this.buffer.update(cx, |buffer, cx| {
11641                buffer.edit(edits, None, cx);
11642            });
11643            this.change_selections(Default::default(), window, cx, |s| {
11644                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11645            });
11646        });
11647    }
11648
11649    pub fn clear_selection_drag_state(&mut self) {
11650        self.selection_drag_state = SelectionDragState::None;
11651    }
11652
11653    pub fn duplicate(
11654        &mut self,
11655        upwards: bool,
11656        whole_lines: bool,
11657        window: &mut Window,
11658        cx: &mut Context<Self>,
11659    ) {
11660        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11661
11662        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11663        let buffer = &display_map.buffer_snapshot;
11664        let selections = self.selections.all::<Point>(cx);
11665
11666        let mut edits = Vec::new();
11667        let mut selections_iter = selections.iter().peekable();
11668        while let Some(selection) = selections_iter.next() {
11669            let mut rows = selection.spanned_rows(false, &display_map);
11670            // duplicate line-wise
11671            if whole_lines || selection.start == selection.end {
11672                // Avoid duplicating the same lines twice.
11673                while let Some(next_selection) = selections_iter.peek() {
11674                    let next_rows = next_selection.spanned_rows(false, &display_map);
11675                    if next_rows.start < rows.end {
11676                        rows.end = next_rows.end;
11677                        selections_iter.next().unwrap();
11678                    } else {
11679                        break;
11680                    }
11681                }
11682
11683                // Copy the text from the selected row region and splice it either at the start
11684                // or end of the region.
11685                let start = Point::new(rows.start.0, 0);
11686                let end = Point::new(
11687                    rows.end.previous_row().0,
11688                    buffer.line_len(rows.end.previous_row()),
11689                );
11690                let text = buffer
11691                    .text_for_range(start..end)
11692                    .chain(Some("\n"))
11693                    .collect::<String>();
11694                let insert_location = if upwards {
11695                    Point::new(rows.end.0, 0)
11696                } else {
11697                    start
11698                };
11699                edits.push((insert_location..insert_location, text));
11700            } else {
11701                // duplicate character-wise
11702                let start = selection.start;
11703                let end = selection.end;
11704                let text = buffer.text_for_range(start..end).collect::<String>();
11705                edits.push((selection.end..selection.end, text));
11706            }
11707        }
11708
11709        self.transact(window, cx, |this, _, cx| {
11710            this.buffer.update(cx, |buffer, cx| {
11711                buffer.edit(edits, None, cx);
11712            });
11713
11714            this.request_autoscroll(Autoscroll::fit(), cx);
11715        });
11716    }
11717
11718    pub fn duplicate_line_up(
11719        &mut self,
11720        _: &DuplicateLineUp,
11721        window: &mut Window,
11722        cx: &mut Context<Self>,
11723    ) {
11724        self.duplicate(true, true, window, cx);
11725    }
11726
11727    pub fn duplicate_line_down(
11728        &mut self,
11729        _: &DuplicateLineDown,
11730        window: &mut Window,
11731        cx: &mut Context<Self>,
11732    ) {
11733        self.duplicate(false, true, window, cx);
11734    }
11735
11736    pub fn duplicate_selection(
11737        &mut self,
11738        _: &DuplicateSelection,
11739        window: &mut Window,
11740        cx: &mut Context<Self>,
11741    ) {
11742        self.duplicate(false, false, window, cx);
11743    }
11744
11745    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11746        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11747        if self.mode.is_single_line() {
11748            cx.propagate();
11749            return;
11750        }
11751
11752        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11753        let buffer = self.buffer.read(cx).snapshot(cx);
11754
11755        let mut edits = Vec::new();
11756        let mut unfold_ranges = Vec::new();
11757        let mut refold_creases = Vec::new();
11758
11759        let selections = self.selections.all::<Point>(cx);
11760        let mut selections = selections.iter().peekable();
11761        let mut contiguous_row_selections = Vec::new();
11762        let mut new_selections = Vec::new();
11763
11764        while let Some(selection) = selections.next() {
11765            // Find all the selections that span a contiguous row range
11766            let (start_row, end_row) = consume_contiguous_rows(
11767                &mut contiguous_row_selections,
11768                selection,
11769                &display_map,
11770                &mut selections,
11771            );
11772
11773            // Move the text spanned by the row range to be before the line preceding the row range
11774            if start_row.0 > 0 {
11775                let range_to_move = Point::new(
11776                    start_row.previous_row().0,
11777                    buffer.line_len(start_row.previous_row()),
11778                )
11779                    ..Point::new(
11780                        end_row.previous_row().0,
11781                        buffer.line_len(end_row.previous_row()),
11782                    );
11783                let insertion_point = display_map
11784                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11785                    .0;
11786
11787                // Don't move lines across excerpts
11788                if buffer
11789                    .excerpt_containing(insertion_point..range_to_move.end)
11790                    .is_some()
11791                {
11792                    let text = buffer
11793                        .text_for_range(range_to_move.clone())
11794                        .flat_map(|s| s.chars())
11795                        .skip(1)
11796                        .chain(['\n'])
11797                        .collect::<String>();
11798
11799                    edits.push((
11800                        buffer.anchor_after(range_to_move.start)
11801                            ..buffer.anchor_before(range_to_move.end),
11802                        String::new(),
11803                    ));
11804                    let insertion_anchor = buffer.anchor_after(insertion_point);
11805                    edits.push((insertion_anchor..insertion_anchor, text));
11806
11807                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11808
11809                    // Move selections up
11810                    new_selections.extend(contiguous_row_selections.drain(..).map(
11811                        |mut selection| {
11812                            selection.start.row -= row_delta;
11813                            selection.end.row -= row_delta;
11814                            selection
11815                        },
11816                    ));
11817
11818                    // Move folds up
11819                    unfold_ranges.push(range_to_move.clone());
11820                    for fold in display_map.folds_in_range(
11821                        buffer.anchor_before(range_to_move.start)
11822                            ..buffer.anchor_after(range_to_move.end),
11823                    ) {
11824                        let mut start = fold.range.start.to_point(&buffer);
11825                        let mut end = fold.range.end.to_point(&buffer);
11826                        start.row -= row_delta;
11827                        end.row -= row_delta;
11828                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11829                    }
11830                }
11831            }
11832
11833            // If we didn't move line(s), preserve the existing selections
11834            new_selections.append(&mut contiguous_row_selections);
11835        }
11836
11837        self.transact(window, cx, |this, window, cx| {
11838            this.unfold_ranges(&unfold_ranges, true, true, cx);
11839            this.buffer.update(cx, |buffer, cx| {
11840                for (range, text) in edits {
11841                    buffer.edit([(range, text)], None, cx);
11842                }
11843            });
11844            this.fold_creases(refold_creases, true, window, cx);
11845            this.change_selections(Default::default(), window, cx, |s| {
11846                s.select(new_selections);
11847            })
11848        });
11849    }
11850
11851    pub fn move_line_down(
11852        &mut self,
11853        _: &MoveLineDown,
11854        window: &mut Window,
11855        cx: &mut Context<Self>,
11856    ) {
11857        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11858        if self.mode.is_single_line() {
11859            cx.propagate();
11860            return;
11861        }
11862
11863        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11864        let buffer = self.buffer.read(cx).snapshot(cx);
11865
11866        let mut edits = Vec::new();
11867        let mut unfold_ranges = Vec::new();
11868        let mut refold_creases = Vec::new();
11869
11870        let selections = self.selections.all::<Point>(cx);
11871        let mut selections = selections.iter().peekable();
11872        let mut contiguous_row_selections = Vec::new();
11873        let mut new_selections = Vec::new();
11874
11875        while let Some(selection) = selections.next() {
11876            // Find all the selections that span a contiguous row range
11877            let (start_row, end_row) = consume_contiguous_rows(
11878                &mut contiguous_row_selections,
11879                selection,
11880                &display_map,
11881                &mut selections,
11882            );
11883
11884            // Move the text spanned by the row range to be after the last line of the row range
11885            if end_row.0 <= buffer.max_point().row {
11886                let range_to_move =
11887                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11888                let insertion_point = display_map
11889                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11890                    .0;
11891
11892                // Don't move lines across excerpt boundaries
11893                if buffer
11894                    .excerpt_containing(range_to_move.start..insertion_point)
11895                    .is_some()
11896                {
11897                    let mut text = String::from("\n");
11898                    text.extend(buffer.text_for_range(range_to_move.clone()));
11899                    text.pop(); // Drop trailing newline
11900                    edits.push((
11901                        buffer.anchor_after(range_to_move.start)
11902                            ..buffer.anchor_before(range_to_move.end),
11903                        String::new(),
11904                    ));
11905                    let insertion_anchor = buffer.anchor_after(insertion_point);
11906                    edits.push((insertion_anchor..insertion_anchor, text));
11907
11908                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11909
11910                    // Move selections down
11911                    new_selections.extend(contiguous_row_selections.drain(..).map(
11912                        |mut selection| {
11913                            selection.start.row += row_delta;
11914                            selection.end.row += row_delta;
11915                            selection
11916                        },
11917                    ));
11918
11919                    // Move folds down
11920                    unfold_ranges.push(range_to_move.clone());
11921                    for fold in display_map.folds_in_range(
11922                        buffer.anchor_before(range_to_move.start)
11923                            ..buffer.anchor_after(range_to_move.end),
11924                    ) {
11925                        let mut start = fold.range.start.to_point(&buffer);
11926                        let mut end = fold.range.end.to_point(&buffer);
11927                        start.row += row_delta;
11928                        end.row += row_delta;
11929                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11930                    }
11931                }
11932            }
11933
11934            // If we didn't move line(s), preserve the existing selections
11935            new_selections.append(&mut contiguous_row_selections);
11936        }
11937
11938        self.transact(window, cx, |this, window, cx| {
11939            this.unfold_ranges(&unfold_ranges, true, true, cx);
11940            this.buffer.update(cx, |buffer, cx| {
11941                for (range, text) in edits {
11942                    buffer.edit([(range, text)], None, cx);
11943                }
11944            });
11945            this.fold_creases(refold_creases, true, window, cx);
11946            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11947        });
11948    }
11949
11950    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11951        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11952        let text_layout_details = &self.text_layout_details(window);
11953        self.transact(window, cx, |this, window, cx| {
11954            let edits = this.change_selections(Default::default(), window, cx, |s| {
11955                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11956                s.move_with(|display_map, selection| {
11957                    if !selection.is_empty() {
11958                        return;
11959                    }
11960
11961                    let mut head = selection.head();
11962                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11963                    if head.column() == display_map.line_len(head.row()) {
11964                        transpose_offset = display_map
11965                            .buffer_snapshot
11966                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11967                    }
11968
11969                    if transpose_offset == 0 {
11970                        return;
11971                    }
11972
11973                    *head.column_mut() += 1;
11974                    head = display_map.clip_point(head, Bias::Right);
11975                    let goal = SelectionGoal::HorizontalPosition(
11976                        display_map
11977                            .x_for_display_point(head, text_layout_details)
11978                            .into(),
11979                    );
11980                    selection.collapse_to(head, goal);
11981
11982                    let transpose_start = display_map
11983                        .buffer_snapshot
11984                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11985                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11986                        let transpose_end = display_map
11987                            .buffer_snapshot
11988                            .clip_offset(transpose_offset + 1, Bias::Right);
11989                        if let Some(ch) =
11990                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11991                        {
11992                            edits.push((transpose_start..transpose_offset, String::new()));
11993                            edits.push((transpose_end..transpose_end, ch.to_string()));
11994                        }
11995                    }
11996                });
11997                edits
11998            });
11999            this.buffer
12000                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12001            let selections = this.selections.all::<usize>(cx);
12002            this.change_selections(Default::default(), window, cx, |s| {
12003                s.select(selections);
12004            });
12005        });
12006    }
12007
12008    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12009        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12010        if self.mode.is_single_line() {
12011            cx.propagate();
12012            return;
12013        }
12014
12015        self.rewrap_impl(RewrapOptions::default(), cx)
12016    }
12017
12018    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12019        let buffer = self.buffer.read(cx).snapshot(cx);
12020        let selections = self.selections.all::<Point>(cx);
12021
12022        #[derive(Clone, Debug, PartialEq)]
12023        enum CommentFormat {
12024            /// single line comment, with prefix for line
12025            Line(String),
12026            /// single line within a block comment, with prefix for line
12027            BlockLine(String),
12028            /// a single line of a block comment that includes the initial delimiter
12029            BlockCommentWithStart(BlockCommentConfig),
12030            /// a single line of a block comment that includes the ending delimiter
12031            BlockCommentWithEnd(BlockCommentConfig),
12032        }
12033
12034        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12035        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12036            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12037                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12038                .peekable();
12039
12040            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12041                row
12042            } else {
12043                return Vec::new();
12044            };
12045
12046            let language_settings = buffer.language_settings_at(selection.head(), cx);
12047            let language_scope = buffer.language_scope_at(selection.head());
12048
12049            let indent_and_prefix_for_row =
12050                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12051                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12052                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12053                        &language_scope
12054                    {
12055                        let indent_end = Point::new(row, indent.len);
12056                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12057                        let line_text_after_indent = buffer
12058                            .text_for_range(indent_end..line_end)
12059                            .collect::<String>();
12060
12061                        let is_within_comment_override = buffer
12062                            .language_scope_at(indent_end)
12063                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12064                        let comment_delimiters = if is_within_comment_override {
12065                            // we are within a comment syntax node, but we don't
12066                            // yet know what kind of comment: block, doc or line
12067                            match (
12068                                language_scope.documentation_comment(),
12069                                language_scope.block_comment(),
12070                            ) {
12071                                (Some(config), _) | (_, Some(config))
12072                                    if buffer.contains_str_at(indent_end, &config.start) =>
12073                                {
12074                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12075                                }
12076                                (Some(config), _) | (_, Some(config))
12077                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12078                                {
12079                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12080                                }
12081                                (Some(config), _) | (_, Some(config))
12082                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12083                                {
12084                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12085                                }
12086                                (_, _) => language_scope
12087                                    .line_comment_prefixes()
12088                                    .iter()
12089                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12090                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12091                            }
12092                        } else {
12093                            // we not in an overridden comment node, but we may
12094                            // be within a non-overridden line comment node
12095                            language_scope
12096                                .line_comment_prefixes()
12097                                .iter()
12098                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12099                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12100                        };
12101
12102                        let rewrap_prefix = language_scope
12103                            .rewrap_prefixes()
12104                            .iter()
12105                            .find_map(|prefix_regex| {
12106                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12107                                    if mat.start() == 0 {
12108                                        Some(mat.as_str().to_string())
12109                                    } else {
12110                                        None
12111                                    }
12112                                })
12113                            })
12114                            .flatten();
12115                        (comment_delimiters, rewrap_prefix)
12116                    } else {
12117                        (None, None)
12118                    };
12119                    (indent, comment_prefix, rewrap_prefix)
12120                };
12121
12122            let mut ranges = Vec::new();
12123            let from_empty_selection = selection.is_empty();
12124
12125            let mut current_range_start = first_row;
12126            let mut prev_row = first_row;
12127            let (
12128                mut current_range_indent,
12129                mut current_range_comment_delimiters,
12130                mut current_range_rewrap_prefix,
12131            ) = indent_and_prefix_for_row(first_row);
12132
12133            for row in non_blank_rows_iter.skip(1) {
12134                let has_paragraph_break = row > prev_row + 1;
12135
12136                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12137                    indent_and_prefix_for_row(row);
12138
12139                let has_indent_change = row_indent != current_range_indent;
12140                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12141
12142                let has_boundary_change = has_comment_change
12143                    || row_rewrap_prefix.is_some()
12144                    || (has_indent_change && current_range_comment_delimiters.is_some());
12145
12146                if has_paragraph_break || has_boundary_change {
12147                    ranges.push((
12148                        language_settings.clone(),
12149                        Point::new(current_range_start, 0)
12150                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12151                        current_range_indent,
12152                        current_range_comment_delimiters.clone(),
12153                        current_range_rewrap_prefix.clone(),
12154                        from_empty_selection,
12155                    ));
12156                    current_range_start = row;
12157                    current_range_indent = row_indent;
12158                    current_range_comment_delimiters = row_comment_delimiters;
12159                    current_range_rewrap_prefix = row_rewrap_prefix;
12160                }
12161                prev_row = row;
12162            }
12163
12164            ranges.push((
12165                language_settings.clone(),
12166                Point::new(current_range_start, 0)
12167                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12168                current_range_indent,
12169                current_range_comment_delimiters,
12170                current_range_rewrap_prefix,
12171                from_empty_selection,
12172            ));
12173
12174            ranges
12175        });
12176
12177        let mut edits = Vec::new();
12178        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12179
12180        for (
12181            language_settings,
12182            wrap_range,
12183            mut indent_size,
12184            comment_prefix,
12185            rewrap_prefix,
12186            from_empty_selection,
12187        ) in wrap_ranges
12188        {
12189            let mut start_row = wrap_range.start.row;
12190            let mut end_row = wrap_range.end.row;
12191
12192            // Skip selections that overlap with a range that has already been rewrapped.
12193            let selection_range = start_row..end_row;
12194            if rewrapped_row_ranges
12195                .iter()
12196                .any(|range| range.overlaps(&selection_range))
12197            {
12198                continue;
12199            }
12200
12201            let tab_size = language_settings.tab_size;
12202
12203            let (line_prefix, inside_comment) = match &comment_prefix {
12204                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12205                    (Some(prefix.as_str()), true)
12206                }
12207                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12208                    (Some(prefix.as_ref()), true)
12209                }
12210                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12211                    start: _,
12212                    end: _,
12213                    prefix,
12214                    tab_size,
12215                })) => {
12216                    indent_size.len += tab_size;
12217                    (Some(prefix.as_ref()), true)
12218                }
12219                None => (None, false),
12220            };
12221            let indent_prefix = indent_size.chars().collect::<String>();
12222            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12223
12224            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12225                RewrapBehavior::InComments => inside_comment,
12226                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12227                RewrapBehavior::Anywhere => true,
12228            };
12229
12230            let should_rewrap = options.override_language_settings
12231                || allow_rewrap_based_on_language
12232                || self.hard_wrap.is_some();
12233            if !should_rewrap {
12234                continue;
12235            }
12236
12237            if from_empty_selection {
12238                'expand_upwards: while start_row > 0 {
12239                    let prev_row = start_row - 1;
12240                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12241                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12242                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12243                    {
12244                        start_row = prev_row;
12245                    } else {
12246                        break 'expand_upwards;
12247                    }
12248                }
12249
12250                'expand_downwards: while end_row < buffer.max_point().row {
12251                    let next_row = end_row + 1;
12252                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12253                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12254                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12255                    {
12256                        end_row = next_row;
12257                    } else {
12258                        break 'expand_downwards;
12259                    }
12260                }
12261            }
12262
12263            let start = Point::new(start_row, 0);
12264            let start_offset = start.to_offset(&buffer);
12265            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12266            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12267            let mut first_line_delimiter = None;
12268            let mut last_line_delimiter = None;
12269            let Some(lines_without_prefixes) = selection_text
12270                .lines()
12271                .enumerate()
12272                .map(|(ix, line)| {
12273                    let line_trimmed = line.trim_start();
12274                    if rewrap_prefix.is_some() && ix > 0 {
12275                        Ok(line_trimmed)
12276                    } else if let Some(
12277                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12278                            start,
12279                            prefix,
12280                            end,
12281                            tab_size,
12282                        })
12283                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12284                            start,
12285                            prefix,
12286                            end,
12287                            tab_size,
12288                        }),
12289                    ) = &comment_prefix
12290                    {
12291                        let line_trimmed = line_trimmed
12292                            .strip_prefix(start.as_ref())
12293                            .map(|s| {
12294                                let mut indent_size = indent_size;
12295                                indent_size.len -= tab_size;
12296                                let indent_prefix: String = indent_size.chars().collect();
12297                                first_line_delimiter = Some((indent_prefix, start));
12298                                s.trim_start()
12299                            })
12300                            .unwrap_or(line_trimmed);
12301                        let line_trimmed = line_trimmed
12302                            .strip_suffix(end.as_ref())
12303                            .map(|s| {
12304                                last_line_delimiter = Some(end);
12305                                s.trim_end()
12306                            })
12307                            .unwrap_or(line_trimmed);
12308                        let line_trimmed = line_trimmed
12309                            .strip_prefix(prefix.as_ref())
12310                            .unwrap_or(line_trimmed);
12311                        Ok(line_trimmed)
12312                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12313                        line_trimmed.strip_prefix(prefix).with_context(|| {
12314                            format!("line did not start with prefix {prefix:?}: {line:?}")
12315                        })
12316                    } else {
12317                        line_trimmed
12318                            .strip_prefix(&line_prefix.trim_start())
12319                            .with_context(|| {
12320                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12321                            })
12322                    }
12323                })
12324                .collect::<Result<Vec<_>, _>>()
12325                .log_err()
12326            else {
12327                continue;
12328            };
12329
12330            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12331                buffer
12332                    .language_settings_at(Point::new(start_row, 0), cx)
12333                    .preferred_line_length as usize
12334            });
12335
12336            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12337                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12338            } else {
12339                line_prefix.clone()
12340            };
12341
12342            let wrapped_text = {
12343                let mut wrapped_text = wrap_with_prefix(
12344                    line_prefix,
12345                    subsequent_lines_prefix,
12346                    lines_without_prefixes.join("\n"),
12347                    wrap_column,
12348                    tab_size,
12349                    options.preserve_existing_whitespace,
12350                );
12351
12352                if let Some((indent, delimiter)) = first_line_delimiter {
12353                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12354                }
12355                if let Some(last_line) = last_line_delimiter {
12356                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12357                }
12358
12359                wrapped_text
12360            };
12361
12362            // TODO: should always use char-based diff while still supporting cursor behavior that
12363            // matches vim.
12364            let mut diff_options = DiffOptions::default();
12365            if options.override_language_settings {
12366                diff_options.max_word_diff_len = 0;
12367                diff_options.max_word_diff_line_count = 0;
12368            } else {
12369                diff_options.max_word_diff_len = usize::MAX;
12370                diff_options.max_word_diff_line_count = usize::MAX;
12371            }
12372
12373            for (old_range, new_text) in
12374                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12375            {
12376                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12377                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12378                edits.push((edit_start..edit_end, new_text));
12379            }
12380
12381            rewrapped_row_ranges.push(start_row..=end_row);
12382        }
12383
12384        self.buffer
12385            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12386    }
12387
12388    pub fn cut_common(
12389        &mut self,
12390        cut_no_selection_line: bool,
12391        window: &mut Window,
12392        cx: &mut Context<Self>,
12393    ) -> ClipboardItem {
12394        let mut text = String::new();
12395        let buffer = self.buffer.read(cx).snapshot(cx);
12396        let mut selections = self.selections.all::<Point>(cx);
12397        let mut clipboard_selections = Vec::with_capacity(selections.len());
12398        {
12399            let max_point = buffer.max_point();
12400            let mut is_first = true;
12401            for selection in &mut selections {
12402                let is_entire_line =
12403                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12404                if is_entire_line {
12405                    selection.start = Point::new(selection.start.row, 0);
12406                    if !selection.is_empty() && selection.end.column == 0 {
12407                        selection.end = cmp::min(max_point, selection.end);
12408                    } else {
12409                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12410                    }
12411                    selection.goal = SelectionGoal::None;
12412                }
12413                if is_first {
12414                    is_first = false;
12415                } else {
12416                    text += "\n";
12417                }
12418                let mut len = 0;
12419                for chunk in buffer.text_for_range(selection.start..selection.end) {
12420                    text.push_str(chunk);
12421                    len += chunk.len();
12422                }
12423                clipboard_selections.push(ClipboardSelection {
12424                    len,
12425                    is_entire_line,
12426                    first_line_indent: buffer
12427                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12428                        .len,
12429                });
12430            }
12431        }
12432
12433        self.transact(window, cx, |this, window, cx| {
12434            this.change_selections(Default::default(), window, cx, |s| {
12435                s.select(selections);
12436            });
12437            this.insert("", window, cx);
12438        });
12439        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12440    }
12441
12442    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12443        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12444        let item = self.cut_common(true, window, cx);
12445        cx.write_to_clipboard(item);
12446    }
12447
12448    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12449        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12450        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12451            s.move_with(|snapshot, sel| {
12452                if sel.is_empty() {
12453                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12454                }
12455                if sel.is_empty() {
12456                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12457                }
12458            });
12459        });
12460        let item = self.cut_common(false, window, cx);
12461        cx.set_global(KillRing(item))
12462    }
12463
12464    pub fn kill_ring_yank(
12465        &mut self,
12466        _: &KillRingYank,
12467        window: &mut Window,
12468        cx: &mut Context<Self>,
12469    ) {
12470        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12471        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12472            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12473                (kill_ring.text().to_string(), kill_ring.metadata_json())
12474            } else {
12475                return;
12476            }
12477        } else {
12478            return;
12479        };
12480        self.do_paste(&text, metadata, false, window, cx);
12481    }
12482
12483    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12484        self.do_copy(true, cx);
12485    }
12486
12487    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12488        self.do_copy(false, cx);
12489    }
12490
12491    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12492        let selections = self.selections.all::<Point>(cx);
12493        let buffer = self.buffer.read(cx).read(cx);
12494        let mut text = String::new();
12495
12496        let mut clipboard_selections = Vec::with_capacity(selections.len());
12497        {
12498            let max_point = buffer.max_point();
12499            let mut is_first = true;
12500            for selection in &selections {
12501                let mut start = selection.start;
12502                let mut end = selection.end;
12503                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12504                if is_entire_line {
12505                    start = Point::new(start.row, 0);
12506                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12507                }
12508
12509                let mut trimmed_selections = Vec::new();
12510                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12511                    let row = MultiBufferRow(start.row);
12512                    let first_indent = buffer.indent_size_for_line(row);
12513                    if first_indent.len == 0 || start.column > first_indent.len {
12514                        trimmed_selections.push(start..end);
12515                    } else {
12516                        trimmed_selections.push(
12517                            Point::new(row.0, first_indent.len)
12518                                ..Point::new(row.0, buffer.line_len(row)),
12519                        );
12520                        for row in start.row + 1..=end.row {
12521                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12522                            if row == end.row {
12523                                line_len = end.column;
12524                            }
12525                            if line_len == 0 {
12526                                trimmed_selections
12527                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12528                                continue;
12529                            }
12530                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12531                            if row_indent_size.len >= first_indent.len {
12532                                trimmed_selections.push(
12533                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12534                                );
12535                            } else {
12536                                trimmed_selections.clear();
12537                                trimmed_selections.push(start..end);
12538                                break;
12539                            }
12540                        }
12541                    }
12542                } else {
12543                    trimmed_selections.push(start..end);
12544                }
12545
12546                for trimmed_range in trimmed_selections {
12547                    if is_first {
12548                        is_first = false;
12549                    } else {
12550                        text += "\n";
12551                    }
12552                    let mut len = 0;
12553                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12554                        text.push_str(chunk);
12555                        len += chunk.len();
12556                    }
12557                    clipboard_selections.push(ClipboardSelection {
12558                        len,
12559                        is_entire_line,
12560                        first_line_indent: buffer
12561                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12562                            .len,
12563                    });
12564                }
12565            }
12566        }
12567
12568        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12569            text,
12570            clipboard_selections,
12571        ));
12572    }
12573
12574    pub fn do_paste(
12575        &mut self,
12576        text: &String,
12577        clipboard_selections: Option<Vec<ClipboardSelection>>,
12578        handle_entire_lines: bool,
12579        window: &mut Window,
12580        cx: &mut Context<Self>,
12581    ) {
12582        if self.read_only(cx) {
12583            return;
12584        }
12585
12586        let clipboard_text = Cow::Borrowed(text.as_str());
12587
12588        self.transact(window, cx, |this, window, cx| {
12589            let had_active_edit_prediction = this.has_active_edit_prediction();
12590            let old_selections = this.selections.all::<usize>(cx);
12591            let cursor_offset = this.selections.last::<usize>(cx).head();
12592
12593            if let Some(mut clipboard_selections) = clipboard_selections {
12594                let all_selections_were_entire_line =
12595                    clipboard_selections.iter().all(|s| s.is_entire_line);
12596                let first_selection_indent_column =
12597                    clipboard_selections.first().map(|s| s.first_line_indent);
12598                if clipboard_selections.len() != old_selections.len() {
12599                    clipboard_selections.drain(..);
12600                }
12601                let mut auto_indent_on_paste = true;
12602
12603                this.buffer.update(cx, |buffer, cx| {
12604                    let snapshot = buffer.read(cx);
12605                    auto_indent_on_paste = snapshot
12606                        .language_settings_at(cursor_offset, cx)
12607                        .auto_indent_on_paste;
12608
12609                    let mut start_offset = 0;
12610                    let mut edits = Vec::new();
12611                    let mut original_indent_columns = Vec::new();
12612                    for (ix, selection) in old_selections.iter().enumerate() {
12613                        let to_insert;
12614                        let entire_line;
12615                        let original_indent_column;
12616                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12617                            let end_offset = start_offset + clipboard_selection.len;
12618                            to_insert = &clipboard_text[start_offset..end_offset];
12619                            entire_line = clipboard_selection.is_entire_line;
12620                            start_offset = end_offset + 1;
12621                            original_indent_column = Some(clipboard_selection.first_line_indent);
12622                        } else {
12623                            to_insert = &*clipboard_text;
12624                            entire_line = all_selections_were_entire_line;
12625                            original_indent_column = first_selection_indent_column
12626                        }
12627
12628                        let (range, to_insert) =
12629                            if selection.is_empty() && handle_entire_lines && entire_line {
12630                                // If the corresponding selection was empty when this slice of the
12631                                // clipboard text was written, then the entire line containing the
12632                                // selection was copied. If this selection is also currently empty,
12633                                // then paste the line before the current line of the buffer.
12634                                let column = selection.start.to_point(&snapshot).column as usize;
12635                                let line_start = selection.start - column;
12636                                (line_start..line_start, Cow::Borrowed(to_insert))
12637                            } else {
12638                                let language = snapshot.language_at(selection.head());
12639                                let range = selection.range();
12640                                if let Some(language) = language
12641                                    && language.name() == "Markdown".into()
12642                                {
12643                                    edit_for_markdown_paste(
12644                                        &snapshot,
12645                                        range,
12646                                        to_insert,
12647                                        url::Url::parse(to_insert).ok(),
12648                                    )
12649                                } else {
12650                                    (range, Cow::Borrowed(to_insert))
12651                                }
12652                            };
12653
12654                        edits.push((range, to_insert));
12655                        original_indent_columns.push(original_indent_column);
12656                    }
12657                    drop(snapshot);
12658
12659                    buffer.edit(
12660                        edits,
12661                        if auto_indent_on_paste {
12662                            Some(AutoindentMode::Block {
12663                                original_indent_columns,
12664                            })
12665                        } else {
12666                            None
12667                        },
12668                        cx,
12669                    );
12670                });
12671
12672                let selections = this.selections.all::<usize>(cx);
12673                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12674            } else {
12675                let url = url::Url::parse(&clipboard_text).ok();
12676
12677                let auto_indent_mode = if !clipboard_text.is_empty() {
12678                    Some(AutoindentMode::Block {
12679                        original_indent_columns: Vec::new(),
12680                    })
12681                } else {
12682                    None
12683                };
12684
12685                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12686                    let snapshot = buffer.snapshot(cx);
12687
12688                    let anchors = old_selections
12689                        .iter()
12690                        .map(|s| {
12691                            let anchor = snapshot.anchor_after(s.head());
12692                            s.map(|_| anchor)
12693                        })
12694                        .collect::<Vec<_>>();
12695
12696                    let mut edits = Vec::new();
12697
12698                    for selection in old_selections.iter() {
12699                        let language = snapshot.language_at(selection.head());
12700                        let range = selection.range();
12701
12702                        let (edit_range, edit_text) = if let Some(language) = language
12703                            && language.name() == "Markdown".into()
12704                        {
12705                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12706                        } else {
12707                            (range, clipboard_text.clone())
12708                        };
12709
12710                        edits.push((edit_range, edit_text));
12711                    }
12712
12713                    drop(snapshot);
12714                    buffer.edit(edits, auto_indent_mode, cx);
12715
12716                    anchors
12717                });
12718
12719                this.change_selections(Default::default(), window, cx, |s| {
12720                    s.select_anchors(selection_anchors);
12721                });
12722            }
12723
12724            let trigger_in_words =
12725                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12726
12727            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12728        });
12729    }
12730
12731    pub fn diff_clipboard_with_selection(
12732        &mut self,
12733        _: &DiffClipboardWithSelection,
12734        window: &mut Window,
12735        cx: &mut Context<Self>,
12736    ) {
12737        let selections = self.selections.all::<usize>(cx);
12738
12739        if selections.is_empty() {
12740            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12741            return;
12742        };
12743
12744        let clipboard_text = match cx.read_from_clipboard() {
12745            Some(item) => match item.entries().first() {
12746                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12747                _ => None,
12748            },
12749            None => None,
12750        };
12751
12752        let Some(clipboard_text) = clipboard_text else {
12753            log::warn!("Clipboard doesn't contain text.");
12754            return;
12755        };
12756
12757        window.dispatch_action(
12758            Box::new(DiffClipboardWithSelectionData {
12759                clipboard_text,
12760                editor: cx.entity(),
12761            }),
12762            cx,
12763        );
12764    }
12765
12766    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12767        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12768        if let Some(item) = cx.read_from_clipboard() {
12769            let entries = item.entries();
12770
12771            match entries.first() {
12772                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12773                // of all the pasted entries.
12774                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12775                    .do_paste(
12776                        clipboard_string.text(),
12777                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12778                        true,
12779                        window,
12780                        cx,
12781                    ),
12782                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12783            }
12784        }
12785    }
12786
12787    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12788        if self.read_only(cx) {
12789            return;
12790        }
12791
12792        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12793
12794        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12795            if let Some((selections, _)) =
12796                self.selection_history.transaction(transaction_id).cloned()
12797            {
12798                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12799                    s.select_anchors(selections.to_vec());
12800                });
12801            } else {
12802                log::error!(
12803                    "No entry in selection_history found for undo. \
12804                     This may correspond to a bug where undo does not update the selection. \
12805                     If this is occurring, please add details to \
12806                     https://github.com/zed-industries/zed/issues/22692"
12807                );
12808            }
12809            self.request_autoscroll(Autoscroll::fit(), cx);
12810            self.unmark_text(window, cx);
12811            self.refresh_edit_prediction(true, false, window, cx);
12812            cx.emit(EditorEvent::Edited { transaction_id });
12813            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12814        }
12815    }
12816
12817    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12818        if self.read_only(cx) {
12819            return;
12820        }
12821
12822        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12823
12824        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12825            if let Some((_, Some(selections))) =
12826                self.selection_history.transaction(transaction_id).cloned()
12827            {
12828                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12829                    s.select_anchors(selections.to_vec());
12830                });
12831            } else {
12832                log::error!(
12833                    "No entry in selection_history found for redo. \
12834                     This may correspond to a bug where undo does not update the selection. \
12835                     If this is occurring, please add details to \
12836                     https://github.com/zed-industries/zed/issues/22692"
12837                );
12838            }
12839            self.request_autoscroll(Autoscroll::fit(), cx);
12840            self.unmark_text(window, cx);
12841            self.refresh_edit_prediction(true, false, window, cx);
12842            cx.emit(EditorEvent::Edited { transaction_id });
12843        }
12844    }
12845
12846    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12847        self.buffer
12848            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12849    }
12850
12851    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12852        self.buffer
12853            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12854    }
12855
12856    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12858        self.change_selections(Default::default(), window, cx, |s| {
12859            s.move_with(|map, selection| {
12860                let cursor = if selection.is_empty() {
12861                    movement::left(map, selection.start)
12862                } else {
12863                    selection.start
12864                };
12865                selection.collapse_to(cursor, SelectionGoal::None);
12866            });
12867        })
12868    }
12869
12870    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12871        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12872        self.change_selections(Default::default(), window, cx, |s| {
12873            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12874        })
12875    }
12876
12877    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12878        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12879        self.change_selections(Default::default(), window, cx, |s| {
12880            s.move_with(|map, selection| {
12881                let cursor = if selection.is_empty() {
12882                    movement::right(map, selection.end)
12883                } else {
12884                    selection.end
12885                };
12886                selection.collapse_to(cursor, SelectionGoal::None)
12887            });
12888        })
12889    }
12890
12891    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12892        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12893        self.change_selections(Default::default(), window, cx, |s| {
12894            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12895        });
12896    }
12897
12898    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12899        if self.take_rename(true, window, cx).is_some() {
12900            return;
12901        }
12902
12903        if self.mode.is_single_line() {
12904            cx.propagate();
12905            return;
12906        }
12907
12908        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12909
12910        let text_layout_details = &self.text_layout_details(window);
12911        let selection_count = self.selections.count();
12912        let first_selection = self.selections.first_anchor();
12913
12914        self.change_selections(Default::default(), window, cx, |s| {
12915            s.move_with(|map, selection| {
12916                if !selection.is_empty() {
12917                    selection.goal = SelectionGoal::None;
12918                }
12919                let (cursor, goal) = movement::up(
12920                    map,
12921                    selection.start,
12922                    selection.goal,
12923                    false,
12924                    text_layout_details,
12925                );
12926                selection.collapse_to(cursor, goal);
12927            });
12928        });
12929
12930        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12931        {
12932            cx.propagate();
12933        }
12934    }
12935
12936    pub fn move_up_by_lines(
12937        &mut self,
12938        action: &MoveUpByLines,
12939        window: &mut Window,
12940        cx: &mut Context<Self>,
12941    ) {
12942        if self.take_rename(true, window, cx).is_some() {
12943            return;
12944        }
12945
12946        if self.mode.is_single_line() {
12947            cx.propagate();
12948            return;
12949        }
12950
12951        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12952
12953        let text_layout_details = &self.text_layout_details(window);
12954
12955        self.change_selections(Default::default(), window, cx, |s| {
12956            s.move_with(|map, selection| {
12957                if !selection.is_empty() {
12958                    selection.goal = SelectionGoal::None;
12959                }
12960                let (cursor, goal) = movement::up_by_rows(
12961                    map,
12962                    selection.start,
12963                    action.lines,
12964                    selection.goal,
12965                    false,
12966                    text_layout_details,
12967                );
12968                selection.collapse_to(cursor, goal);
12969            });
12970        })
12971    }
12972
12973    pub fn move_down_by_lines(
12974        &mut self,
12975        action: &MoveDownByLines,
12976        window: &mut Window,
12977        cx: &mut Context<Self>,
12978    ) {
12979        if self.take_rename(true, window, cx).is_some() {
12980            return;
12981        }
12982
12983        if self.mode.is_single_line() {
12984            cx.propagate();
12985            return;
12986        }
12987
12988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12989
12990        let text_layout_details = &self.text_layout_details(window);
12991
12992        self.change_selections(Default::default(), window, cx, |s| {
12993            s.move_with(|map, selection| {
12994                if !selection.is_empty() {
12995                    selection.goal = SelectionGoal::None;
12996                }
12997                let (cursor, goal) = movement::down_by_rows(
12998                    map,
12999                    selection.start,
13000                    action.lines,
13001                    selection.goal,
13002                    false,
13003                    text_layout_details,
13004                );
13005                selection.collapse_to(cursor, goal);
13006            });
13007        })
13008    }
13009
13010    pub fn select_down_by_lines(
13011        &mut self,
13012        action: &SelectDownByLines,
13013        window: &mut Window,
13014        cx: &mut Context<Self>,
13015    ) {
13016        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13017        let text_layout_details = &self.text_layout_details(window);
13018        self.change_selections(Default::default(), window, cx, |s| {
13019            s.move_heads_with(|map, head, goal| {
13020                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13021            })
13022        })
13023    }
13024
13025    pub fn select_up_by_lines(
13026        &mut self,
13027        action: &SelectUpByLines,
13028        window: &mut Window,
13029        cx: &mut Context<Self>,
13030    ) {
13031        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13032        let text_layout_details = &self.text_layout_details(window);
13033        self.change_selections(Default::default(), window, cx, |s| {
13034            s.move_heads_with(|map, head, goal| {
13035                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13036            })
13037        })
13038    }
13039
13040    pub fn select_page_up(
13041        &mut self,
13042        _: &SelectPageUp,
13043        window: &mut Window,
13044        cx: &mut Context<Self>,
13045    ) {
13046        let Some(row_count) = self.visible_row_count() else {
13047            return;
13048        };
13049
13050        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13051
13052        let text_layout_details = &self.text_layout_details(window);
13053
13054        self.change_selections(Default::default(), window, cx, |s| {
13055            s.move_heads_with(|map, head, goal| {
13056                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13057            })
13058        })
13059    }
13060
13061    pub fn move_page_up(
13062        &mut self,
13063        action: &MovePageUp,
13064        window: &mut Window,
13065        cx: &mut Context<Self>,
13066    ) {
13067        if self.take_rename(true, window, cx).is_some() {
13068            return;
13069        }
13070
13071        if self
13072            .context_menu
13073            .borrow_mut()
13074            .as_mut()
13075            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13076            .unwrap_or(false)
13077        {
13078            return;
13079        }
13080
13081        if matches!(self.mode, EditorMode::SingleLine) {
13082            cx.propagate();
13083            return;
13084        }
13085
13086        let Some(row_count) = self.visible_row_count() else {
13087            return;
13088        };
13089
13090        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13091
13092        let effects = if action.center_cursor {
13093            SelectionEffects::scroll(Autoscroll::center())
13094        } else {
13095            SelectionEffects::default()
13096        };
13097
13098        let text_layout_details = &self.text_layout_details(window);
13099
13100        self.change_selections(effects, window, cx, |s| {
13101            s.move_with(|map, selection| {
13102                if !selection.is_empty() {
13103                    selection.goal = SelectionGoal::None;
13104                }
13105                let (cursor, goal) = movement::up_by_rows(
13106                    map,
13107                    selection.end,
13108                    row_count,
13109                    selection.goal,
13110                    false,
13111                    text_layout_details,
13112                );
13113                selection.collapse_to(cursor, goal);
13114            });
13115        });
13116    }
13117
13118    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13119        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13120        let text_layout_details = &self.text_layout_details(window);
13121        self.change_selections(Default::default(), window, cx, |s| {
13122            s.move_heads_with(|map, head, goal| {
13123                movement::up(map, head, goal, false, text_layout_details)
13124            })
13125        })
13126    }
13127
13128    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13129        self.take_rename(true, window, cx);
13130
13131        if self.mode.is_single_line() {
13132            cx.propagate();
13133            return;
13134        }
13135
13136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13137
13138        let text_layout_details = &self.text_layout_details(window);
13139        let selection_count = self.selections.count();
13140        let first_selection = self.selections.first_anchor();
13141
13142        self.change_selections(Default::default(), window, cx, |s| {
13143            s.move_with(|map, selection| {
13144                if !selection.is_empty() {
13145                    selection.goal = SelectionGoal::None;
13146                }
13147                let (cursor, goal) = movement::down(
13148                    map,
13149                    selection.end,
13150                    selection.goal,
13151                    false,
13152                    text_layout_details,
13153                );
13154                selection.collapse_to(cursor, goal);
13155            });
13156        });
13157
13158        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13159        {
13160            cx.propagate();
13161        }
13162    }
13163
13164    pub fn select_page_down(
13165        &mut self,
13166        _: &SelectPageDown,
13167        window: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        let Some(row_count) = self.visible_row_count() else {
13171            return;
13172        };
13173
13174        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13175
13176        let text_layout_details = &self.text_layout_details(window);
13177
13178        self.change_selections(Default::default(), window, cx, |s| {
13179            s.move_heads_with(|map, head, goal| {
13180                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13181            })
13182        })
13183    }
13184
13185    pub fn move_page_down(
13186        &mut self,
13187        action: &MovePageDown,
13188        window: &mut Window,
13189        cx: &mut Context<Self>,
13190    ) {
13191        if self.take_rename(true, window, cx).is_some() {
13192            return;
13193        }
13194
13195        if self
13196            .context_menu
13197            .borrow_mut()
13198            .as_mut()
13199            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13200            .unwrap_or(false)
13201        {
13202            return;
13203        }
13204
13205        if matches!(self.mode, EditorMode::SingleLine) {
13206            cx.propagate();
13207            return;
13208        }
13209
13210        let Some(row_count) = self.visible_row_count() else {
13211            return;
13212        };
13213
13214        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13215
13216        let effects = if action.center_cursor {
13217            SelectionEffects::scroll(Autoscroll::center())
13218        } else {
13219            SelectionEffects::default()
13220        };
13221
13222        let text_layout_details = &self.text_layout_details(window);
13223        self.change_selections(effects, window, cx, |s| {
13224            s.move_with(|map, selection| {
13225                if !selection.is_empty() {
13226                    selection.goal = SelectionGoal::None;
13227                }
13228                let (cursor, goal) = movement::down_by_rows(
13229                    map,
13230                    selection.end,
13231                    row_count,
13232                    selection.goal,
13233                    false,
13234                    text_layout_details,
13235                );
13236                selection.collapse_to(cursor, goal);
13237            });
13238        });
13239    }
13240
13241    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13243        let text_layout_details = &self.text_layout_details(window);
13244        self.change_selections(Default::default(), window, cx, |s| {
13245            s.move_heads_with(|map, head, goal| {
13246                movement::down(map, head, goal, false, text_layout_details)
13247            })
13248        });
13249    }
13250
13251    pub fn context_menu_first(
13252        &mut self,
13253        _: &ContextMenuFirst,
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_first(self.completion_provider.as_deref(), window, cx);
13259        }
13260    }
13261
13262    pub fn context_menu_prev(
13263        &mut self,
13264        _: &ContextMenuPrevious,
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_prev(self.completion_provider.as_deref(), window, cx);
13270        }
13271    }
13272
13273    pub fn context_menu_next(
13274        &mut self,
13275        _: &ContextMenuNext,
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_next(self.completion_provider.as_deref(), window, cx);
13281        }
13282    }
13283
13284    pub fn context_menu_last(
13285        &mut self,
13286        _: &ContextMenuLast,
13287        window: &mut Window,
13288        cx: &mut Context<Self>,
13289    ) {
13290        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13291            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13292        }
13293    }
13294
13295    pub fn signature_help_prev(
13296        &mut self,
13297        _: &SignatureHelpPrevious,
13298        _: &mut Window,
13299        cx: &mut Context<Self>,
13300    ) {
13301        if let Some(popover) = self.signature_help_state.popover_mut() {
13302            if popover.current_signature == 0 {
13303                popover.current_signature = popover.signatures.len() - 1;
13304            } else {
13305                popover.current_signature -= 1;
13306            }
13307            cx.notify();
13308        }
13309    }
13310
13311    pub fn signature_help_next(
13312        &mut self,
13313        _: &SignatureHelpNext,
13314        _: &mut Window,
13315        cx: &mut Context<Self>,
13316    ) {
13317        if let Some(popover) = self.signature_help_state.popover_mut() {
13318            if popover.current_signature + 1 == popover.signatures.len() {
13319                popover.current_signature = 0;
13320            } else {
13321                popover.current_signature += 1;
13322            }
13323            cx.notify();
13324        }
13325    }
13326
13327    pub fn move_to_previous_word_start(
13328        &mut self,
13329        _: &MoveToPreviousWordStart,
13330        window: &mut Window,
13331        cx: &mut Context<Self>,
13332    ) {
13333        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13334        self.change_selections(Default::default(), window, cx, |s| {
13335            s.move_cursors_with(|map, head, _| {
13336                (
13337                    movement::previous_word_start(map, head),
13338                    SelectionGoal::None,
13339                )
13340            });
13341        })
13342    }
13343
13344    pub fn move_to_previous_subword_start(
13345        &mut self,
13346        _: &MoveToPreviousSubwordStart,
13347        window: &mut Window,
13348        cx: &mut Context<Self>,
13349    ) {
13350        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13351        self.change_selections(Default::default(), window, cx, |s| {
13352            s.move_cursors_with(|map, head, _| {
13353                (
13354                    movement::previous_subword_start(map, head),
13355                    SelectionGoal::None,
13356                )
13357            });
13358        })
13359    }
13360
13361    pub fn select_to_previous_word_start(
13362        &mut self,
13363        _: &SelectToPreviousWordStart,
13364        window: &mut Window,
13365        cx: &mut Context<Self>,
13366    ) {
13367        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13368        self.change_selections(Default::default(), window, cx, |s| {
13369            s.move_heads_with(|map, head, _| {
13370                (
13371                    movement::previous_word_start(map, head),
13372                    SelectionGoal::None,
13373                )
13374            });
13375        })
13376    }
13377
13378    pub fn select_to_previous_subword_start(
13379        &mut self,
13380        _: &SelectToPreviousSubwordStart,
13381        window: &mut Window,
13382        cx: &mut Context<Self>,
13383    ) {
13384        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13385        self.change_selections(Default::default(), window, cx, |s| {
13386            s.move_heads_with(|map, head, _| {
13387                (
13388                    movement::previous_subword_start(map, head),
13389                    SelectionGoal::None,
13390                )
13391            });
13392        })
13393    }
13394
13395    pub fn delete_to_previous_word_start(
13396        &mut self,
13397        action: &DeleteToPreviousWordStart,
13398        window: &mut Window,
13399        cx: &mut Context<Self>,
13400    ) {
13401        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13402        self.transact(window, cx, |this, window, cx| {
13403            this.select_autoclose_pair(window, cx);
13404            this.change_selections(Default::default(), window, cx, |s| {
13405                s.move_with(|map, selection| {
13406                    if selection.is_empty() {
13407                        let mut cursor = if action.ignore_newlines {
13408                            movement::previous_word_start(map, selection.head())
13409                        } else {
13410                            movement::previous_word_start_or_newline(map, selection.head())
13411                        };
13412                        cursor = movement::adjust_greedy_deletion(
13413                            map,
13414                            selection.head(),
13415                            cursor,
13416                            action.ignore_brackets,
13417                        );
13418                        selection.set_head(cursor, SelectionGoal::None);
13419                    }
13420                });
13421            });
13422            this.insert("", window, cx);
13423        });
13424    }
13425
13426    pub fn delete_to_previous_subword_start(
13427        &mut self,
13428        _: &DeleteToPreviousSubwordStart,
13429        window: &mut Window,
13430        cx: &mut Context<Self>,
13431    ) {
13432        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13433        self.transact(window, cx, |this, window, cx| {
13434            this.select_autoclose_pair(window, cx);
13435            this.change_selections(Default::default(), window, cx, |s| {
13436                s.move_with(|map, selection| {
13437                    if selection.is_empty() {
13438                        let mut cursor = movement::previous_subword_start(map, selection.head());
13439                        cursor =
13440                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13441                        selection.set_head(cursor, SelectionGoal::None);
13442                    }
13443                });
13444            });
13445            this.insert("", window, cx);
13446        });
13447    }
13448
13449    pub fn move_to_next_word_end(
13450        &mut self,
13451        _: &MoveToNextWordEnd,
13452        window: &mut Window,
13453        cx: &mut Context<Self>,
13454    ) {
13455        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13456        self.change_selections(Default::default(), window, cx, |s| {
13457            s.move_cursors_with(|map, head, _| {
13458                (movement::next_word_end(map, head), SelectionGoal::None)
13459            });
13460        })
13461    }
13462
13463    pub fn move_to_next_subword_end(
13464        &mut self,
13465        _: &MoveToNextSubwordEnd,
13466        window: &mut Window,
13467        cx: &mut Context<Self>,
13468    ) {
13469        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13470        self.change_selections(Default::default(), window, cx, |s| {
13471            s.move_cursors_with(|map, head, _| {
13472                (movement::next_subword_end(map, head), SelectionGoal::None)
13473            });
13474        })
13475    }
13476
13477    pub fn select_to_next_word_end(
13478        &mut self,
13479        _: &SelectToNextWordEnd,
13480        window: &mut Window,
13481        cx: &mut Context<Self>,
13482    ) {
13483        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13484        self.change_selections(Default::default(), window, cx, |s| {
13485            s.move_heads_with(|map, head, _| {
13486                (movement::next_word_end(map, head), SelectionGoal::None)
13487            });
13488        })
13489    }
13490
13491    pub fn select_to_next_subword_end(
13492        &mut self,
13493        _: &SelectToNextSubwordEnd,
13494        window: &mut Window,
13495        cx: &mut Context<Self>,
13496    ) {
13497        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13498        self.change_selections(Default::default(), window, cx, |s| {
13499            s.move_heads_with(|map, head, _| {
13500                (movement::next_subword_end(map, head), SelectionGoal::None)
13501            });
13502        })
13503    }
13504
13505    pub fn delete_to_next_word_end(
13506        &mut self,
13507        action: &DeleteToNextWordEnd,
13508        window: &mut Window,
13509        cx: &mut Context<Self>,
13510    ) {
13511        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13512        self.transact(window, cx, |this, window, cx| {
13513            this.change_selections(Default::default(), window, cx, |s| {
13514                s.move_with(|map, selection| {
13515                    if selection.is_empty() {
13516                        let mut cursor = if action.ignore_newlines {
13517                            movement::next_word_end(map, selection.head())
13518                        } else {
13519                            movement::next_word_end_or_newline(map, selection.head())
13520                        };
13521                        cursor = movement::adjust_greedy_deletion(
13522                            map,
13523                            selection.head(),
13524                            cursor,
13525                            action.ignore_brackets,
13526                        );
13527                        selection.set_head(cursor, SelectionGoal::None);
13528                    }
13529                });
13530            });
13531            this.insert("", window, cx);
13532        });
13533    }
13534
13535    pub fn delete_to_next_subword_end(
13536        &mut self,
13537        _: &DeleteToNextSubwordEnd,
13538        window: &mut Window,
13539        cx: &mut Context<Self>,
13540    ) {
13541        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13542        self.transact(window, cx, |this, window, cx| {
13543            this.change_selections(Default::default(), window, cx, |s| {
13544                s.move_with(|map, selection| {
13545                    if selection.is_empty() {
13546                        let mut cursor = movement::next_subword_end(map, selection.head());
13547                        cursor =
13548                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13549                        selection.set_head(cursor, SelectionGoal::None);
13550                    }
13551                });
13552            });
13553            this.insert("", window, cx);
13554        });
13555    }
13556
13557    pub fn move_to_beginning_of_line(
13558        &mut self,
13559        action: &MoveToBeginningOfLine,
13560        window: &mut Window,
13561        cx: &mut Context<Self>,
13562    ) {
13563        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13564        self.change_selections(Default::default(), window, cx, |s| {
13565            s.move_cursors_with(|map, head, _| {
13566                (
13567                    movement::indented_line_beginning(
13568                        map,
13569                        head,
13570                        action.stop_at_soft_wraps,
13571                        action.stop_at_indent,
13572                    ),
13573                    SelectionGoal::None,
13574                )
13575            });
13576        })
13577    }
13578
13579    pub fn select_to_beginning_of_line(
13580        &mut self,
13581        action: &SelectToBeginningOfLine,
13582        window: &mut Window,
13583        cx: &mut Context<Self>,
13584    ) {
13585        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13586        self.change_selections(Default::default(), window, cx, |s| {
13587            s.move_heads_with(|map, head, _| {
13588                (
13589                    movement::indented_line_beginning(
13590                        map,
13591                        head,
13592                        action.stop_at_soft_wraps,
13593                        action.stop_at_indent,
13594                    ),
13595                    SelectionGoal::None,
13596                )
13597            });
13598        });
13599    }
13600
13601    pub fn delete_to_beginning_of_line(
13602        &mut self,
13603        action: &DeleteToBeginningOfLine,
13604        window: &mut Window,
13605        cx: &mut Context<Self>,
13606    ) {
13607        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13608        self.transact(window, cx, |this, window, cx| {
13609            this.change_selections(Default::default(), window, cx, |s| {
13610                s.move_with(|_, selection| {
13611                    selection.reversed = true;
13612                });
13613            });
13614
13615            this.select_to_beginning_of_line(
13616                &SelectToBeginningOfLine {
13617                    stop_at_soft_wraps: false,
13618                    stop_at_indent: action.stop_at_indent,
13619                },
13620                window,
13621                cx,
13622            );
13623            this.backspace(&Backspace, window, cx);
13624        });
13625    }
13626
13627    pub fn move_to_end_of_line(
13628        &mut self,
13629        action: &MoveToEndOfLine,
13630        window: &mut Window,
13631        cx: &mut Context<Self>,
13632    ) {
13633        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13634        self.change_selections(Default::default(), window, cx, |s| {
13635            s.move_cursors_with(|map, head, _| {
13636                (
13637                    movement::line_end(map, head, action.stop_at_soft_wraps),
13638                    SelectionGoal::None,
13639                )
13640            });
13641        })
13642    }
13643
13644    pub fn select_to_end_of_line(
13645        &mut self,
13646        action: &SelectToEndOfLine,
13647        window: &mut Window,
13648        cx: &mut Context<Self>,
13649    ) {
13650        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13651        self.change_selections(Default::default(), window, cx, |s| {
13652            s.move_heads_with(|map, head, _| {
13653                (
13654                    movement::line_end(map, head, action.stop_at_soft_wraps),
13655                    SelectionGoal::None,
13656                )
13657            });
13658        })
13659    }
13660
13661    pub fn delete_to_end_of_line(
13662        &mut self,
13663        _: &DeleteToEndOfLine,
13664        window: &mut Window,
13665        cx: &mut Context<Self>,
13666    ) {
13667        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13668        self.transact(window, cx, |this, window, cx| {
13669            this.select_to_end_of_line(
13670                &SelectToEndOfLine {
13671                    stop_at_soft_wraps: false,
13672                },
13673                window,
13674                cx,
13675            );
13676            this.delete(&Delete, window, cx);
13677        });
13678    }
13679
13680    pub fn cut_to_end_of_line(
13681        &mut self,
13682        action: &CutToEndOfLine,
13683        window: &mut Window,
13684        cx: &mut Context<Self>,
13685    ) {
13686        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13687        self.transact(window, cx, |this, window, cx| {
13688            this.select_to_end_of_line(
13689                &SelectToEndOfLine {
13690                    stop_at_soft_wraps: false,
13691                },
13692                window,
13693                cx,
13694            );
13695            if !action.stop_at_newlines {
13696                this.change_selections(Default::default(), window, cx, |s| {
13697                    s.move_with(|_, sel| {
13698                        if sel.is_empty() {
13699                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13700                        }
13701                    });
13702                });
13703            }
13704            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13705            let item = this.cut_common(false, window, cx);
13706            cx.write_to_clipboard(item);
13707        });
13708    }
13709
13710    pub fn move_to_start_of_paragraph(
13711        &mut self,
13712        _: &MoveToStartOfParagraph,
13713        window: &mut Window,
13714        cx: &mut Context<Self>,
13715    ) {
13716        if matches!(self.mode, EditorMode::SingleLine) {
13717            cx.propagate();
13718            return;
13719        }
13720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13721        self.change_selections(Default::default(), window, cx, |s| {
13722            s.move_with(|map, selection| {
13723                selection.collapse_to(
13724                    movement::start_of_paragraph(map, selection.head(), 1),
13725                    SelectionGoal::None,
13726                )
13727            });
13728        })
13729    }
13730
13731    pub fn move_to_end_of_paragraph(
13732        &mut self,
13733        _: &MoveToEndOfParagraph,
13734        window: &mut Window,
13735        cx: &mut Context<Self>,
13736    ) {
13737        if matches!(self.mode, EditorMode::SingleLine) {
13738            cx.propagate();
13739            return;
13740        }
13741        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13742        self.change_selections(Default::default(), window, cx, |s| {
13743            s.move_with(|map, selection| {
13744                selection.collapse_to(
13745                    movement::end_of_paragraph(map, selection.head(), 1),
13746                    SelectionGoal::None,
13747                )
13748            });
13749        })
13750    }
13751
13752    pub fn select_to_start_of_paragraph(
13753        &mut self,
13754        _: &SelectToStartOfParagraph,
13755        window: &mut Window,
13756        cx: &mut Context<Self>,
13757    ) {
13758        if matches!(self.mode, EditorMode::SingleLine) {
13759            cx.propagate();
13760            return;
13761        }
13762        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13763        self.change_selections(Default::default(), window, cx, |s| {
13764            s.move_heads_with(|map, head, _| {
13765                (
13766                    movement::start_of_paragraph(map, head, 1),
13767                    SelectionGoal::None,
13768                )
13769            });
13770        })
13771    }
13772
13773    pub fn select_to_end_of_paragraph(
13774        &mut self,
13775        _: &SelectToEndOfParagraph,
13776        window: &mut Window,
13777        cx: &mut Context<Self>,
13778    ) {
13779        if matches!(self.mode, EditorMode::SingleLine) {
13780            cx.propagate();
13781            return;
13782        }
13783        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13784        self.change_selections(Default::default(), window, cx, |s| {
13785            s.move_heads_with(|map, head, _| {
13786                (
13787                    movement::end_of_paragraph(map, head, 1),
13788                    SelectionGoal::None,
13789                )
13790            });
13791        })
13792    }
13793
13794    pub fn move_to_start_of_excerpt(
13795        &mut self,
13796        _: &MoveToStartOfExcerpt,
13797        window: &mut Window,
13798        cx: &mut Context<Self>,
13799    ) {
13800        if matches!(self.mode, EditorMode::SingleLine) {
13801            cx.propagate();
13802            return;
13803        }
13804        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13805        self.change_selections(Default::default(), window, cx, |s| {
13806            s.move_with(|map, selection| {
13807                selection.collapse_to(
13808                    movement::start_of_excerpt(
13809                        map,
13810                        selection.head(),
13811                        workspace::searchable::Direction::Prev,
13812                    ),
13813                    SelectionGoal::None,
13814                )
13815            });
13816        })
13817    }
13818
13819    pub fn move_to_start_of_next_excerpt(
13820        &mut self,
13821        _: &MoveToStartOfNextExcerpt,
13822        window: &mut Window,
13823        cx: &mut Context<Self>,
13824    ) {
13825        if matches!(self.mode, EditorMode::SingleLine) {
13826            cx.propagate();
13827            return;
13828        }
13829
13830        self.change_selections(Default::default(), window, cx, |s| {
13831            s.move_with(|map, selection| {
13832                selection.collapse_to(
13833                    movement::start_of_excerpt(
13834                        map,
13835                        selection.head(),
13836                        workspace::searchable::Direction::Next,
13837                    ),
13838                    SelectionGoal::None,
13839                )
13840            });
13841        })
13842    }
13843
13844    pub fn move_to_end_of_excerpt(
13845        &mut self,
13846        _: &MoveToEndOfExcerpt,
13847        window: &mut Window,
13848        cx: &mut Context<Self>,
13849    ) {
13850        if matches!(self.mode, EditorMode::SingleLine) {
13851            cx.propagate();
13852            return;
13853        }
13854        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13855        self.change_selections(Default::default(), window, cx, |s| {
13856            s.move_with(|map, selection| {
13857                selection.collapse_to(
13858                    movement::end_of_excerpt(
13859                        map,
13860                        selection.head(),
13861                        workspace::searchable::Direction::Next,
13862                    ),
13863                    SelectionGoal::None,
13864                )
13865            });
13866        })
13867    }
13868
13869    pub fn move_to_end_of_previous_excerpt(
13870        &mut self,
13871        _: &MoveToEndOfPreviousExcerpt,
13872        window: &mut Window,
13873        cx: &mut Context<Self>,
13874    ) {
13875        if matches!(self.mode, EditorMode::SingleLine) {
13876            cx.propagate();
13877            return;
13878        }
13879        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13880        self.change_selections(Default::default(), window, cx, |s| {
13881            s.move_with(|map, selection| {
13882                selection.collapse_to(
13883                    movement::end_of_excerpt(
13884                        map,
13885                        selection.head(),
13886                        workspace::searchable::Direction::Prev,
13887                    ),
13888                    SelectionGoal::None,
13889                )
13890            });
13891        })
13892    }
13893
13894    pub fn select_to_start_of_excerpt(
13895        &mut self,
13896        _: &SelectToStartOfExcerpt,
13897        window: &mut Window,
13898        cx: &mut Context<Self>,
13899    ) {
13900        if matches!(self.mode, EditorMode::SingleLine) {
13901            cx.propagate();
13902            return;
13903        }
13904        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13905        self.change_selections(Default::default(), window, cx, |s| {
13906            s.move_heads_with(|map, head, _| {
13907                (
13908                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13909                    SelectionGoal::None,
13910                )
13911            });
13912        })
13913    }
13914
13915    pub fn select_to_start_of_next_excerpt(
13916        &mut self,
13917        _: &SelectToStartOfNextExcerpt,
13918        window: &mut Window,
13919        cx: &mut Context<Self>,
13920    ) {
13921        if matches!(self.mode, EditorMode::SingleLine) {
13922            cx.propagate();
13923            return;
13924        }
13925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13926        self.change_selections(Default::default(), window, cx, |s| {
13927            s.move_heads_with(|map, head, _| {
13928                (
13929                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13930                    SelectionGoal::None,
13931                )
13932            });
13933        })
13934    }
13935
13936    pub fn select_to_end_of_excerpt(
13937        &mut self,
13938        _: &SelectToEndOfExcerpt,
13939        window: &mut Window,
13940        cx: &mut Context<Self>,
13941    ) {
13942        if matches!(self.mode, EditorMode::SingleLine) {
13943            cx.propagate();
13944            return;
13945        }
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947        self.change_selections(Default::default(), window, cx, |s| {
13948            s.move_heads_with(|map, head, _| {
13949                (
13950                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13951                    SelectionGoal::None,
13952                )
13953            });
13954        })
13955    }
13956
13957    pub fn select_to_end_of_previous_excerpt(
13958        &mut self,
13959        _: &SelectToEndOfPreviousExcerpt,
13960        window: &mut Window,
13961        cx: &mut Context<Self>,
13962    ) {
13963        if matches!(self.mode, EditorMode::SingleLine) {
13964            cx.propagate();
13965            return;
13966        }
13967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13968        self.change_selections(Default::default(), window, cx, |s| {
13969            s.move_heads_with(|map, head, _| {
13970                (
13971                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13972                    SelectionGoal::None,
13973                )
13974            });
13975        })
13976    }
13977
13978    pub fn move_to_beginning(
13979        &mut self,
13980        _: &MoveToBeginning,
13981        window: &mut Window,
13982        cx: &mut Context<Self>,
13983    ) {
13984        if matches!(self.mode, EditorMode::SingleLine) {
13985            cx.propagate();
13986            return;
13987        }
13988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13989        self.change_selections(Default::default(), window, cx, |s| {
13990            s.select_ranges(vec![0..0]);
13991        });
13992    }
13993
13994    pub fn select_to_beginning(
13995        &mut self,
13996        _: &SelectToBeginning,
13997        window: &mut Window,
13998        cx: &mut Context<Self>,
13999    ) {
14000        let mut selection = self.selections.last::<Point>(cx);
14001        selection.set_head(Point::zero(), SelectionGoal::None);
14002        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14003        self.change_selections(Default::default(), window, cx, |s| {
14004            s.select(vec![selection]);
14005        });
14006    }
14007
14008    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14009        if matches!(self.mode, EditorMode::SingleLine) {
14010            cx.propagate();
14011            return;
14012        }
14013        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14014        let cursor = self.buffer.read(cx).read(cx).len();
14015        self.change_selections(Default::default(), window, cx, |s| {
14016            s.select_ranges(vec![cursor..cursor])
14017        });
14018    }
14019
14020    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14021        self.nav_history = nav_history;
14022    }
14023
14024    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14025        self.nav_history.as_ref()
14026    }
14027
14028    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14029        self.push_to_nav_history(
14030            self.selections.newest_anchor().head(),
14031            None,
14032            false,
14033            true,
14034            cx,
14035        );
14036    }
14037
14038    fn push_to_nav_history(
14039        &mut self,
14040        cursor_anchor: Anchor,
14041        new_position: Option<Point>,
14042        is_deactivate: bool,
14043        always: bool,
14044        cx: &mut Context<Self>,
14045    ) {
14046        if let Some(nav_history) = self.nav_history.as_mut() {
14047            let buffer = self.buffer.read(cx).read(cx);
14048            let cursor_position = cursor_anchor.to_point(&buffer);
14049            let scroll_state = self.scroll_manager.anchor();
14050            let scroll_top_row = scroll_state.top_row(&buffer);
14051            drop(buffer);
14052
14053            if let Some(new_position) = new_position {
14054                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14055                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14056                    return;
14057                }
14058            }
14059
14060            nav_history.push(
14061                Some(NavigationData {
14062                    cursor_anchor,
14063                    cursor_position,
14064                    scroll_anchor: scroll_state,
14065                    scroll_top_row,
14066                }),
14067                cx,
14068            );
14069            cx.emit(EditorEvent::PushedToNavHistory {
14070                anchor: cursor_anchor,
14071                is_deactivate,
14072            })
14073        }
14074    }
14075
14076    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14077        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14078        let buffer = self.buffer.read(cx).snapshot(cx);
14079        let mut selection = self.selections.first::<usize>(cx);
14080        selection.set_head(buffer.len(), SelectionGoal::None);
14081        self.change_selections(Default::default(), window, cx, |s| {
14082            s.select(vec![selection]);
14083        });
14084    }
14085
14086    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14087        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14088        let end = self.buffer.read(cx).read(cx).len();
14089        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14090            s.select_ranges(vec![0..end]);
14091        });
14092    }
14093
14094    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14095        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14096        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14097        let mut selections = self.selections.all::<Point>(cx);
14098        let max_point = display_map.buffer_snapshot.max_point();
14099        for selection in &mut selections {
14100            let rows = selection.spanned_rows(true, &display_map);
14101            selection.start = Point::new(rows.start.0, 0);
14102            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14103            selection.reversed = false;
14104        }
14105        self.change_selections(Default::default(), window, cx, |s| {
14106            s.select(selections);
14107        });
14108    }
14109
14110    pub fn split_selection_into_lines(
14111        &mut self,
14112        action: &SplitSelectionIntoLines,
14113        window: &mut Window,
14114        cx: &mut Context<Self>,
14115    ) {
14116        let selections = self
14117            .selections
14118            .all::<Point>(cx)
14119            .into_iter()
14120            .map(|selection| selection.start..selection.end)
14121            .collect::<Vec<_>>();
14122        self.unfold_ranges(&selections, true, true, cx);
14123
14124        let mut new_selection_ranges = Vec::new();
14125        {
14126            let buffer = self.buffer.read(cx).read(cx);
14127            for selection in selections {
14128                for row in selection.start.row..selection.end.row {
14129                    let line_start = Point::new(row, 0);
14130                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14131
14132                    if action.keep_selections {
14133                        // Keep the selection range for each line
14134                        let selection_start = if row == selection.start.row {
14135                            selection.start
14136                        } else {
14137                            line_start
14138                        };
14139                        new_selection_ranges.push(selection_start..line_end);
14140                    } else {
14141                        // Collapse to cursor at end of line
14142                        new_selection_ranges.push(line_end..line_end);
14143                    }
14144                }
14145
14146                let is_multiline_selection = selection.start.row != selection.end.row;
14147                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14148                // so this action feels more ergonomic when paired with other selection operations
14149                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14150                if !should_skip_last {
14151                    if action.keep_selections {
14152                        if is_multiline_selection {
14153                            let line_start = Point::new(selection.end.row, 0);
14154                            new_selection_ranges.push(line_start..selection.end);
14155                        } else {
14156                            new_selection_ranges.push(selection.start..selection.end);
14157                        }
14158                    } else {
14159                        new_selection_ranges.push(selection.end..selection.end);
14160                    }
14161                }
14162            }
14163        }
14164        self.change_selections(Default::default(), window, cx, |s| {
14165            s.select_ranges(new_selection_ranges);
14166        });
14167    }
14168
14169    pub fn add_selection_above(
14170        &mut self,
14171        _: &AddSelectionAbove,
14172        window: &mut Window,
14173        cx: &mut Context<Self>,
14174    ) {
14175        self.add_selection(true, window, cx);
14176    }
14177
14178    pub fn add_selection_below(
14179        &mut self,
14180        _: &AddSelectionBelow,
14181        window: &mut Window,
14182        cx: &mut Context<Self>,
14183    ) {
14184        self.add_selection(false, window, cx);
14185    }
14186
14187    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14188        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14189
14190        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14191        let all_selections = self.selections.all::<Point>(cx);
14192        let text_layout_details = self.text_layout_details(window);
14193
14194        let (mut columnar_selections, new_selections_to_columnarize) = {
14195            if let Some(state) = self.add_selections_state.as_ref() {
14196                let columnar_selection_ids: HashSet<_> = state
14197                    .groups
14198                    .iter()
14199                    .flat_map(|group| group.stack.iter())
14200                    .copied()
14201                    .collect();
14202
14203                all_selections
14204                    .into_iter()
14205                    .partition(|s| columnar_selection_ids.contains(&s.id))
14206            } else {
14207                (Vec::new(), all_selections)
14208            }
14209        };
14210
14211        let mut state = self
14212            .add_selections_state
14213            .take()
14214            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14215
14216        for selection in new_selections_to_columnarize {
14217            let range = selection.display_range(&display_map).sorted();
14218            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14219            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14220            let positions = start_x.min(end_x)..start_x.max(end_x);
14221            let mut stack = Vec::new();
14222            for row in range.start.row().0..=range.end.row().0 {
14223                if let Some(selection) = self.selections.build_columnar_selection(
14224                    &display_map,
14225                    DisplayRow(row),
14226                    &positions,
14227                    selection.reversed,
14228                    &text_layout_details,
14229                ) {
14230                    stack.push(selection.id);
14231                    columnar_selections.push(selection);
14232                }
14233            }
14234            if !stack.is_empty() {
14235                if above {
14236                    stack.reverse();
14237                }
14238                state.groups.push(AddSelectionsGroup { above, stack });
14239            }
14240        }
14241
14242        let mut final_selections = Vec::new();
14243        let end_row = if above {
14244            DisplayRow(0)
14245        } else {
14246            display_map.max_point().row()
14247        };
14248
14249        let mut last_added_item_per_group = HashMap::default();
14250        for group in state.groups.iter_mut() {
14251            if let Some(last_id) = group.stack.last() {
14252                last_added_item_per_group.insert(*last_id, group);
14253            }
14254        }
14255
14256        for selection in columnar_selections {
14257            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14258                if above == group.above {
14259                    let range = selection.display_range(&display_map).sorted();
14260                    debug_assert_eq!(range.start.row(), range.end.row());
14261                    let mut row = range.start.row();
14262                    let positions =
14263                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14264                            Pixels::from(start)..Pixels::from(end)
14265                        } else {
14266                            let start_x =
14267                                display_map.x_for_display_point(range.start, &text_layout_details);
14268                            let end_x =
14269                                display_map.x_for_display_point(range.end, &text_layout_details);
14270                            start_x.min(end_x)..start_x.max(end_x)
14271                        };
14272
14273                    let mut maybe_new_selection = None;
14274                    while row != end_row {
14275                        if above {
14276                            row.0 -= 1;
14277                        } else {
14278                            row.0 += 1;
14279                        }
14280                        if let Some(new_selection) = self.selections.build_columnar_selection(
14281                            &display_map,
14282                            row,
14283                            &positions,
14284                            selection.reversed,
14285                            &text_layout_details,
14286                        ) {
14287                            maybe_new_selection = Some(new_selection);
14288                            break;
14289                        }
14290                    }
14291
14292                    if let Some(new_selection) = maybe_new_selection {
14293                        group.stack.push(new_selection.id);
14294                        if above {
14295                            final_selections.push(new_selection);
14296                            final_selections.push(selection);
14297                        } else {
14298                            final_selections.push(selection);
14299                            final_selections.push(new_selection);
14300                        }
14301                    } else {
14302                        final_selections.push(selection);
14303                    }
14304                } else {
14305                    group.stack.pop();
14306                }
14307            } else {
14308                final_selections.push(selection);
14309            }
14310        }
14311
14312        self.change_selections(Default::default(), window, cx, |s| {
14313            s.select(final_selections);
14314        });
14315
14316        let final_selection_ids: HashSet<_> = self
14317            .selections
14318            .all::<Point>(cx)
14319            .iter()
14320            .map(|s| s.id)
14321            .collect();
14322        state.groups.retain_mut(|group| {
14323            // selections might get merged above so we remove invalid items from stacks
14324            group.stack.retain(|id| final_selection_ids.contains(id));
14325
14326            // single selection in stack can be treated as initial state
14327            group.stack.len() > 1
14328        });
14329
14330        if !state.groups.is_empty() {
14331            self.add_selections_state = Some(state);
14332        }
14333    }
14334
14335    fn select_match_ranges(
14336        &mut self,
14337        range: Range<usize>,
14338        reversed: bool,
14339        replace_newest: bool,
14340        auto_scroll: Option<Autoscroll>,
14341        window: &mut Window,
14342        cx: &mut Context<Editor>,
14343    ) {
14344        self.unfold_ranges(
14345            std::slice::from_ref(&range),
14346            false,
14347            auto_scroll.is_some(),
14348            cx,
14349        );
14350        let effects = if let Some(scroll) = auto_scroll {
14351            SelectionEffects::scroll(scroll)
14352        } else {
14353            SelectionEffects::no_scroll()
14354        };
14355        self.change_selections(effects, window, cx, |s| {
14356            if replace_newest {
14357                s.delete(s.newest_anchor().id);
14358            }
14359            if reversed {
14360                s.insert_range(range.end..range.start);
14361            } else {
14362                s.insert_range(range);
14363            }
14364        });
14365    }
14366
14367    pub fn select_next_match_internal(
14368        &mut self,
14369        display_map: &DisplaySnapshot,
14370        replace_newest: bool,
14371        autoscroll: Option<Autoscroll>,
14372        window: &mut Window,
14373        cx: &mut Context<Self>,
14374    ) -> Result<()> {
14375        let buffer = &display_map.buffer_snapshot;
14376        let mut selections = self.selections.all::<usize>(cx);
14377        if let Some(mut select_next_state) = self.select_next_state.take() {
14378            let query = &select_next_state.query;
14379            if !select_next_state.done {
14380                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14381                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14382                let mut next_selected_range = None;
14383
14384                let bytes_after_last_selection =
14385                    buffer.bytes_in_range(last_selection.end..buffer.len());
14386                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14387                let query_matches = query
14388                    .stream_find_iter(bytes_after_last_selection)
14389                    .map(|result| (last_selection.end, result))
14390                    .chain(
14391                        query
14392                            .stream_find_iter(bytes_before_first_selection)
14393                            .map(|result| (0, result)),
14394                    );
14395
14396                for (start_offset, query_match) in query_matches {
14397                    let query_match = query_match.unwrap(); // can only fail due to I/O
14398                    let offset_range =
14399                        start_offset + query_match.start()..start_offset + query_match.end();
14400
14401                    if !select_next_state.wordwise
14402                        || (!buffer.is_inside_word(offset_range.start, None)
14403                            && !buffer.is_inside_word(offset_range.end, None))
14404                    {
14405                        // TODO: This is n^2, because we might check all the selections
14406                        if !selections
14407                            .iter()
14408                            .any(|selection| selection.range().overlaps(&offset_range))
14409                        {
14410                            next_selected_range = Some(offset_range);
14411                            break;
14412                        }
14413                    }
14414                }
14415
14416                if let Some(next_selected_range) = next_selected_range {
14417                    self.select_match_ranges(
14418                        next_selected_range,
14419                        last_selection.reversed,
14420                        replace_newest,
14421                        autoscroll,
14422                        window,
14423                        cx,
14424                    );
14425                } else {
14426                    select_next_state.done = true;
14427                }
14428            }
14429
14430            self.select_next_state = Some(select_next_state);
14431        } else {
14432            let mut only_carets = true;
14433            let mut same_text_selected = true;
14434            let mut selected_text = None;
14435
14436            let mut selections_iter = selections.iter().peekable();
14437            while let Some(selection) = selections_iter.next() {
14438                if selection.start != selection.end {
14439                    only_carets = false;
14440                }
14441
14442                if same_text_selected {
14443                    if selected_text.is_none() {
14444                        selected_text =
14445                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14446                    }
14447
14448                    if let Some(next_selection) = selections_iter.peek() {
14449                        if next_selection.range().len() == selection.range().len() {
14450                            let next_selected_text = buffer
14451                                .text_for_range(next_selection.range())
14452                                .collect::<String>();
14453                            if Some(next_selected_text) != selected_text {
14454                                same_text_selected = false;
14455                                selected_text = None;
14456                            }
14457                        } else {
14458                            same_text_selected = false;
14459                            selected_text = None;
14460                        }
14461                    }
14462                }
14463            }
14464
14465            if only_carets {
14466                for selection in &mut selections {
14467                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14468                    selection.start = word_range.start;
14469                    selection.end = word_range.end;
14470                    selection.goal = SelectionGoal::None;
14471                    selection.reversed = false;
14472                    self.select_match_ranges(
14473                        selection.start..selection.end,
14474                        selection.reversed,
14475                        replace_newest,
14476                        autoscroll,
14477                        window,
14478                        cx,
14479                    );
14480                }
14481
14482                if selections.len() == 1 {
14483                    let selection = selections
14484                        .last()
14485                        .expect("ensured that there's only one selection");
14486                    let query = buffer
14487                        .text_for_range(selection.start..selection.end)
14488                        .collect::<String>();
14489                    let is_empty = query.is_empty();
14490                    let select_state = SelectNextState {
14491                        query: AhoCorasick::new(&[query])?,
14492                        wordwise: true,
14493                        done: is_empty,
14494                    };
14495                    self.select_next_state = Some(select_state);
14496                } else {
14497                    self.select_next_state = None;
14498                }
14499            } else if let Some(selected_text) = selected_text {
14500                self.select_next_state = Some(SelectNextState {
14501                    query: AhoCorasick::new(&[selected_text])?,
14502                    wordwise: false,
14503                    done: false,
14504                });
14505                self.select_next_match_internal(
14506                    display_map,
14507                    replace_newest,
14508                    autoscroll,
14509                    window,
14510                    cx,
14511                )?;
14512            }
14513        }
14514        Ok(())
14515    }
14516
14517    pub fn select_all_matches(
14518        &mut self,
14519        _action: &SelectAllMatches,
14520        window: &mut Window,
14521        cx: &mut Context<Self>,
14522    ) -> Result<()> {
14523        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14524
14525        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14526
14527        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14528        let Some(select_next_state) = self.select_next_state.as_mut() else {
14529            return Ok(());
14530        };
14531        if select_next_state.done {
14532            return Ok(());
14533        }
14534
14535        let mut new_selections = Vec::new();
14536
14537        let reversed = self.selections.oldest::<usize>(cx).reversed;
14538        let buffer = &display_map.buffer_snapshot;
14539        let query_matches = select_next_state
14540            .query
14541            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14542
14543        for query_match in query_matches.into_iter() {
14544            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14545            let offset_range = if reversed {
14546                query_match.end()..query_match.start()
14547            } else {
14548                query_match.start()..query_match.end()
14549            };
14550
14551            if !select_next_state.wordwise
14552                || (!buffer.is_inside_word(offset_range.start, None)
14553                    && !buffer.is_inside_word(offset_range.end, None))
14554            {
14555                new_selections.push(offset_range.start..offset_range.end);
14556            }
14557        }
14558
14559        select_next_state.done = true;
14560
14561        if new_selections.is_empty() {
14562            log::error!("bug: new_selections is empty in select_all_matches");
14563            return Ok(());
14564        }
14565
14566        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14567        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14568            selections.select_ranges(new_selections)
14569        });
14570
14571        Ok(())
14572    }
14573
14574    pub fn select_next(
14575        &mut self,
14576        action: &SelectNext,
14577        window: &mut Window,
14578        cx: &mut Context<Self>,
14579    ) -> Result<()> {
14580        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14581        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14582        self.select_next_match_internal(
14583            &display_map,
14584            action.replace_newest,
14585            Some(Autoscroll::newest()),
14586            window,
14587            cx,
14588        )?;
14589        Ok(())
14590    }
14591
14592    pub fn select_previous(
14593        &mut self,
14594        action: &SelectPrevious,
14595        window: &mut Window,
14596        cx: &mut Context<Self>,
14597    ) -> Result<()> {
14598        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14599        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14600        let buffer = &display_map.buffer_snapshot;
14601        let mut selections = self.selections.all::<usize>(cx);
14602        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14603            let query = &select_prev_state.query;
14604            if !select_prev_state.done {
14605                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14606                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14607                let mut next_selected_range = None;
14608                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14609                let bytes_before_last_selection =
14610                    buffer.reversed_bytes_in_range(0..last_selection.start);
14611                let bytes_after_first_selection =
14612                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14613                let query_matches = query
14614                    .stream_find_iter(bytes_before_last_selection)
14615                    .map(|result| (last_selection.start, result))
14616                    .chain(
14617                        query
14618                            .stream_find_iter(bytes_after_first_selection)
14619                            .map(|result| (buffer.len(), result)),
14620                    );
14621                for (end_offset, query_match) in query_matches {
14622                    let query_match = query_match.unwrap(); // can only fail due to I/O
14623                    let offset_range =
14624                        end_offset - query_match.end()..end_offset - query_match.start();
14625
14626                    if !select_prev_state.wordwise
14627                        || (!buffer.is_inside_word(offset_range.start, None)
14628                            && !buffer.is_inside_word(offset_range.end, None))
14629                    {
14630                        next_selected_range = Some(offset_range);
14631                        break;
14632                    }
14633                }
14634
14635                if let Some(next_selected_range) = next_selected_range {
14636                    self.select_match_ranges(
14637                        next_selected_range,
14638                        last_selection.reversed,
14639                        action.replace_newest,
14640                        Some(Autoscroll::newest()),
14641                        window,
14642                        cx,
14643                    );
14644                } else {
14645                    select_prev_state.done = true;
14646                }
14647            }
14648
14649            self.select_prev_state = Some(select_prev_state);
14650        } else {
14651            let mut only_carets = true;
14652            let mut same_text_selected = true;
14653            let mut selected_text = None;
14654
14655            let mut selections_iter = selections.iter().peekable();
14656            while let Some(selection) = selections_iter.next() {
14657                if selection.start != selection.end {
14658                    only_carets = false;
14659                }
14660
14661                if same_text_selected {
14662                    if selected_text.is_none() {
14663                        selected_text =
14664                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14665                    }
14666
14667                    if let Some(next_selection) = selections_iter.peek() {
14668                        if next_selection.range().len() == selection.range().len() {
14669                            let next_selected_text = buffer
14670                                .text_for_range(next_selection.range())
14671                                .collect::<String>();
14672                            if Some(next_selected_text) != selected_text {
14673                                same_text_selected = false;
14674                                selected_text = None;
14675                            }
14676                        } else {
14677                            same_text_selected = false;
14678                            selected_text = None;
14679                        }
14680                    }
14681                }
14682            }
14683
14684            if only_carets {
14685                for selection in &mut selections {
14686                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14687                    selection.start = word_range.start;
14688                    selection.end = word_range.end;
14689                    selection.goal = SelectionGoal::None;
14690                    selection.reversed = false;
14691                    self.select_match_ranges(
14692                        selection.start..selection.end,
14693                        selection.reversed,
14694                        action.replace_newest,
14695                        Some(Autoscroll::newest()),
14696                        window,
14697                        cx,
14698                    );
14699                }
14700                if selections.len() == 1 {
14701                    let selection = selections
14702                        .last()
14703                        .expect("ensured that there's only one selection");
14704                    let query = buffer
14705                        .text_for_range(selection.start..selection.end)
14706                        .collect::<String>();
14707                    let is_empty = query.is_empty();
14708                    let select_state = SelectNextState {
14709                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14710                        wordwise: true,
14711                        done: is_empty,
14712                    };
14713                    self.select_prev_state = Some(select_state);
14714                } else {
14715                    self.select_prev_state = None;
14716                }
14717            } else if let Some(selected_text) = selected_text {
14718                self.select_prev_state = Some(SelectNextState {
14719                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14720                    wordwise: false,
14721                    done: false,
14722                });
14723                self.select_previous(action, window, cx)?;
14724            }
14725        }
14726        Ok(())
14727    }
14728
14729    pub fn find_next_match(
14730        &mut self,
14731        _: &FindNextMatch,
14732        window: &mut Window,
14733        cx: &mut Context<Self>,
14734    ) -> Result<()> {
14735        let selections = self.selections.disjoint_anchors_arc();
14736        match selections.first() {
14737            Some(first) if selections.len() >= 2 => {
14738                self.change_selections(Default::default(), window, cx, |s| {
14739                    s.select_ranges([first.range()]);
14740                });
14741            }
14742            _ => self.select_next(
14743                &SelectNext {
14744                    replace_newest: true,
14745                },
14746                window,
14747                cx,
14748            )?,
14749        }
14750        Ok(())
14751    }
14752
14753    pub fn find_previous_match(
14754        &mut self,
14755        _: &FindPreviousMatch,
14756        window: &mut Window,
14757        cx: &mut Context<Self>,
14758    ) -> Result<()> {
14759        let selections = self.selections.disjoint_anchors_arc();
14760        match selections.last() {
14761            Some(last) if selections.len() >= 2 => {
14762                self.change_selections(Default::default(), window, cx, |s| {
14763                    s.select_ranges([last.range()]);
14764                });
14765            }
14766            _ => self.select_previous(
14767                &SelectPrevious {
14768                    replace_newest: true,
14769                },
14770                window,
14771                cx,
14772            )?,
14773        }
14774        Ok(())
14775    }
14776
14777    pub fn toggle_comments(
14778        &mut self,
14779        action: &ToggleComments,
14780        window: &mut Window,
14781        cx: &mut Context<Self>,
14782    ) {
14783        if self.read_only(cx) {
14784            return;
14785        }
14786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14787        let text_layout_details = &self.text_layout_details(window);
14788        self.transact(window, cx, |this, window, cx| {
14789            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14790            let mut edits = Vec::new();
14791            let mut selection_edit_ranges = Vec::new();
14792            let mut last_toggled_row = None;
14793            let snapshot = this.buffer.read(cx).read(cx);
14794            let empty_str: Arc<str> = Arc::default();
14795            let mut suffixes_inserted = Vec::new();
14796            let ignore_indent = action.ignore_indent;
14797
14798            fn comment_prefix_range(
14799                snapshot: &MultiBufferSnapshot,
14800                row: MultiBufferRow,
14801                comment_prefix: &str,
14802                comment_prefix_whitespace: &str,
14803                ignore_indent: bool,
14804            ) -> Range<Point> {
14805                let indent_size = if ignore_indent {
14806                    0
14807                } else {
14808                    snapshot.indent_size_for_line(row).len
14809                };
14810
14811                let start = Point::new(row.0, indent_size);
14812
14813                let mut line_bytes = snapshot
14814                    .bytes_in_range(start..snapshot.max_point())
14815                    .flatten()
14816                    .copied();
14817
14818                // If this line currently begins with the line comment prefix, then record
14819                // the range containing the prefix.
14820                if line_bytes
14821                    .by_ref()
14822                    .take(comment_prefix.len())
14823                    .eq(comment_prefix.bytes())
14824                {
14825                    // Include any whitespace that matches the comment prefix.
14826                    let matching_whitespace_len = line_bytes
14827                        .zip(comment_prefix_whitespace.bytes())
14828                        .take_while(|(a, b)| a == b)
14829                        .count() as u32;
14830                    let end = Point::new(
14831                        start.row,
14832                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14833                    );
14834                    start..end
14835                } else {
14836                    start..start
14837                }
14838            }
14839
14840            fn comment_suffix_range(
14841                snapshot: &MultiBufferSnapshot,
14842                row: MultiBufferRow,
14843                comment_suffix: &str,
14844                comment_suffix_has_leading_space: bool,
14845            ) -> Range<Point> {
14846                let end = Point::new(row.0, snapshot.line_len(row));
14847                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14848
14849                let mut line_end_bytes = snapshot
14850                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14851                    .flatten()
14852                    .copied();
14853
14854                let leading_space_len = if suffix_start_column > 0
14855                    && line_end_bytes.next() == Some(b' ')
14856                    && comment_suffix_has_leading_space
14857                {
14858                    1
14859                } else {
14860                    0
14861                };
14862
14863                // If this line currently begins with the line comment prefix, then record
14864                // the range containing the prefix.
14865                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14866                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14867                    start..end
14868                } else {
14869                    end..end
14870                }
14871            }
14872
14873            // TODO: Handle selections that cross excerpts
14874            for selection in &mut selections {
14875                let start_column = snapshot
14876                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14877                    .len;
14878                let language = if let Some(language) =
14879                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14880                {
14881                    language
14882                } else {
14883                    continue;
14884                };
14885
14886                selection_edit_ranges.clear();
14887
14888                // If multiple selections contain a given row, avoid processing that
14889                // row more than once.
14890                let mut start_row = MultiBufferRow(selection.start.row);
14891                if last_toggled_row == Some(start_row) {
14892                    start_row = start_row.next_row();
14893                }
14894                let end_row =
14895                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14896                        MultiBufferRow(selection.end.row - 1)
14897                    } else {
14898                        MultiBufferRow(selection.end.row)
14899                    };
14900                last_toggled_row = Some(end_row);
14901
14902                if start_row > end_row {
14903                    continue;
14904                }
14905
14906                // If the language has line comments, toggle those.
14907                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14908
14909                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14910                if ignore_indent {
14911                    full_comment_prefixes = full_comment_prefixes
14912                        .into_iter()
14913                        .map(|s| Arc::from(s.trim_end()))
14914                        .collect();
14915                }
14916
14917                if !full_comment_prefixes.is_empty() {
14918                    let first_prefix = full_comment_prefixes
14919                        .first()
14920                        .expect("prefixes is non-empty");
14921                    let prefix_trimmed_lengths = full_comment_prefixes
14922                        .iter()
14923                        .map(|p| p.trim_end_matches(' ').len())
14924                        .collect::<SmallVec<[usize; 4]>>();
14925
14926                    let mut all_selection_lines_are_comments = true;
14927
14928                    for row in start_row.0..=end_row.0 {
14929                        let row = MultiBufferRow(row);
14930                        if start_row < end_row && snapshot.is_line_blank(row) {
14931                            continue;
14932                        }
14933
14934                        let prefix_range = full_comment_prefixes
14935                            .iter()
14936                            .zip(prefix_trimmed_lengths.iter().copied())
14937                            .map(|(prefix, trimmed_prefix_len)| {
14938                                comment_prefix_range(
14939                                    snapshot.deref(),
14940                                    row,
14941                                    &prefix[..trimmed_prefix_len],
14942                                    &prefix[trimmed_prefix_len..],
14943                                    ignore_indent,
14944                                )
14945                            })
14946                            .max_by_key(|range| range.end.column - range.start.column)
14947                            .expect("prefixes is non-empty");
14948
14949                        if prefix_range.is_empty() {
14950                            all_selection_lines_are_comments = false;
14951                        }
14952
14953                        selection_edit_ranges.push(prefix_range);
14954                    }
14955
14956                    if all_selection_lines_are_comments {
14957                        edits.extend(
14958                            selection_edit_ranges
14959                                .iter()
14960                                .cloned()
14961                                .map(|range| (range, empty_str.clone())),
14962                        );
14963                    } else {
14964                        let min_column = selection_edit_ranges
14965                            .iter()
14966                            .map(|range| range.start.column)
14967                            .min()
14968                            .unwrap_or(0);
14969                        edits.extend(selection_edit_ranges.iter().map(|range| {
14970                            let position = Point::new(range.start.row, min_column);
14971                            (position..position, first_prefix.clone())
14972                        }));
14973                    }
14974                } else if let Some(BlockCommentConfig {
14975                    start: full_comment_prefix,
14976                    end: comment_suffix,
14977                    ..
14978                }) = language.block_comment()
14979                {
14980                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14981                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14982                    let prefix_range = comment_prefix_range(
14983                        snapshot.deref(),
14984                        start_row,
14985                        comment_prefix,
14986                        comment_prefix_whitespace,
14987                        ignore_indent,
14988                    );
14989                    let suffix_range = comment_suffix_range(
14990                        snapshot.deref(),
14991                        end_row,
14992                        comment_suffix.trim_start_matches(' '),
14993                        comment_suffix.starts_with(' '),
14994                    );
14995
14996                    if prefix_range.is_empty() || suffix_range.is_empty() {
14997                        edits.push((
14998                            prefix_range.start..prefix_range.start,
14999                            full_comment_prefix.clone(),
15000                        ));
15001                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15002                        suffixes_inserted.push((end_row, comment_suffix.len()));
15003                    } else {
15004                        edits.push((prefix_range, empty_str.clone()));
15005                        edits.push((suffix_range, empty_str.clone()));
15006                    }
15007                } else {
15008                    continue;
15009                }
15010            }
15011
15012            drop(snapshot);
15013            this.buffer.update(cx, |buffer, cx| {
15014                buffer.edit(edits, None, cx);
15015            });
15016
15017            // Adjust selections so that they end before any comment suffixes that
15018            // were inserted.
15019            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15020            let mut selections = this.selections.all::<Point>(cx);
15021            let snapshot = this.buffer.read(cx).read(cx);
15022            for selection in &mut selections {
15023                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15024                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15025                        Ordering::Less => {
15026                            suffixes_inserted.next();
15027                            continue;
15028                        }
15029                        Ordering::Greater => break,
15030                        Ordering::Equal => {
15031                            if selection.end.column == snapshot.line_len(row) {
15032                                if selection.is_empty() {
15033                                    selection.start.column -= suffix_len as u32;
15034                                }
15035                                selection.end.column -= suffix_len as u32;
15036                            }
15037                            break;
15038                        }
15039                    }
15040                }
15041            }
15042
15043            drop(snapshot);
15044            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15045
15046            let selections = this.selections.all::<Point>(cx);
15047            let selections_on_single_row = selections.windows(2).all(|selections| {
15048                selections[0].start.row == selections[1].start.row
15049                    && selections[0].end.row == selections[1].end.row
15050                    && selections[0].start.row == selections[0].end.row
15051            });
15052            let selections_selecting = selections
15053                .iter()
15054                .any(|selection| selection.start != selection.end);
15055            let advance_downwards = action.advance_downwards
15056                && selections_on_single_row
15057                && !selections_selecting
15058                && !matches!(this.mode, EditorMode::SingleLine);
15059
15060            if advance_downwards {
15061                let snapshot = this.buffer.read(cx).snapshot(cx);
15062
15063                this.change_selections(Default::default(), window, cx, |s| {
15064                    s.move_cursors_with(|display_snapshot, display_point, _| {
15065                        let mut point = display_point.to_point(display_snapshot);
15066                        point.row += 1;
15067                        point = snapshot.clip_point(point, Bias::Left);
15068                        let display_point = point.to_display_point(display_snapshot);
15069                        let goal = SelectionGoal::HorizontalPosition(
15070                            display_snapshot
15071                                .x_for_display_point(display_point, text_layout_details)
15072                                .into(),
15073                        );
15074                        (display_point, goal)
15075                    })
15076                });
15077            }
15078        });
15079    }
15080
15081    pub fn select_enclosing_symbol(
15082        &mut self,
15083        _: &SelectEnclosingSymbol,
15084        window: &mut Window,
15085        cx: &mut Context<Self>,
15086    ) {
15087        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15088
15089        let buffer = self.buffer.read(cx).snapshot(cx);
15090        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15091
15092        fn update_selection(
15093            selection: &Selection<usize>,
15094            buffer_snap: &MultiBufferSnapshot,
15095        ) -> Option<Selection<usize>> {
15096            let cursor = selection.head();
15097            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15098            for symbol in symbols.iter().rev() {
15099                let start = symbol.range.start.to_offset(buffer_snap);
15100                let end = symbol.range.end.to_offset(buffer_snap);
15101                let new_range = start..end;
15102                if start < selection.start || end > selection.end {
15103                    return Some(Selection {
15104                        id: selection.id,
15105                        start: new_range.start,
15106                        end: new_range.end,
15107                        goal: SelectionGoal::None,
15108                        reversed: selection.reversed,
15109                    });
15110                }
15111            }
15112            None
15113        }
15114
15115        let mut selected_larger_symbol = false;
15116        let new_selections = old_selections
15117            .iter()
15118            .map(|selection| match update_selection(selection, &buffer) {
15119                Some(new_selection) => {
15120                    if new_selection.range() != selection.range() {
15121                        selected_larger_symbol = true;
15122                    }
15123                    new_selection
15124                }
15125                None => selection.clone(),
15126            })
15127            .collect::<Vec<_>>();
15128
15129        if selected_larger_symbol {
15130            self.change_selections(Default::default(), window, cx, |s| {
15131                s.select(new_selections);
15132            });
15133        }
15134    }
15135
15136    pub fn select_larger_syntax_node(
15137        &mut self,
15138        _: &SelectLargerSyntaxNode,
15139        window: &mut Window,
15140        cx: &mut Context<Self>,
15141    ) {
15142        let Some(visible_row_count) = self.visible_row_count() else {
15143            return;
15144        };
15145        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15146        if old_selections.is_empty() {
15147            return;
15148        }
15149
15150        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15151
15152        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15153        let buffer = self.buffer.read(cx).snapshot(cx);
15154
15155        let mut selected_larger_node = false;
15156        let mut new_selections = old_selections
15157            .iter()
15158            .map(|selection| {
15159                let old_range = selection.start..selection.end;
15160
15161                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15162                    // manually select word at selection
15163                    if ["string_content", "inline"].contains(&node.kind()) {
15164                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15165                        // ignore if word is already selected
15166                        if !word_range.is_empty() && old_range != word_range {
15167                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15168                            // only select word if start and end point belongs to same word
15169                            if word_range == last_word_range {
15170                                selected_larger_node = true;
15171                                return Selection {
15172                                    id: selection.id,
15173                                    start: word_range.start,
15174                                    end: word_range.end,
15175                                    goal: SelectionGoal::None,
15176                                    reversed: selection.reversed,
15177                                };
15178                            }
15179                        }
15180                    }
15181                }
15182
15183                let mut new_range = old_range.clone();
15184                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15185                    new_range = range;
15186                    if !node.is_named() {
15187                        continue;
15188                    }
15189                    if !display_map.intersects_fold(new_range.start)
15190                        && !display_map.intersects_fold(new_range.end)
15191                    {
15192                        break;
15193                    }
15194                }
15195
15196                selected_larger_node |= new_range != old_range;
15197                Selection {
15198                    id: selection.id,
15199                    start: new_range.start,
15200                    end: new_range.end,
15201                    goal: SelectionGoal::None,
15202                    reversed: selection.reversed,
15203                }
15204            })
15205            .collect::<Vec<_>>();
15206
15207        if !selected_larger_node {
15208            return; // don't put this call in the history
15209        }
15210
15211        // scroll based on transformation done to the last selection created by the user
15212        let (last_old, last_new) = old_selections
15213            .last()
15214            .zip(new_selections.last().cloned())
15215            .expect("old_selections isn't empty");
15216
15217        // revert selection
15218        let is_selection_reversed = {
15219            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15220            new_selections.last_mut().expect("checked above").reversed =
15221                should_newest_selection_be_reversed;
15222            should_newest_selection_be_reversed
15223        };
15224
15225        if selected_larger_node {
15226            self.select_syntax_node_history.disable_clearing = true;
15227            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15228                s.select(new_selections.clone());
15229            });
15230            self.select_syntax_node_history.disable_clearing = false;
15231        }
15232
15233        let start_row = last_new.start.to_display_point(&display_map).row().0;
15234        let end_row = last_new.end.to_display_point(&display_map).row().0;
15235        let selection_height = end_row - start_row + 1;
15236        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15237
15238        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15239        let scroll_behavior = if fits_on_the_screen {
15240            self.request_autoscroll(Autoscroll::fit(), cx);
15241            SelectSyntaxNodeScrollBehavior::FitSelection
15242        } else if is_selection_reversed {
15243            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15244            SelectSyntaxNodeScrollBehavior::CursorTop
15245        } else {
15246            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15247            SelectSyntaxNodeScrollBehavior::CursorBottom
15248        };
15249
15250        self.select_syntax_node_history.push((
15251            old_selections,
15252            scroll_behavior,
15253            is_selection_reversed,
15254        ));
15255    }
15256
15257    pub fn select_smaller_syntax_node(
15258        &mut self,
15259        _: &SelectSmallerSyntaxNode,
15260        window: &mut Window,
15261        cx: &mut Context<Self>,
15262    ) {
15263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15264
15265        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15266            self.select_syntax_node_history.pop()
15267        {
15268            if let Some(selection) = selections.last_mut() {
15269                selection.reversed = is_selection_reversed;
15270            }
15271
15272            self.select_syntax_node_history.disable_clearing = true;
15273            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15274                s.select(selections.to_vec());
15275            });
15276            self.select_syntax_node_history.disable_clearing = false;
15277
15278            match scroll_behavior {
15279                SelectSyntaxNodeScrollBehavior::CursorTop => {
15280                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15281                }
15282                SelectSyntaxNodeScrollBehavior::FitSelection => {
15283                    self.request_autoscroll(Autoscroll::fit(), cx);
15284                }
15285                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15286                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15287                }
15288            }
15289        }
15290    }
15291
15292    pub fn unwrap_syntax_node(
15293        &mut self,
15294        _: &UnwrapSyntaxNode,
15295        window: &mut Window,
15296        cx: &mut Context<Self>,
15297    ) {
15298        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15299
15300        let buffer = self.buffer.read(cx).snapshot(cx);
15301        let selections = self
15302            .selections
15303            .all::<usize>(cx)
15304            .into_iter()
15305            // subtracting the offset requires sorting
15306            .sorted_by_key(|i| i.start);
15307
15308        let full_edits = selections
15309            .into_iter()
15310            .filter_map(|selection| {
15311                let child = if selection.is_empty()
15312                    && let Some((_, ancestor_range)) =
15313                        buffer.syntax_ancestor(selection.start..selection.end)
15314                {
15315                    ancestor_range
15316                } else {
15317                    selection.range()
15318                };
15319
15320                let mut parent = child.clone();
15321                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15322                    parent = ancestor_range;
15323                    if parent.start < child.start || parent.end > child.end {
15324                        break;
15325                    }
15326                }
15327
15328                if parent == child {
15329                    return None;
15330                }
15331                let text = buffer.text_for_range(child).collect::<String>();
15332                Some((selection.id, parent, text))
15333            })
15334            .collect::<Vec<_>>();
15335        if full_edits.is_empty() {
15336            return;
15337        }
15338
15339        self.transact(window, cx, |this, window, cx| {
15340            this.buffer.update(cx, |buffer, cx| {
15341                buffer.edit(
15342                    full_edits
15343                        .iter()
15344                        .map(|(_, p, t)| (p.clone(), t.clone()))
15345                        .collect::<Vec<_>>(),
15346                    None,
15347                    cx,
15348                );
15349            });
15350            this.change_selections(Default::default(), window, cx, |s| {
15351                let mut offset = 0;
15352                let mut selections = vec![];
15353                for (id, parent, text) in full_edits {
15354                    let start = parent.start - offset;
15355                    offset += parent.len() - text.len();
15356                    selections.push(Selection {
15357                        id,
15358                        start,
15359                        end: start + text.len(),
15360                        reversed: false,
15361                        goal: Default::default(),
15362                    });
15363                }
15364                s.select(selections);
15365            });
15366        });
15367    }
15368
15369    pub fn select_next_syntax_node(
15370        &mut self,
15371        _: &SelectNextSyntaxNode,
15372        window: &mut Window,
15373        cx: &mut Context<Self>,
15374    ) {
15375        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15376        if old_selections.is_empty() {
15377            return;
15378        }
15379
15380        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15381
15382        let buffer = self.buffer.read(cx).snapshot(cx);
15383        let mut selected_sibling = false;
15384
15385        let new_selections = old_selections
15386            .iter()
15387            .map(|selection| {
15388                let old_range = selection.start..selection.end;
15389
15390                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15391                    let new_range = node.byte_range();
15392                    selected_sibling = true;
15393                    Selection {
15394                        id: selection.id,
15395                        start: new_range.start,
15396                        end: new_range.end,
15397                        goal: SelectionGoal::None,
15398                        reversed: selection.reversed,
15399                    }
15400                } else {
15401                    selection.clone()
15402                }
15403            })
15404            .collect::<Vec<_>>();
15405
15406        if selected_sibling {
15407            self.change_selections(
15408                SelectionEffects::scroll(Autoscroll::fit()),
15409                window,
15410                cx,
15411                |s| {
15412                    s.select(new_selections);
15413                },
15414            );
15415        }
15416    }
15417
15418    pub fn select_prev_syntax_node(
15419        &mut self,
15420        _: &SelectPreviousSyntaxNode,
15421        window: &mut Window,
15422        cx: &mut Context<Self>,
15423    ) {
15424        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15425        if old_selections.is_empty() {
15426            return;
15427        }
15428
15429        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15430
15431        let buffer = self.buffer.read(cx).snapshot(cx);
15432        let mut selected_sibling = false;
15433
15434        let new_selections = old_selections
15435            .iter()
15436            .map(|selection| {
15437                let old_range = selection.start..selection.end;
15438
15439                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15440                    let new_range = node.byte_range();
15441                    selected_sibling = true;
15442                    Selection {
15443                        id: selection.id,
15444                        start: new_range.start,
15445                        end: new_range.end,
15446                        goal: SelectionGoal::None,
15447                        reversed: selection.reversed,
15448                    }
15449                } else {
15450                    selection.clone()
15451                }
15452            })
15453            .collect::<Vec<_>>();
15454
15455        if selected_sibling {
15456            self.change_selections(
15457                SelectionEffects::scroll(Autoscroll::fit()),
15458                window,
15459                cx,
15460                |s| {
15461                    s.select(new_selections);
15462                },
15463            );
15464        }
15465    }
15466
15467    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15468        if !EditorSettings::get_global(cx).gutter.runnables {
15469            self.clear_tasks();
15470            return Task::ready(());
15471        }
15472        let project = self.project().map(Entity::downgrade);
15473        let task_sources = self.lsp_task_sources(cx);
15474        let multi_buffer = self.buffer.downgrade();
15475        cx.spawn_in(window, async move |editor, cx| {
15476            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15477            let Some(project) = project.and_then(|p| p.upgrade()) else {
15478                return;
15479            };
15480            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15481                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15482            }) else {
15483                return;
15484            };
15485
15486            let hide_runnables = project
15487                .update(cx, |project, _| project.is_via_collab())
15488                .unwrap_or(true);
15489            if hide_runnables {
15490                return;
15491            }
15492            let new_rows =
15493                cx.background_spawn({
15494                    let snapshot = display_snapshot.clone();
15495                    async move {
15496                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15497                    }
15498                })
15499                    .await;
15500            let Ok(lsp_tasks) =
15501                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15502            else {
15503                return;
15504            };
15505            let lsp_tasks = lsp_tasks.await;
15506
15507            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15508                lsp_tasks
15509                    .into_iter()
15510                    .flat_map(|(kind, tasks)| {
15511                        tasks.into_iter().filter_map(move |(location, task)| {
15512                            Some((kind.clone(), location?, task))
15513                        })
15514                    })
15515                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15516                        let buffer = location.target.buffer;
15517                        let buffer_snapshot = buffer.read(cx).snapshot();
15518                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15519                            |(excerpt_id, snapshot, _)| {
15520                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15521                                    display_snapshot
15522                                        .buffer_snapshot
15523                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15524                                } else {
15525                                    None
15526                                }
15527                            },
15528                        );
15529                        if let Some(offset) = offset {
15530                            let task_buffer_range =
15531                                location.target.range.to_point(&buffer_snapshot);
15532                            let context_buffer_range =
15533                                task_buffer_range.to_offset(&buffer_snapshot);
15534                            let context_range = BufferOffset(context_buffer_range.start)
15535                                ..BufferOffset(context_buffer_range.end);
15536
15537                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15538                                .or_insert_with(|| RunnableTasks {
15539                                    templates: Vec::new(),
15540                                    offset,
15541                                    column: task_buffer_range.start.column,
15542                                    extra_variables: HashMap::default(),
15543                                    context_range,
15544                                })
15545                                .templates
15546                                .push((kind, task.original_task().clone()));
15547                        }
15548
15549                        acc
15550                    })
15551            }) else {
15552                return;
15553            };
15554
15555            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15556                buffer.language_settings(cx).tasks.prefer_lsp
15557            }) else {
15558                return;
15559            };
15560
15561            let rows = Self::runnable_rows(
15562                project,
15563                display_snapshot,
15564                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15565                new_rows,
15566                cx.clone(),
15567            )
15568            .await;
15569            editor
15570                .update(cx, |editor, _| {
15571                    editor.clear_tasks();
15572                    for (key, mut value) in rows {
15573                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15574                            value.templates.extend(lsp_tasks.templates);
15575                        }
15576
15577                        editor.insert_tasks(key, value);
15578                    }
15579                    for (key, value) in lsp_tasks_by_rows {
15580                        editor.insert_tasks(key, value);
15581                    }
15582                })
15583                .ok();
15584        })
15585    }
15586    fn fetch_runnable_ranges(
15587        snapshot: &DisplaySnapshot,
15588        range: Range<Anchor>,
15589    ) -> Vec<language::RunnableRange> {
15590        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15591    }
15592
15593    fn runnable_rows(
15594        project: Entity<Project>,
15595        snapshot: DisplaySnapshot,
15596        prefer_lsp: bool,
15597        runnable_ranges: Vec<RunnableRange>,
15598        cx: AsyncWindowContext,
15599    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15600        cx.spawn(async move |cx| {
15601            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15602            for mut runnable in runnable_ranges {
15603                let Some(tasks) = cx
15604                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15605                    .ok()
15606                else {
15607                    continue;
15608                };
15609                let mut tasks = tasks.await;
15610
15611                if prefer_lsp {
15612                    tasks.retain(|(task_kind, _)| {
15613                        !matches!(task_kind, TaskSourceKind::Language { .. })
15614                    });
15615                }
15616                if tasks.is_empty() {
15617                    continue;
15618                }
15619
15620                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15621                let Some(row) = snapshot
15622                    .buffer_snapshot
15623                    .buffer_line_for_row(MultiBufferRow(point.row))
15624                    .map(|(_, range)| range.start.row)
15625                else {
15626                    continue;
15627                };
15628
15629                let context_range =
15630                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15631                runnable_rows.push((
15632                    (runnable.buffer_id, row),
15633                    RunnableTasks {
15634                        templates: tasks,
15635                        offset: snapshot
15636                            .buffer_snapshot
15637                            .anchor_before(runnable.run_range.start),
15638                        context_range,
15639                        column: point.column,
15640                        extra_variables: runnable.extra_captures,
15641                    },
15642                ));
15643            }
15644            runnable_rows
15645        })
15646    }
15647
15648    fn templates_with_tags(
15649        project: &Entity<Project>,
15650        runnable: &mut Runnable,
15651        cx: &mut App,
15652    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15653        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15654            let (worktree_id, file) = project
15655                .buffer_for_id(runnable.buffer, cx)
15656                .and_then(|buffer| buffer.read(cx).file())
15657                .map(|file| (file.worktree_id(cx), file.clone()))
15658                .unzip();
15659
15660            (
15661                project.task_store().read(cx).task_inventory().cloned(),
15662                worktree_id,
15663                file,
15664            )
15665        });
15666
15667        let tags = mem::take(&mut runnable.tags);
15668        let language = runnable.language.clone();
15669        cx.spawn(async move |cx| {
15670            let mut templates_with_tags = Vec::new();
15671            if let Some(inventory) = inventory {
15672                for RunnableTag(tag) in tags {
15673                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15674                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15675                    }) else {
15676                        return templates_with_tags;
15677                    };
15678                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15679                        move |(_, template)| {
15680                            template.tags.iter().any(|source_tag| source_tag == &tag)
15681                        },
15682                    ));
15683                }
15684            }
15685            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15686
15687            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15688                // Strongest source wins; if we have worktree tag binding, prefer that to
15689                // global and language bindings;
15690                // if we have a global binding, prefer that to language binding.
15691                let first_mismatch = templates_with_tags
15692                    .iter()
15693                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15694                if let Some(index) = first_mismatch {
15695                    templates_with_tags.truncate(index);
15696                }
15697            }
15698
15699            templates_with_tags
15700        })
15701    }
15702
15703    pub fn move_to_enclosing_bracket(
15704        &mut self,
15705        _: &MoveToEnclosingBracket,
15706        window: &mut Window,
15707        cx: &mut Context<Self>,
15708    ) {
15709        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15710        self.change_selections(Default::default(), window, cx, |s| {
15711            s.move_offsets_with(|snapshot, selection| {
15712                let Some(enclosing_bracket_ranges) =
15713                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15714                else {
15715                    return;
15716                };
15717
15718                let mut best_length = usize::MAX;
15719                let mut best_inside = false;
15720                let mut best_in_bracket_range = false;
15721                let mut best_destination = None;
15722                for (open, close) in enclosing_bracket_ranges {
15723                    let close = close.to_inclusive();
15724                    let length = close.end() - open.start;
15725                    let inside = selection.start >= open.end && selection.end <= *close.start();
15726                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15727                        || close.contains(&selection.head());
15728
15729                    // If best is next to a bracket and current isn't, skip
15730                    if !in_bracket_range && best_in_bracket_range {
15731                        continue;
15732                    }
15733
15734                    // Prefer smaller lengths unless best is inside and current isn't
15735                    if length > best_length && (best_inside || !inside) {
15736                        continue;
15737                    }
15738
15739                    best_length = length;
15740                    best_inside = inside;
15741                    best_in_bracket_range = in_bracket_range;
15742                    best_destination = Some(
15743                        if close.contains(&selection.start) && close.contains(&selection.end) {
15744                            if inside { open.end } else { open.start }
15745                        } else if inside {
15746                            *close.start()
15747                        } else {
15748                            *close.end()
15749                        },
15750                    );
15751                }
15752
15753                if let Some(destination) = best_destination {
15754                    selection.collapse_to(destination, SelectionGoal::None);
15755                }
15756            })
15757        });
15758    }
15759
15760    pub fn undo_selection(
15761        &mut self,
15762        _: &UndoSelection,
15763        window: &mut Window,
15764        cx: &mut Context<Self>,
15765    ) {
15766        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15767        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15768            self.selection_history.mode = SelectionHistoryMode::Undoing;
15769            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15770                this.end_selection(window, cx);
15771                this.change_selections(
15772                    SelectionEffects::scroll(Autoscroll::newest()),
15773                    window,
15774                    cx,
15775                    |s| s.select_anchors(entry.selections.to_vec()),
15776                );
15777            });
15778            self.selection_history.mode = SelectionHistoryMode::Normal;
15779
15780            self.select_next_state = entry.select_next_state;
15781            self.select_prev_state = entry.select_prev_state;
15782            self.add_selections_state = entry.add_selections_state;
15783        }
15784    }
15785
15786    pub fn redo_selection(
15787        &mut self,
15788        _: &RedoSelection,
15789        window: &mut Window,
15790        cx: &mut Context<Self>,
15791    ) {
15792        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15793        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15794            self.selection_history.mode = SelectionHistoryMode::Redoing;
15795            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15796                this.end_selection(window, cx);
15797                this.change_selections(
15798                    SelectionEffects::scroll(Autoscroll::newest()),
15799                    window,
15800                    cx,
15801                    |s| s.select_anchors(entry.selections.to_vec()),
15802                );
15803            });
15804            self.selection_history.mode = SelectionHistoryMode::Normal;
15805
15806            self.select_next_state = entry.select_next_state;
15807            self.select_prev_state = entry.select_prev_state;
15808            self.add_selections_state = entry.add_selections_state;
15809        }
15810    }
15811
15812    pub fn expand_excerpts(
15813        &mut self,
15814        action: &ExpandExcerpts,
15815        _: &mut Window,
15816        cx: &mut Context<Self>,
15817    ) {
15818        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15819    }
15820
15821    pub fn expand_excerpts_down(
15822        &mut self,
15823        action: &ExpandExcerptsDown,
15824        _: &mut Window,
15825        cx: &mut Context<Self>,
15826    ) {
15827        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15828    }
15829
15830    pub fn expand_excerpts_up(
15831        &mut self,
15832        action: &ExpandExcerptsUp,
15833        _: &mut Window,
15834        cx: &mut Context<Self>,
15835    ) {
15836        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15837    }
15838
15839    pub fn expand_excerpts_for_direction(
15840        &mut self,
15841        lines: u32,
15842        direction: ExpandExcerptDirection,
15843
15844        cx: &mut Context<Self>,
15845    ) {
15846        let selections = self.selections.disjoint_anchors_arc();
15847
15848        let lines = if lines == 0 {
15849            EditorSettings::get_global(cx).expand_excerpt_lines
15850        } else {
15851            lines
15852        };
15853
15854        self.buffer.update(cx, |buffer, cx| {
15855            let snapshot = buffer.snapshot(cx);
15856            let mut excerpt_ids = selections
15857                .iter()
15858                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15859                .collect::<Vec<_>>();
15860            excerpt_ids.sort();
15861            excerpt_ids.dedup();
15862            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15863        })
15864    }
15865
15866    pub fn expand_excerpt(
15867        &mut self,
15868        excerpt: ExcerptId,
15869        direction: ExpandExcerptDirection,
15870        window: &mut Window,
15871        cx: &mut Context<Self>,
15872    ) {
15873        let current_scroll_position = self.scroll_position(cx);
15874        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15875        let mut should_scroll_up = false;
15876
15877        if direction == ExpandExcerptDirection::Down {
15878            let multi_buffer = self.buffer.read(cx);
15879            let snapshot = multi_buffer.snapshot(cx);
15880            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15881                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15882                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15883            {
15884                let buffer_snapshot = buffer.read(cx).snapshot();
15885                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15886                let last_row = buffer_snapshot.max_point().row;
15887                let lines_below = last_row.saturating_sub(excerpt_end_row);
15888                should_scroll_up = lines_below >= lines_to_expand;
15889            }
15890        }
15891
15892        self.buffer.update(cx, |buffer, cx| {
15893            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15894        });
15895
15896        if should_scroll_up {
15897            let new_scroll_position =
15898                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15899            self.set_scroll_position(new_scroll_position, window, cx);
15900        }
15901    }
15902
15903    pub fn go_to_singleton_buffer_point(
15904        &mut self,
15905        point: Point,
15906        window: &mut Window,
15907        cx: &mut Context<Self>,
15908    ) {
15909        self.go_to_singleton_buffer_range(point..point, window, cx);
15910    }
15911
15912    pub fn go_to_singleton_buffer_range(
15913        &mut self,
15914        range: Range<Point>,
15915        window: &mut Window,
15916        cx: &mut Context<Self>,
15917    ) {
15918        let multibuffer = self.buffer().read(cx);
15919        let Some(buffer) = multibuffer.as_singleton() else {
15920            return;
15921        };
15922        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15923            return;
15924        };
15925        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15926            return;
15927        };
15928        self.change_selections(
15929            SelectionEffects::default().nav_history(true),
15930            window,
15931            cx,
15932            |s| s.select_anchor_ranges([start..end]),
15933        );
15934    }
15935
15936    pub fn go_to_diagnostic(
15937        &mut self,
15938        action: &GoToDiagnostic,
15939        window: &mut Window,
15940        cx: &mut Context<Self>,
15941    ) {
15942        if !self.diagnostics_enabled() {
15943            return;
15944        }
15945        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15946        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15947    }
15948
15949    pub fn go_to_prev_diagnostic(
15950        &mut self,
15951        action: &GoToPreviousDiagnostic,
15952        window: &mut Window,
15953        cx: &mut Context<Self>,
15954    ) {
15955        if !self.diagnostics_enabled() {
15956            return;
15957        }
15958        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15959        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15960    }
15961
15962    pub fn go_to_diagnostic_impl(
15963        &mut self,
15964        direction: Direction,
15965        severity: GoToDiagnosticSeverityFilter,
15966        window: &mut Window,
15967        cx: &mut Context<Self>,
15968    ) {
15969        let buffer = self.buffer.read(cx).snapshot(cx);
15970        let selection = self.selections.newest::<usize>(cx);
15971
15972        let mut active_group_id = None;
15973        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15974            && active_group.active_range.start.to_offset(&buffer) == selection.start
15975        {
15976            active_group_id = Some(active_group.group_id);
15977        }
15978
15979        fn filtered<'a>(
15980            snapshot: EditorSnapshot,
15981            severity: GoToDiagnosticSeverityFilter,
15982            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
15983        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
15984            diagnostics
15985                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15986                .filter(|entry| entry.range.start != entry.range.end)
15987                .filter(|entry| !entry.diagnostic.is_unnecessary)
15988                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15989        }
15990
15991        let snapshot = self.snapshot(window, cx);
15992        let before = filtered(
15993            snapshot.clone(),
15994            severity,
15995            buffer
15996                .diagnostics_in_range(0..selection.start)
15997                .filter(|entry| entry.range.start <= selection.start),
15998        );
15999        let after = filtered(
16000            snapshot,
16001            severity,
16002            buffer
16003                .diagnostics_in_range(selection.start..buffer.len())
16004                .filter(|entry| entry.range.start >= selection.start),
16005        );
16006
16007        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16008        if direction == Direction::Prev {
16009            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16010            {
16011                for diagnostic in prev_diagnostics.into_iter().rev() {
16012                    if diagnostic.range.start != selection.start
16013                        || active_group_id
16014                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16015                    {
16016                        found = Some(diagnostic);
16017                        break 'outer;
16018                    }
16019                }
16020            }
16021        } else {
16022            for diagnostic in after.chain(before) {
16023                if diagnostic.range.start != selection.start
16024                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16025                {
16026                    found = Some(diagnostic);
16027                    break;
16028                }
16029            }
16030        }
16031        let Some(next_diagnostic) = found else {
16032            return;
16033        };
16034
16035        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16036        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16037            return;
16038        };
16039        self.change_selections(Default::default(), window, cx, |s| {
16040            s.select_ranges(vec![
16041                next_diagnostic.range.start..next_diagnostic.range.start,
16042            ])
16043        });
16044        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16045        self.refresh_edit_prediction(false, true, window, cx);
16046    }
16047
16048    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16049        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16050        let snapshot = self.snapshot(window, cx);
16051        let selection = self.selections.newest::<Point>(cx);
16052        self.go_to_hunk_before_or_after_position(
16053            &snapshot,
16054            selection.head(),
16055            Direction::Next,
16056            window,
16057            cx,
16058        );
16059    }
16060
16061    pub fn go_to_hunk_before_or_after_position(
16062        &mut self,
16063        snapshot: &EditorSnapshot,
16064        position: Point,
16065        direction: Direction,
16066        window: &mut Window,
16067        cx: &mut Context<Editor>,
16068    ) {
16069        let row = if direction == Direction::Next {
16070            self.hunk_after_position(snapshot, position)
16071                .map(|hunk| hunk.row_range.start)
16072        } else {
16073            self.hunk_before_position(snapshot, position)
16074        };
16075
16076        if let Some(row) = row {
16077            let destination = Point::new(row.0, 0);
16078            let autoscroll = Autoscroll::center();
16079
16080            self.unfold_ranges(&[destination..destination], false, false, cx);
16081            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16082                s.select_ranges([destination..destination]);
16083            });
16084        }
16085    }
16086
16087    fn hunk_after_position(
16088        &mut self,
16089        snapshot: &EditorSnapshot,
16090        position: Point,
16091    ) -> Option<MultiBufferDiffHunk> {
16092        snapshot
16093            .buffer_snapshot
16094            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16095            .find(|hunk| hunk.row_range.start.0 > position.row)
16096            .or_else(|| {
16097                snapshot
16098                    .buffer_snapshot
16099                    .diff_hunks_in_range(Point::zero()..position)
16100                    .find(|hunk| hunk.row_range.end.0 < position.row)
16101            })
16102    }
16103
16104    fn go_to_prev_hunk(
16105        &mut self,
16106        _: &GoToPreviousHunk,
16107        window: &mut Window,
16108        cx: &mut Context<Self>,
16109    ) {
16110        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16111        let snapshot = self.snapshot(window, cx);
16112        let selection = self.selections.newest::<Point>(cx);
16113        self.go_to_hunk_before_or_after_position(
16114            &snapshot,
16115            selection.head(),
16116            Direction::Prev,
16117            window,
16118            cx,
16119        );
16120    }
16121
16122    fn hunk_before_position(
16123        &mut self,
16124        snapshot: &EditorSnapshot,
16125        position: Point,
16126    ) -> Option<MultiBufferRow> {
16127        snapshot
16128            .buffer_snapshot
16129            .diff_hunk_before(position)
16130            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
16131    }
16132
16133    fn go_to_next_change(
16134        &mut self,
16135        _: &GoToNextChange,
16136        window: &mut Window,
16137        cx: &mut Context<Self>,
16138    ) {
16139        if let Some(selections) = self
16140            .change_list
16141            .next_change(1, Direction::Next)
16142            .map(|s| s.to_vec())
16143        {
16144            self.change_selections(Default::default(), window, cx, |s| {
16145                let map = s.display_map();
16146                s.select_display_ranges(selections.iter().map(|a| {
16147                    let point = a.to_display_point(&map);
16148                    point..point
16149                }))
16150            })
16151        }
16152    }
16153
16154    fn go_to_previous_change(
16155        &mut self,
16156        _: &GoToPreviousChange,
16157        window: &mut Window,
16158        cx: &mut Context<Self>,
16159    ) {
16160        if let Some(selections) = self
16161            .change_list
16162            .next_change(1, Direction::Prev)
16163            .map(|s| s.to_vec())
16164        {
16165            self.change_selections(Default::default(), window, cx, |s| {
16166                let map = s.display_map();
16167                s.select_display_ranges(selections.iter().map(|a| {
16168                    let point = a.to_display_point(&map);
16169                    point..point
16170                }))
16171            })
16172        }
16173    }
16174
16175    pub fn go_to_next_document_highlight(
16176        &mut self,
16177        _: &GoToNextDocumentHighlight,
16178        window: &mut Window,
16179        cx: &mut Context<Self>,
16180    ) {
16181        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16182    }
16183
16184    pub fn go_to_prev_document_highlight(
16185        &mut self,
16186        _: &GoToPreviousDocumentHighlight,
16187        window: &mut Window,
16188        cx: &mut Context<Self>,
16189    ) {
16190        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16191    }
16192
16193    pub fn go_to_document_highlight_before_or_after_position(
16194        &mut self,
16195        direction: Direction,
16196        window: &mut Window,
16197        cx: &mut Context<Editor>,
16198    ) {
16199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16200        let snapshot = self.snapshot(window, cx);
16201        let buffer = &snapshot.buffer_snapshot;
16202        let position = self.selections.newest::<Point>(cx).head();
16203        let anchor_position = buffer.anchor_after(position);
16204
16205        // Get all document highlights (both read and write)
16206        let mut all_highlights = Vec::new();
16207
16208        if let Some((_, read_highlights)) = self
16209            .background_highlights
16210            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16211        {
16212            all_highlights.extend(read_highlights.iter());
16213        }
16214
16215        if let Some((_, write_highlights)) = self
16216            .background_highlights
16217            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16218        {
16219            all_highlights.extend(write_highlights.iter());
16220        }
16221
16222        if all_highlights.is_empty() {
16223            return;
16224        }
16225
16226        // Sort highlights by position
16227        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16228
16229        let target_highlight = match direction {
16230            Direction::Next => {
16231                // Find the first highlight after the current position
16232                all_highlights
16233                    .iter()
16234                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16235            }
16236            Direction::Prev => {
16237                // Find the last highlight before the current position
16238                all_highlights
16239                    .iter()
16240                    .rev()
16241                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16242            }
16243        };
16244
16245        if let Some(highlight) = target_highlight {
16246            let destination = highlight.start.to_point(buffer);
16247            let autoscroll = Autoscroll::center();
16248
16249            self.unfold_ranges(&[destination..destination], false, false, cx);
16250            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16251                s.select_ranges([destination..destination]);
16252            });
16253        }
16254    }
16255
16256    fn go_to_line<T: 'static>(
16257        &mut self,
16258        position: Anchor,
16259        highlight_color: Option<Hsla>,
16260        window: &mut Window,
16261        cx: &mut Context<Self>,
16262    ) {
16263        let snapshot = self.snapshot(window, cx).display_snapshot;
16264        let position = position.to_point(&snapshot.buffer_snapshot);
16265        let start = snapshot
16266            .buffer_snapshot
16267            .clip_point(Point::new(position.row, 0), Bias::Left);
16268        let end = start + Point::new(1, 0);
16269        let start = snapshot.buffer_snapshot.anchor_before(start);
16270        let end = snapshot.buffer_snapshot.anchor_before(end);
16271
16272        self.highlight_rows::<T>(
16273            start..end,
16274            highlight_color
16275                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16276            Default::default(),
16277            cx,
16278        );
16279
16280        if self.buffer.read(cx).is_singleton() {
16281            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16282        }
16283    }
16284
16285    pub fn go_to_definition(
16286        &mut self,
16287        _: &GoToDefinition,
16288        window: &mut Window,
16289        cx: &mut Context<Self>,
16290    ) -> Task<Result<Navigated>> {
16291        let definition =
16292            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16293        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16294        cx.spawn_in(window, async move |editor, cx| {
16295            if definition.await? == Navigated::Yes {
16296                return Ok(Navigated::Yes);
16297            }
16298            match fallback_strategy {
16299                GoToDefinitionFallback::None => Ok(Navigated::No),
16300                GoToDefinitionFallback::FindAllReferences => {
16301                    match editor.update_in(cx, |editor, window, cx| {
16302                        editor.find_all_references(&FindAllReferences, window, cx)
16303                    })? {
16304                        Some(references) => references.await,
16305                        None => Ok(Navigated::No),
16306                    }
16307                }
16308            }
16309        })
16310    }
16311
16312    pub fn go_to_declaration(
16313        &mut self,
16314        _: &GoToDeclaration,
16315        window: &mut Window,
16316        cx: &mut Context<Self>,
16317    ) -> Task<Result<Navigated>> {
16318        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16319    }
16320
16321    pub fn go_to_declaration_split(
16322        &mut self,
16323        _: &GoToDeclaration,
16324        window: &mut Window,
16325        cx: &mut Context<Self>,
16326    ) -> Task<Result<Navigated>> {
16327        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16328    }
16329
16330    pub fn go_to_implementation(
16331        &mut self,
16332        _: &GoToImplementation,
16333        window: &mut Window,
16334        cx: &mut Context<Self>,
16335    ) -> Task<Result<Navigated>> {
16336        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16337    }
16338
16339    pub fn go_to_implementation_split(
16340        &mut self,
16341        _: &GoToImplementationSplit,
16342        window: &mut Window,
16343        cx: &mut Context<Self>,
16344    ) -> Task<Result<Navigated>> {
16345        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16346    }
16347
16348    pub fn go_to_type_definition(
16349        &mut self,
16350        _: &GoToTypeDefinition,
16351        window: &mut Window,
16352        cx: &mut Context<Self>,
16353    ) -> Task<Result<Navigated>> {
16354        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16355    }
16356
16357    pub fn go_to_definition_split(
16358        &mut self,
16359        _: &GoToDefinitionSplit,
16360        window: &mut Window,
16361        cx: &mut Context<Self>,
16362    ) -> Task<Result<Navigated>> {
16363        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16364    }
16365
16366    pub fn go_to_type_definition_split(
16367        &mut self,
16368        _: &GoToTypeDefinitionSplit,
16369        window: &mut Window,
16370        cx: &mut Context<Self>,
16371    ) -> Task<Result<Navigated>> {
16372        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16373    }
16374
16375    fn go_to_definition_of_kind(
16376        &mut self,
16377        kind: GotoDefinitionKind,
16378        split: bool,
16379        window: &mut Window,
16380        cx: &mut Context<Self>,
16381    ) -> Task<Result<Navigated>> {
16382        let Some(provider) = self.semantics_provider.clone() else {
16383            return Task::ready(Ok(Navigated::No));
16384        };
16385        let head = self.selections.newest::<usize>(cx).head();
16386        let buffer = self.buffer.read(cx);
16387        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16388            return Task::ready(Ok(Navigated::No));
16389        };
16390        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16391            return Task::ready(Ok(Navigated::No));
16392        };
16393
16394        cx.spawn_in(window, async move |editor, cx| {
16395            let Some(definitions) = definitions.await? else {
16396                return Ok(Navigated::No);
16397            };
16398            let navigated = editor
16399                .update_in(cx, |editor, window, cx| {
16400                    editor.navigate_to_hover_links(
16401                        Some(kind),
16402                        definitions
16403                            .into_iter()
16404                            .filter(|location| {
16405                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16406                            })
16407                            .map(HoverLink::Text)
16408                            .collect::<Vec<_>>(),
16409                        split,
16410                        window,
16411                        cx,
16412                    )
16413                })?
16414                .await?;
16415            anyhow::Ok(navigated)
16416        })
16417    }
16418
16419    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16420        let selection = self.selections.newest_anchor();
16421        let head = selection.head();
16422        let tail = selection.tail();
16423
16424        let Some((buffer, start_position)) =
16425            self.buffer.read(cx).text_anchor_for_position(head, cx)
16426        else {
16427            return;
16428        };
16429
16430        let end_position = if head != tail {
16431            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16432                return;
16433            };
16434            Some(pos)
16435        } else {
16436            None
16437        };
16438
16439        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16440            let url = if let Some(end_pos) = end_position {
16441                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16442            } else {
16443                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16444            };
16445
16446            if let Some(url) = url {
16447                cx.update(|window, cx| {
16448                    if parse_zed_link(&url, cx).is_some() {
16449                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16450                    } else {
16451                        cx.open_url(&url);
16452                    }
16453                })?;
16454            }
16455
16456            anyhow::Ok(())
16457        });
16458
16459        url_finder.detach();
16460    }
16461
16462    pub fn open_selected_filename(
16463        &mut self,
16464        _: &OpenSelectedFilename,
16465        window: &mut Window,
16466        cx: &mut Context<Self>,
16467    ) {
16468        let Some(workspace) = self.workspace() else {
16469            return;
16470        };
16471
16472        let position = self.selections.newest_anchor().head();
16473
16474        let Some((buffer, buffer_position)) =
16475            self.buffer.read(cx).text_anchor_for_position(position, cx)
16476        else {
16477            return;
16478        };
16479
16480        let project = self.project.clone();
16481
16482        cx.spawn_in(window, async move |_, cx| {
16483            let result = find_file(&buffer, project, buffer_position, cx).await;
16484
16485            if let Some((_, path)) = result {
16486                workspace
16487                    .update_in(cx, |workspace, window, cx| {
16488                        workspace.open_resolved_path(path, window, cx)
16489                    })?
16490                    .await?;
16491            }
16492            anyhow::Ok(())
16493        })
16494        .detach();
16495    }
16496
16497    pub(crate) fn navigate_to_hover_links(
16498        &mut self,
16499        kind: Option<GotoDefinitionKind>,
16500        definitions: Vec<HoverLink>,
16501        split: bool,
16502        window: &mut Window,
16503        cx: &mut Context<Editor>,
16504    ) -> Task<Result<Navigated>> {
16505        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16506        let mut first_url_or_file = None;
16507        let definitions: Vec<_> = definitions
16508            .into_iter()
16509            .filter_map(|def| match def {
16510                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16511                HoverLink::InlayHint(lsp_location, server_id) => {
16512                    let computation =
16513                        self.compute_target_location(lsp_location, server_id, window, cx);
16514                    Some(cx.background_spawn(computation))
16515                }
16516                HoverLink::Url(url) => {
16517                    first_url_or_file = Some(Either::Left(url));
16518                    None
16519                }
16520                HoverLink::File(path) => {
16521                    first_url_or_file = Some(Either::Right(path));
16522                    None
16523                }
16524            })
16525            .collect();
16526
16527        let workspace = self.workspace();
16528
16529        cx.spawn_in(window, async move |editor, cx| {
16530            let locations: Vec<Location> = future::join_all(definitions)
16531                .await
16532                .into_iter()
16533                .filter_map(|location| location.transpose())
16534                .collect::<Result<_>>()
16535                .context("location tasks")?;
16536            let mut locations = cx.update(|_, cx| {
16537                locations
16538                    .into_iter()
16539                    .map(|location| {
16540                        let buffer = location.buffer.read(cx);
16541                        (location.buffer, location.range.to_point(buffer))
16542                    })
16543                    .into_group_map()
16544            })?;
16545            let mut num_locations = 0;
16546            for ranges in locations.values_mut() {
16547                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16548                ranges.dedup();
16549                num_locations += ranges.len();
16550            }
16551
16552            if num_locations > 1 {
16553                let Some(workspace) = workspace else {
16554                    return Ok(Navigated::No);
16555                };
16556
16557                let tab_kind = match kind {
16558                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16559                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16560                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16561                    Some(GotoDefinitionKind::Type) => "Types",
16562                };
16563                let title = editor
16564                    .update_in(cx, |_, _, cx| {
16565                        let target = locations
16566                            .iter()
16567                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16568                            .map(|(buffer, location)| {
16569                                buffer
16570                                    .read(cx)
16571                                    .text_for_range(location.clone())
16572                                    .collect::<String>()
16573                            })
16574                            .filter(|text| !text.contains('\n'))
16575                            .unique()
16576                            .take(3)
16577                            .join(", ");
16578                        if target.is_empty() {
16579                            tab_kind.to_owned()
16580                        } else {
16581                            format!("{tab_kind} for {target}")
16582                        }
16583                    })
16584                    .context("buffer title")?;
16585
16586                let opened = workspace
16587                    .update_in(cx, |workspace, window, cx| {
16588                        Self::open_locations_in_multibuffer(
16589                            workspace,
16590                            locations,
16591                            title,
16592                            split,
16593                            MultibufferSelectionMode::First,
16594                            window,
16595                            cx,
16596                        )
16597                    })
16598                    .is_ok();
16599
16600                anyhow::Ok(Navigated::from_bool(opened))
16601            } else if num_locations == 0 {
16602                // If there is one url or file, open it directly
16603                match first_url_or_file {
16604                    Some(Either::Left(url)) => {
16605                        cx.update(|_, cx| cx.open_url(&url))?;
16606                        Ok(Navigated::Yes)
16607                    }
16608                    Some(Either::Right(path)) => {
16609                        let Some(workspace) = workspace else {
16610                            return Ok(Navigated::No);
16611                        };
16612
16613                        workspace
16614                            .update_in(cx, |workspace, window, cx| {
16615                                workspace.open_resolved_path(path, window, cx)
16616                            })?
16617                            .await?;
16618                        Ok(Navigated::Yes)
16619                    }
16620                    None => Ok(Navigated::No),
16621                }
16622            } else {
16623                let Some(workspace) = workspace else {
16624                    return Ok(Navigated::No);
16625                };
16626
16627                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16628                let target_range = target_ranges.first().unwrap().clone();
16629
16630                editor.update_in(cx, |editor, window, cx| {
16631                    let range = target_range.to_point(target_buffer.read(cx));
16632                    let range = editor.range_for_match(&range);
16633                    let range = collapse_multiline_range(range);
16634
16635                    if !split
16636                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16637                    {
16638                        editor.go_to_singleton_buffer_range(range, window, cx);
16639                    } else {
16640                        let pane = workspace.read(cx).active_pane().clone();
16641                        window.defer(cx, move |window, cx| {
16642                            let target_editor: Entity<Self> =
16643                                workspace.update(cx, |workspace, cx| {
16644                                    let pane = if split {
16645                                        workspace.adjacent_pane(window, cx)
16646                                    } else {
16647                                        workspace.active_pane().clone()
16648                                    };
16649
16650                                    workspace.open_project_item(
16651                                        pane,
16652                                        target_buffer.clone(),
16653                                        true,
16654                                        true,
16655                                        window,
16656                                        cx,
16657                                    )
16658                                });
16659                            target_editor.update(cx, |target_editor, cx| {
16660                                // When selecting a definition in a different buffer, disable the nav history
16661                                // to avoid creating a history entry at the previous cursor location.
16662                                pane.update(cx, |pane, _| pane.disable_history());
16663                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16664                                pane.update(cx, |pane, _| pane.enable_history());
16665                            });
16666                        });
16667                    }
16668                    Navigated::Yes
16669                })
16670            }
16671        })
16672    }
16673
16674    fn compute_target_location(
16675        &self,
16676        lsp_location: lsp::Location,
16677        server_id: LanguageServerId,
16678        window: &mut Window,
16679        cx: &mut Context<Self>,
16680    ) -> Task<anyhow::Result<Option<Location>>> {
16681        let Some(project) = self.project.clone() else {
16682            return Task::ready(Ok(None));
16683        };
16684
16685        cx.spawn_in(window, async move |editor, cx| {
16686            let location_task = editor.update(cx, |_, cx| {
16687                project.update(cx, |project, cx| {
16688                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16689                })
16690            })?;
16691            let location = Some({
16692                let target_buffer_handle = location_task.await.context("open local buffer")?;
16693                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16694                    let target_start = target_buffer
16695                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16696                    let target_end = target_buffer
16697                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16698                    target_buffer.anchor_after(target_start)
16699                        ..target_buffer.anchor_before(target_end)
16700                })?;
16701                Location {
16702                    buffer: target_buffer_handle,
16703                    range,
16704                }
16705            });
16706            Ok(location)
16707        })
16708    }
16709
16710    pub fn find_all_references(
16711        &mut self,
16712        _: &FindAllReferences,
16713        window: &mut Window,
16714        cx: &mut Context<Self>,
16715    ) -> Option<Task<Result<Navigated>>> {
16716        let selection = self.selections.newest::<usize>(cx);
16717        let multi_buffer = self.buffer.read(cx);
16718        let head = selection.head();
16719
16720        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16721        let head_anchor = multi_buffer_snapshot.anchor_at(
16722            head,
16723            if head < selection.tail() {
16724                Bias::Right
16725            } else {
16726                Bias::Left
16727            },
16728        );
16729
16730        match self
16731            .find_all_references_task_sources
16732            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16733        {
16734            Ok(_) => {
16735                log::info!(
16736                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16737                );
16738                return None;
16739            }
16740            Err(i) => {
16741                self.find_all_references_task_sources.insert(i, head_anchor);
16742            }
16743        }
16744
16745        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16746        let workspace = self.workspace()?;
16747        let project = workspace.read(cx).project().clone();
16748        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16749        Some(cx.spawn_in(window, async move |editor, cx| {
16750            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16751                if let Ok(i) = editor
16752                    .find_all_references_task_sources
16753                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16754                {
16755                    editor.find_all_references_task_sources.remove(i);
16756                }
16757            });
16758
16759            let Some(locations) = references.await? else {
16760                return anyhow::Ok(Navigated::No);
16761            };
16762            let mut locations = cx.update(|_, cx| {
16763                locations
16764                    .into_iter()
16765                    .map(|location| {
16766                        let buffer = location.buffer.read(cx);
16767                        (location.buffer, location.range.to_point(buffer))
16768                    })
16769                    .into_group_map()
16770            })?;
16771            if locations.is_empty() {
16772                return anyhow::Ok(Navigated::No);
16773            }
16774            for ranges in locations.values_mut() {
16775                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16776                ranges.dedup();
16777            }
16778
16779            workspace.update_in(cx, |workspace, window, cx| {
16780                let target = locations
16781                    .iter()
16782                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16783                    .map(|(buffer, location)| {
16784                        buffer
16785                            .read(cx)
16786                            .text_for_range(location.clone())
16787                            .collect::<String>()
16788                    })
16789                    .filter(|text| !text.contains('\n'))
16790                    .unique()
16791                    .take(3)
16792                    .join(", ");
16793                let title = if target.is_empty() {
16794                    "References".to_owned()
16795                } else {
16796                    format!("References to {target}")
16797                };
16798                Self::open_locations_in_multibuffer(
16799                    workspace,
16800                    locations,
16801                    title,
16802                    false,
16803                    MultibufferSelectionMode::First,
16804                    window,
16805                    cx,
16806                );
16807                Navigated::Yes
16808            })
16809        }))
16810    }
16811
16812    /// Opens a multibuffer with the given project locations in it
16813    pub fn open_locations_in_multibuffer(
16814        workspace: &mut Workspace,
16815        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16816        title: String,
16817        split: bool,
16818        multibuffer_selection_mode: MultibufferSelectionMode,
16819        window: &mut Window,
16820        cx: &mut Context<Workspace>,
16821    ) {
16822        if locations.is_empty() {
16823            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16824            return;
16825        }
16826
16827        let capability = workspace.project().read(cx).capability();
16828        let mut ranges = <Vec<Range<Anchor>>>::new();
16829
16830        // a key to find existing multibuffer editors with the same set of locations
16831        // to prevent us from opening more and more multibuffer tabs for searches and the like
16832        let mut key = (title.clone(), vec![]);
16833        let excerpt_buffer = cx.new(|cx| {
16834            let key = &mut key.1;
16835            let mut multibuffer = MultiBuffer::new(capability);
16836            for (buffer, mut ranges_for_buffer) in locations {
16837                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16838                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16839                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16840                    PathKey::for_buffer(&buffer, cx),
16841                    buffer.clone(),
16842                    ranges_for_buffer,
16843                    multibuffer_context_lines(cx),
16844                    cx,
16845                );
16846                ranges.extend(new_ranges)
16847            }
16848
16849            multibuffer.with_title(title)
16850        });
16851        let existing = workspace.active_pane().update(cx, |pane, cx| {
16852            pane.items()
16853                .filter_map(|item| item.downcast::<Editor>())
16854                .find(|editor| {
16855                    editor
16856                        .read(cx)
16857                        .lookup_key
16858                        .as_ref()
16859                        .and_then(|it| {
16860                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16861                        })
16862                        .is_some_and(|it| *it == key)
16863                })
16864        });
16865        let editor = existing.unwrap_or_else(|| {
16866            cx.new(|cx| {
16867                let mut editor = Editor::for_multibuffer(
16868                    excerpt_buffer,
16869                    Some(workspace.project().clone()),
16870                    window,
16871                    cx,
16872                );
16873                editor.lookup_key = Some(Box::new(key));
16874                editor
16875            })
16876        });
16877        editor.update(cx, |editor, cx| {
16878            match multibuffer_selection_mode {
16879                MultibufferSelectionMode::First => {
16880                    if let Some(first_range) = ranges.first() {
16881                        editor.change_selections(
16882                            SelectionEffects::no_scroll(),
16883                            window,
16884                            cx,
16885                            |selections| {
16886                                selections.clear_disjoint();
16887                                selections
16888                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16889                            },
16890                        );
16891                    }
16892                    editor.highlight_background::<Self>(
16893                        &ranges,
16894                        |theme| theme.colors().editor_highlighted_line_background,
16895                        cx,
16896                    );
16897                }
16898                MultibufferSelectionMode::All => {
16899                    editor.change_selections(
16900                        SelectionEffects::no_scroll(),
16901                        window,
16902                        cx,
16903                        |selections| {
16904                            selections.clear_disjoint();
16905                            selections.select_anchor_ranges(ranges);
16906                        },
16907                    );
16908                }
16909            }
16910            editor.register_buffers_with_language_servers(cx);
16911        });
16912
16913        let item = Box::new(editor);
16914        let item_id = item.item_id();
16915
16916        if split {
16917            let pane = workspace.adjacent_pane(window, cx);
16918            workspace.add_item(pane, item, None, true, true, window, cx);
16919        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16920            let (preview_item_id, preview_item_idx) =
16921                workspace.active_pane().read_with(cx, |pane, _| {
16922                    (pane.preview_item_id(), pane.preview_item_idx())
16923                });
16924
16925            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16926
16927            if let Some(preview_item_id) = preview_item_id {
16928                workspace.active_pane().update(cx, |pane, cx| {
16929                    pane.remove_item(preview_item_id, false, false, window, cx);
16930                });
16931            }
16932        } else {
16933            workspace.add_item_to_active_pane(item, None, true, window, cx);
16934        }
16935        workspace.active_pane().update(cx, |pane, cx| {
16936            pane.set_preview_item_id(Some(item_id), cx);
16937        });
16938    }
16939
16940    pub fn rename(
16941        &mut self,
16942        _: &Rename,
16943        window: &mut Window,
16944        cx: &mut Context<Self>,
16945    ) -> Option<Task<Result<()>>> {
16946        use language::ToOffset as _;
16947
16948        let provider = self.semantics_provider.clone()?;
16949        let selection = self.selections.newest_anchor().clone();
16950        let (cursor_buffer, cursor_buffer_position) = self
16951            .buffer
16952            .read(cx)
16953            .text_anchor_for_position(selection.head(), cx)?;
16954        let (tail_buffer, cursor_buffer_position_end) = self
16955            .buffer
16956            .read(cx)
16957            .text_anchor_for_position(selection.tail(), cx)?;
16958        if tail_buffer != cursor_buffer {
16959            return None;
16960        }
16961
16962        let snapshot = cursor_buffer.read(cx).snapshot();
16963        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16964        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16965        let prepare_rename = provider
16966            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16967            .unwrap_or_else(|| Task::ready(Ok(None)));
16968        drop(snapshot);
16969
16970        Some(cx.spawn_in(window, async move |this, cx| {
16971            let rename_range = if let Some(range) = prepare_rename.await? {
16972                Some(range)
16973            } else {
16974                this.update(cx, |this, cx| {
16975                    let buffer = this.buffer.read(cx).snapshot(cx);
16976                    let mut buffer_highlights = this
16977                        .document_highlights_for_position(selection.head(), &buffer)
16978                        .filter(|highlight| {
16979                            highlight.start.excerpt_id == selection.head().excerpt_id
16980                                && highlight.end.excerpt_id == selection.head().excerpt_id
16981                        });
16982                    buffer_highlights
16983                        .next()
16984                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16985                })?
16986            };
16987            if let Some(rename_range) = rename_range {
16988                this.update_in(cx, |this, window, cx| {
16989                    let snapshot = cursor_buffer.read(cx).snapshot();
16990                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16991                    let cursor_offset_in_rename_range =
16992                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16993                    let cursor_offset_in_rename_range_end =
16994                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16995
16996                    this.take_rename(false, window, cx);
16997                    let buffer = this.buffer.read(cx).read(cx);
16998                    let cursor_offset = selection.head().to_offset(&buffer);
16999                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17000                    let rename_end = rename_start + rename_buffer_range.len();
17001                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17002                    let mut old_highlight_id = None;
17003                    let old_name: Arc<str> = buffer
17004                        .chunks(rename_start..rename_end, true)
17005                        .map(|chunk| {
17006                            if old_highlight_id.is_none() {
17007                                old_highlight_id = chunk.syntax_highlight_id;
17008                            }
17009                            chunk.text
17010                        })
17011                        .collect::<String>()
17012                        .into();
17013
17014                    drop(buffer);
17015
17016                    // Position the selection in the rename editor so that it matches the current selection.
17017                    this.show_local_selections = false;
17018                    let rename_editor = cx.new(|cx| {
17019                        let mut editor = Editor::single_line(window, cx);
17020                        editor.buffer.update(cx, |buffer, cx| {
17021                            buffer.edit([(0..0, old_name.clone())], None, cx)
17022                        });
17023                        let rename_selection_range = match cursor_offset_in_rename_range
17024                            .cmp(&cursor_offset_in_rename_range_end)
17025                        {
17026                            Ordering::Equal => {
17027                                editor.select_all(&SelectAll, window, cx);
17028                                return editor;
17029                            }
17030                            Ordering::Less => {
17031                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17032                            }
17033                            Ordering::Greater => {
17034                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17035                            }
17036                        };
17037                        if rename_selection_range.end > old_name.len() {
17038                            editor.select_all(&SelectAll, window, cx);
17039                        } else {
17040                            editor.change_selections(Default::default(), window, cx, |s| {
17041                                s.select_ranges([rename_selection_range]);
17042                            });
17043                        }
17044                        editor
17045                    });
17046                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17047                        if e == &EditorEvent::Focused {
17048                            cx.emit(EditorEvent::FocusedIn)
17049                        }
17050                    })
17051                    .detach();
17052
17053                    let write_highlights =
17054                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17055                    let read_highlights =
17056                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17057                    let ranges = write_highlights
17058                        .iter()
17059                        .flat_map(|(_, ranges)| ranges.iter())
17060                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17061                        .cloned()
17062                        .collect();
17063
17064                    this.highlight_text::<Rename>(
17065                        ranges,
17066                        HighlightStyle {
17067                            fade_out: Some(0.6),
17068                            ..Default::default()
17069                        },
17070                        cx,
17071                    );
17072                    let rename_focus_handle = rename_editor.focus_handle(cx);
17073                    window.focus(&rename_focus_handle);
17074                    let block_id = this.insert_blocks(
17075                        [BlockProperties {
17076                            style: BlockStyle::Flex,
17077                            placement: BlockPlacement::Below(range.start),
17078                            height: Some(1),
17079                            render: Arc::new({
17080                                let rename_editor = rename_editor.clone();
17081                                move |cx: &mut BlockContext| {
17082                                    let mut text_style = cx.editor_style.text.clone();
17083                                    if let Some(highlight_style) = old_highlight_id
17084                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17085                                    {
17086                                        text_style = text_style.highlight(highlight_style);
17087                                    }
17088                                    div()
17089                                        .block_mouse_except_scroll()
17090                                        .pl(cx.anchor_x)
17091                                        .child(EditorElement::new(
17092                                            &rename_editor,
17093                                            EditorStyle {
17094                                                background: cx.theme().system().transparent,
17095                                                local_player: cx.editor_style.local_player,
17096                                                text: text_style,
17097                                                scrollbar_width: cx.editor_style.scrollbar_width,
17098                                                syntax: cx.editor_style.syntax.clone(),
17099                                                status: cx.editor_style.status.clone(),
17100                                                inlay_hints_style: HighlightStyle {
17101                                                    font_weight: Some(FontWeight::BOLD),
17102                                                    ..make_inlay_hints_style(cx.app)
17103                                                },
17104                                                edit_prediction_styles: make_suggestion_styles(
17105                                                    cx.app,
17106                                                ),
17107                                                ..EditorStyle::default()
17108                                            },
17109                                        ))
17110                                        .into_any_element()
17111                                }
17112                            }),
17113                            priority: 0,
17114                        }],
17115                        Some(Autoscroll::fit()),
17116                        cx,
17117                    )[0];
17118                    this.pending_rename = Some(RenameState {
17119                        range,
17120                        old_name,
17121                        editor: rename_editor,
17122                        block_id,
17123                    });
17124                })?;
17125            }
17126
17127            Ok(())
17128        }))
17129    }
17130
17131    pub fn confirm_rename(
17132        &mut self,
17133        _: &ConfirmRename,
17134        window: &mut Window,
17135        cx: &mut Context<Self>,
17136    ) -> Option<Task<Result<()>>> {
17137        let rename = self.take_rename(false, window, cx)?;
17138        let workspace = self.workspace()?.downgrade();
17139        let (buffer, start) = self
17140            .buffer
17141            .read(cx)
17142            .text_anchor_for_position(rename.range.start, cx)?;
17143        let (end_buffer, _) = self
17144            .buffer
17145            .read(cx)
17146            .text_anchor_for_position(rename.range.end, cx)?;
17147        if buffer != end_buffer {
17148            return None;
17149        }
17150
17151        let old_name = rename.old_name;
17152        let new_name = rename.editor.read(cx).text(cx);
17153
17154        let rename = self.semantics_provider.as_ref()?.perform_rename(
17155            &buffer,
17156            start,
17157            new_name.clone(),
17158            cx,
17159        )?;
17160
17161        Some(cx.spawn_in(window, async move |editor, cx| {
17162            let project_transaction = rename.await?;
17163            Self::open_project_transaction(
17164                &editor,
17165                workspace,
17166                project_transaction,
17167                format!("Rename: {}{}", old_name, new_name),
17168                cx,
17169            )
17170            .await?;
17171
17172            editor.update(cx, |editor, cx| {
17173                editor.refresh_document_highlights(cx);
17174            })?;
17175            Ok(())
17176        }))
17177    }
17178
17179    fn take_rename(
17180        &mut self,
17181        moving_cursor: bool,
17182        window: &mut Window,
17183        cx: &mut Context<Self>,
17184    ) -> Option<RenameState> {
17185        let rename = self.pending_rename.take()?;
17186        if rename.editor.focus_handle(cx).is_focused(window) {
17187            window.focus(&self.focus_handle);
17188        }
17189
17190        self.remove_blocks(
17191            [rename.block_id].into_iter().collect(),
17192            Some(Autoscroll::fit()),
17193            cx,
17194        );
17195        self.clear_highlights::<Rename>(cx);
17196        self.show_local_selections = true;
17197
17198        if moving_cursor {
17199            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17200                editor.selections.newest::<usize>(cx).head()
17201            });
17202
17203            // Update the selection to match the position of the selection inside
17204            // the rename editor.
17205            let snapshot = self.buffer.read(cx).read(cx);
17206            let rename_range = rename.range.to_offset(&snapshot);
17207            let cursor_in_editor = snapshot
17208                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17209                .min(rename_range.end);
17210            drop(snapshot);
17211
17212            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17213                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17214            });
17215        } else {
17216            self.refresh_document_highlights(cx);
17217        }
17218
17219        Some(rename)
17220    }
17221
17222    pub fn pending_rename(&self) -> Option<&RenameState> {
17223        self.pending_rename.as_ref()
17224    }
17225
17226    fn format(
17227        &mut self,
17228        _: &Format,
17229        window: &mut Window,
17230        cx: &mut Context<Self>,
17231    ) -> Option<Task<Result<()>>> {
17232        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17233
17234        let project = match &self.project {
17235            Some(project) => project.clone(),
17236            None => return None,
17237        };
17238
17239        Some(self.perform_format(
17240            project,
17241            FormatTrigger::Manual,
17242            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17243            window,
17244            cx,
17245        ))
17246    }
17247
17248    fn format_selections(
17249        &mut self,
17250        _: &FormatSelections,
17251        window: &mut Window,
17252        cx: &mut Context<Self>,
17253    ) -> Option<Task<Result<()>>> {
17254        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17255
17256        let project = match &self.project {
17257            Some(project) => project.clone(),
17258            None => return None,
17259        };
17260
17261        let ranges = self
17262            .selections
17263            .all_adjusted(cx)
17264            .into_iter()
17265            .map(|selection| selection.range())
17266            .collect_vec();
17267
17268        Some(self.perform_format(
17269            project,
17270            FormatTrigger::Manual,
17271            FormatTarget::Ranges(ranges),
17272            window,
17273            cx,
17274        ))
17275    }
17276
17277    fn perform_format(
17278        &mut self,
17279        project: Entity<Project>,
17280        trigger: FormatTrigger,
17281        target: FormatTarget,
17282        window: &mut Window,
17283        cx: &mut Context<Self>,
17284    ) -> Task<Result<()>> {
17285        let buffer = self.buffer.clone();
17286        let (buffers, target) = match target {
17287            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17288            FormatTarget::Ranges(selection_ranges) => {
17289                let multi_buffer = buffer.read(cx);
17290                let snapshot = multi_buffer.read(cx);
17291                let mut buffers = HashSet::default();
17292                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17293                    BTreeMap::new();
17294                for selection_range in selection_ranges {
17295                    for (buffer, buffer_range, _) in
17296                        snapshot.range_to_buffer_ranges(selection_range)
17297                    {
17298                        let buffer_id = buffer.remote_id();
17299                        let start = buffer.anchor_before(buffer_range.start);
17300                        let end = buffer.anchor_after(buffer_range.end);
17301                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17302                        buffer_id_to_ranges
17303                            .entry(buffer_id)
17304                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17305                            .or_insert_with(|| vec![start..end]);
17306                    }
17307                }
17308                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17309            }
17310        };
17311
17312        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17313        let selections_prev = transaction_id_prev
17314            .and_then(|transaction_id_prev| {
17315                // default to selections as they were after the last edit, if we have them,
17316                // instead of how they are now.
17317                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17318                // will take you back to where you made the last edit, instead of staying where you scrolled
17319                self.selection_history
17320                    .transaction(transaction_id_prev)
17321                    .map(|t| t.0.clone())
17322            })
17323            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17324
17325        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17326        let format = project.update(cx, |project, cx| {
17327            project.format(buffers, target, true, trigger, cx)
17328        });
17329
17330        cx.spawn_in(window, async move |editor, cx| {
17331            let transaction = futures::select_biased! {
17332                transaction = format.log_err().fuse() => transaction,
17333                () = timeout => {
17334                    log::warn!("timed out waiting for formatting");
17335                    None
17336                }
17337            };
17338
17339            buffer
17340                .update(cx, |buffer, cx| {
17341                    if let Some(transaction) = transaction
17342                        && !buffer.is_singleton()
17343                    {
17344                        buffer.push_transaction(&transaction.0, cx);
17345                    }
17346                    cx.notify();
17347                })
17348                .ok();
17349
17350            if let Some(transaction_id_now) =
17351                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17352            {
17353                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17354                if has_new_transaction {
17355                    _ = editor.update(cx, |editor, _| {
17356                        editor
17357                            .selection_history
17358                            .insert_transaction(transaction_id_now, selections_prev);
17359                    });
17360                }
17361            }
17362
17363            Ok(())
17364        })
17365    }
17366
17367    fn organize_imports(
17368        &mut self,
17369        _: &OrganizeImports,
17370        window: &mut Window,
17371        cx: &mut Context<Self>,
17372    ) -> Option<Task<Result<()>>> {
17373        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17374        let project = match &self.project {
17375            Some(project) => project.clone(),
17376            None => return None,
17377        };
17378        Some(self.perform_code_action_kind(
17379            project,
17380            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17381            window,
17382            cx,
17383        ))
17384    }
17385
17386    fn perform_code_action_kind(
17387        &mut self,
17388        project: Entity<Project>,
17389        kind: CodeActionKind,
17390        window: &mut Window,
17391        cx: &mut Context<Self>,
17392    ) -> Task<Result<()>> {
17393        let buffer = self.buffer.clone();
17394        let buffers = buffer.read(cx).all_buffers();
17395        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17396        let apply_action = project.update(cx, |project, cx| {
17397            project.apply_code_action_kind(buffers, kind, true, cx)
17398        });
17399        cx.spawn_in(window, async move |_, cx| {
17400            let transaction = futures::select_biased! {
17401                () = timeout => {
17402                    log::warn!("timed out waiting for executing code action");
17403                    None
17404                }
17405                transaction = apply_action.log_err().fuse() => transaction,
17406            };
17407            buffer
17408                .update(cx, |buffer, cx| {
17409                    // check if we need this
17410                    if let Some(transaction) = transaction
17411                        && !buffer.is_singleton()
17412                    {
17413                        buffer.push_transaction(&transaction.0, cx);
17414                    }
17415                    cx.notify();
17416                })
17417                .ok();
17418            Ok(())
17419        })
17420    }
17421
17422    pub fn restart_language_server(
17423        &mut self,
17424        _: &RestartLanguageServer,
17425        _: &mut Window,
17426        cx: &mut Context<Self>,
17427    ) {
17428        if let Some(project) = self.project.clone() {
17429            self.buffer.update(cx, |multi_buffer, cx| {
17430                project.update(cx, |project, cx| {
17431                    project.restart_language_servers_for_buffers(
17432                        multi_buffer.all_buffers().into_iter().collect(),
17433                        HashSet::default(),
17434                        cx,
17435                    );
17436                });
17437            })
17438        }
17439    }
17440
17441    pub fn stop_language_server(
17442        &mut self,
17443        _: &StopLanguageServer,
17444        _: &mut Window,
17445        cx: &mut Context<Self>,
17446    ) {
17447        if let Some(project) = self.project.clone() {
17448            self.buffer.update(cx, |multi_buffer, cx| {
17449                project.update(cx, |project, cx| {
17450                    project.stop_language_servers_for_buffers(
17451                        multi_buffer.all_buffers().into_iter().collect(),
17452                        HashSet::default(),
17453                        cx,
17454                    );
17455                    cx.emit(project::Event::RefreshInlayHints);
17456                });
17457            });
17458        }
17459    }
17460
17461    fn cancel_language_server_work(
17462        workspace: &mut Workspace,
17463        _: &actions::CancelLanguageServerWork,
17464        _: &mut Window,
17465        cx: &mut Context<Workspace>,
17466    ) {
17467        let project = workspace.project();
17468        let buffers = workspace
17469            .active_item(cx)
17470            .and_then(|item| item.act_as::<Editor>(cx))
17471            .map_or(HashSet::default(), |editor| {
17472                editor.read(cx).buffer.read(cx).all_buffers()
17473            });
17474        project.update(cx, |project, cx| {
17475            project.cancel_language_server_work_for_buffers(buffers, cx);
17476        });
17477    }
17478
17479    fn show_character_palette(
17480        &mut self,
17481        _: &ShowCharacterPalette,
17482        window: &mut Window,
17483        _: &mut Context<Self>,
17484    ) {
17485        window.show_character_palette();
17486    }
17487
17488    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17489        if !self.diagnostics_enabled() {
17490            return;
17491        }
17492
17493        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17494            let buffer = self.buffer.read(cx).snapshot(cx);
17495            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17496            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17497            let is_valid = buffer
17498                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17499                .any(|entry| {
17500                    entry.diagnostic.is_primary
17501                        && !entry.range.is_empty()
17502                        && entry.range.start == primary_range_start
17503                        && entry.diagnostic.message == active_diagnostics.active_message
17504                });
17505
17506            if !is_valid {
17507                self.dismiss_diagnostics(cx);
17508            }
17509        }
17510    }
17511
17512    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17513        match &self.active_diagnostics {
17514            ActiveDiagnostic::Group(group) => Some(group),
17515            _ => None,
17516        }
17517    }
17518
17519    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17520        if !self.diagnostics_enabled() {
17521            return;
17522        }
17523        self.dismiss_diagnostics(cx);
17524        self.active_diagnostics = ActiveDiagnostic::All;
17525    }
17526
17527    fn activate_diagnostics(
17528        &mut self,
17529        buffer_id: BufferId,
17530        diagnostic: DiagnosticEntryRef<'_, usize>,
17531        window: &mut Window,
17532        cx: &mut Context<Self>,
17533    ) {
17534        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17535            return;
17536        }
17537        self.dismiss_diagnostics(cx);
17538        let snapshot = self.snapshot(window, cx);
17539        let buffer = self.buffer.read(cx).snapshot(cx);
17540        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17541            return;
17542        };
17543
17544        let diagnostic_group = buffer
17545            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17546            .collect::<Vec<_>>();
17547
17548        let blocks =
17549            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17550
17551        let blocks = self.display_map.update(cx, |display_map, cx| {
17552            display_map.insert_blocks(blocks, cx).into_iter().collect()
17553        });
17554        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17555            active_range: buffer.anchor_before(diagnostic.range.start)
17556                ..buffer.anchor_after(diagnostic.range.end),
17557            active_message: diagnostic.diagnostic.message.clone(),
17558            group_id: diagnostic.diagnostic.group_id,
17559            blocks,
17560        });
17561        cx.notify();
17562    }
17563
17564    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17565        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17566            return;
17567        };
17568
17569        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17570        if let ActiveDiagnostic::Group(group) = prev {
17571            self.display_map.update(cx, |display_map, cx| {
17572                display_map.remove_blocks(group.blocks, cx);
17573            });
17574            cx.notify();
17575        }
17576    }
17577
17578    /// Disable inline diagnostics rendering for this editor.
17579    pub fn disable_inline_diagnostics(&mut self) {
17580        self.inline_diagnostics_enabled = false;
17581        self.inline_diagnostics_update = Task::ready(());
17582        self.inline_diagnostics.clear();
17583    }
17584
17585    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17586        self.diagnostics_enabled = false;
17587        self.dismiss_diagnostics(cx);
17588        self.inline_diagnostics_update = Task::ready(());
17589        self.inline_diagnostics.clear();
17590    }
17591
17592    pub fn disable_word_completions(&mut self) {
17593        self.word_completions_enabled = false;
17594    }
17595
17596    pub fn diagnostics_enabled(&self) -> bool {
17597        self.diagnostics_enabled && self.mode.is_full()
17598    }
17599
17600    pub fn inline_diagnostics_enabled(&self) -> bool {
17601        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17602    }
17603
17604    pub fn show_inline_diagnostics(&self) -> bool {
17605        self.show_inline_diagnostics
17606    }
17607
17608    pub fn toggle_inline_diagnostics(
17609        &mut self,
17610        _: &ToggleInlineDiagnostics,
17611        window: &mut Window,
17612        cx: &mut Context<Editor>,
17613    ) {
17614        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17615        self.refresh_inline_diagnostics(false, window, cx);
17616    }
17617
17618    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17619        self.diagnostics_max_severity = severity;
17620        self.display_map.update(cx, |display_map, _| {
17621            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17622        });
17623    }
17624
17625    pub fn toggle_diagnostics(
17626        &mut self,
17627        _: &ToggleDiagnostics,
17628        window: &mut Window,
17629        cx: &mut Context<Editor>,
17630    ) {
17631        if !self.diagnostics_enabled() {
17632            return;
17633        }
17634
17635        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17636            EditorSettings::get_global(cx)
17637                .diagnostics_max_severity
17638                .filter(|severity| severity != &DiagnosticSeverity::Off)
17639                .unwrap_or(DiagnosticSeverity::Hint)
17640        } else {
17641            DiagnosticSeverity::Off
17642        };
17643        self.set_max_diagnostics_severity(new_severity, cx);
17644        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17645            self.active_diagnostics = ActiveDiagnostic::None;
17646            self.inline_diagnostics_update = Task::ready(());
17647            self.inline_diagnostics.clear();
17648        } else {
17649            self.refresh_inline_diagnostics(false, window, cx);
17650        }
17651
17652        cx.notify();
17653    }
17654
17655    pub fn toggle_minimap(
17656        &mut self,
17657        _: &ToggleMinimap,
17658        window: &mut Window,
17659        cx: &mut Context<Editor>,
17660    ) {
17661        if self.supports_minimap(cx) {
17662            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17663        }
17664    }
17665
17666    fn refresh_inline_diagnostics(
17667        &mut self,
17668        debounce: bool,
17669        window: &mut Window,
17670        cx: &mut Context<Self>,
17671    ) {
17672        let max_severity = ProjectSettings::get_global(cx)
17673            .diagnostics
17674            .inline
17675            .max_severity
17676            .unwrap_or(self.diagnostics_max_severity);
17677
17678        if !self.inline_diagnostics_enabled()
17679            || !self.show_inline_diagnostics
17680            || max_severity == DiagnosticSeverity::Off
17681        {
17682            self.inline_diagnostics_update = Task::ready(());
17683            self.inline_diagnostics.clear();
17684            return;
17685        }
17686
17687        let debounce_ms = ProjectSettings::get_global(cx)
17688            .diagnostics
17689            .inline
17690            .update_debounce_ms;
17691        let debounce = if debounce && debounce_ms > 0 {
17692            Some(Duration::from_millis(debounce_ms))
17693        } else {
17694            None
17695        };
17696        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17697            if let Some(debounce) = debounce {
17698                cx.background_executor().timer(debounce).await;
17699            }
17700            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17701                editor
17702                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17703                    .ok()
17704            }) else {
17705                return;
17706            };
17707
17708            let new_inline_diagnostics = cx
17709                .background_spawn(async move {
17710                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17711                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17712                        let message = diagnostic_entry
17713                            .diagnostic
17714                            .message
17715                            .split_once('\n')
17716                            .map(|(line, _)| line)
17717                            .map(SharedString::new)
17718                            .unwrap_or_else(|| {
17719                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17720                            });
17721                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17722                        let (Ok(i) | Err(i)) = inline_diagnostics
17723                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17724                        inline_diagnostics.insert(
17725                            i,
17726                            (
17727                                start_anchor,
17728                                InlineDiagnostic {
17729                                    message,
17730                                    group_id: diagnostic_entry.diagnostic.group_id,
17731                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17732                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17733                                    severity: diagnostic_entry.diagnostic.severity,
17734                                },
17735                            ),
17736                        );
17737                    }
17738                    inline_diagnostics
17739                })
17740                .await;
17741
17742            editor
17743                .update(cx, |editor, cx| {
17744                    editor.inline_diagnostics = new_inline_diagnostics;
17745                    cx.notify();
17746                })
17747                .ok();
17748        });
17749    }
17750
17751    fn pull_diagnostics(
17752        &mut self,
17753        buffer_id: Option<BufferId>,
17754        window: &Window,
17755        cx: &mut Context<Self>,
17756    ) -> Option<()> {
17757        if !self.mode().is_full() {
17758            return None;
17759        }
17760        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17761            .diagnostics
17762            .lsp_pull_diagnostics;
17763        if !pull_diagnostics_settings.enabled {
17764            return None;
17765        }
17766        let project = self.project()?.downgrade();
17767        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17768        let mut buffers = self.buffer.read(cx).all_buffers();
17769        if let Some(buffer_id) = buffer_id {
17770            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17771        }
17772
17773        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17774            cx.background_executor().timer(debounce).await;
17775
17776            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17777                buffers
17778                    .into_iter()
17779                    .filter_map(|buffer| {
17780                        project
17781                            .update(cx, |project, cx| {
17782                                project.lsp_store().update(cx, |lsp_store, cx| {
17783                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17784                                })
17785                            })
17786                            .ok()
17787                    })
17788                    .collect::<FuturesUnordered<_>>()
17789            }) else {
17790                return;
17791            };
17792
17793            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17794                match pull_task {
17795                    Ok(()) => {
17796                        if editor
17797                            .update_in(cx, |editor, window, cx| {
17798                                editor.update_diagnostics_state(window, cx);
17799                            })
17800                            .is_err()
17801                        {
17802                            return;
17803                        }
17804                    }
17805                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17806                }
17807            }
17808        });
17809
17810        Some(())
17811    }
17812
17813    pub fn set_selections_from_remote(
17814        &mut self,
17815        selections: Vec<Selection<Anchor>>,
17816        pending_selection: Option<Selection<Anchor>>,
17817        window: &mut Window,
17818        cx: &mut Context<Self>,
17819    ) {
17820        let old_cursor_position = self.selections.newest_anchor().head();
17821        self.selections.change_with(cx, |s| {
17822            s.select_anchors(selections);
17823            if let Some(pending_selection) = pending_selection {
17824                s.set_pending(pending_selection, SelectMode::Character);
17825            } else {
17826                s.clear_pending();
17827            }
17828        });
17829        self.selections_did_change(
17830            false,
17831            &old_cursor_position,
17832            SelectionEffects::default(),
17833            window,
17834            cx,
17835        );
17836    }
17837
17838    pub fn transact(
17839        &mut self,
17840        window: &mut Window,
17841        cx: &mut Context<Self>,
17842        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17843    ) -> Option<TransactionId> {
17844        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17845            this.start_transaction_at(Instant::now(), window, cx);
17846            update(this, window, cx);
17847            this.end_transaction_at(Instant::now(), cx)
17848        })
17849    }
17850
17851    pub fn start_transaction_at(
17852        &mut self,
17853        now: Instant,
17854        window: &mut Window,
17855        cx: &mut Context<Self>,
17856    ) -> Option<TransactionId> {
17857        self.end_selection(window, cx);
17858        if let Some(tx_id) = self
17859            .buffer
17860            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17861        {
17862            self.selection_history
17863                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17864            cx.emit(EditorEvent::TransactionBegun {
17865                transaction_id: tx_id,
17866            });
17867            Some(tx_id)
17868        } else {
17869            None
17870        }
17871    }
17872
17873    pub fn end_transaction_at(
17874        &mut self,
17875        now: Instant,
17876        cx: &mut Context<Self>,
17877    ) -> Option<TransactionId> {
17878        if let Some(transaction_id) = self
17879            .buffer
17880            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17881        {
17882            if let Some((_, end_selections)) =
17883                self.selection_history.transaction_mut(transaction_id)
17884            {
17885                *end_selections = Some(self.selections.disjoint_anchors_arc());
17886            } else {
17887                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17888            }
17889
17890            cx.emit(EditorEvent::Edited { transaction_id });
17891            Some(transaction_id)
17892        } else {
17893            None
17894        }
17895    }
17896
17897    pub fn modify_transaction_selection_history(
17898        &mut self,
17899        transaction_id: TransactionId,
17900        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17901    ) -> bool {
17902        self.selection_history
17903            .transaction_mut(transaction_id)
17904            .map(modify)
17905            .is_some()
17906    }
17907
17908    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17909        if self.selection_mark_mode {
17910            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17911                s.move_with(|_, sel| {
17912                    sel.collapse_to(sel.head(), SelectionGoal::None);
17913                });
17914            })
17915        }
17916        self.selection_mark_mode = true;
17917        cx.notify();
17918    }
17919
17920    pub fn swap_selection_ends(
17921        &mut self,
17922        _: &actions::SwapSelectionEnds,
17923        window: &mut Window,
17924        cx: &mut Context<Self>,
17925    ) {
17926        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17927            s.move_with(|_, sel| {
17928                if sel.start != sel.end {
17929                    sel.reversed = !sel.reversed
17930                }
17931            });
17932        });
17933        self.request_autoscroll(Autoscroll::newest(), cx);
17934        cx.notify();
17935    }
17936
17937    pub fn toggle_focus(
17938        workspace: &mut Workspace,
17939        _: &actions::ToggleFocus,
17940        window: &mut Window,
17941        cx: &mut Context<Workspace>,
17942    ) {
17943        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17944            return;
17945        };
17946        workspace.activate_item(&item, true, true, window, cx);
17947    }
17948
17949    pub fn toggle_fold(
17950        &mut self,
17951        _: &actions::ToggleFold,
17952        window: &mut Window,
17953        cx: &mut Context<Self>,
17954    ) {
17955        if self.is_singleton(cx) {
17956            let selection = self.selections.newest::<Point>(cx);
17957
17958            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17959            let range = if selection.is_empty() {
17960                let point = selection.head().to_display_point(&display_map);
17961                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17962                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17963                    .to_point(&display_map);
17964                start..end
17965            } else {
17966                selection.range()
17967            };
17968            if display_map.folds_in_range(range).next().is_some() {
17969                self.unfold_lines(&Default::default(), window, cx)
17970            } else {
17971                self.fold(&Default::default(), window, cx)
17972            }
17973        } else {
17974            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17975            let buffer_ids: HashSet<_> = self
17976                .selections
17977                .disjoint_anchor_ranges()
17978                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17979                .collect();
17980
17981            let should_unfold = buffer_ids
17982                .iter()
17983                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17984
17985            for buffer_id in buffer_ids {
17986                if should_unfold {
17987                    self.unfold_buffer(buffer_id, cx);
17988                } else {
17989                    self.fold_buffer(buffer_id, cx);
17990                }
17991            }
17992        }
17993    }
17994
17995    pub fn toggle_fold_recursive(
17996        &mut self,
17997        _: &actions::ToggleFoldRecursive,
17998        window: &mut Window,
17999        cx: &mut Context<Self>,
18000    ) {
18001        let selection = self.selections.newest::<Point>(cx);
18002
18003        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18004        let range = if selection.is_empty() {
18005            let point = selection.head().to_display_point(&display_map);
18006            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18007            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18008                .to_point(&display_map);
18009            start..end
18010        } else {
18011            selection.range()
18012        };
18013        if display_map.folds_in_range(range).next().is_some() {
18014            self.unfold_recursive(&Default::default(), window, cx)
18015        } else {
18016            self.fold_recursive(&Default::default(), window, cx)
18017        }
18018    }
18019
18020    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18021        if self.is_singleton(cx) {
18022            let mut to_fold = Vec::new();
18023            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18024            let selections = self.selections.all_adjusted(cx);
18025
18026            for selection in selections {
18027                let range = selection.range().sorted();
18028                let buffer_start_row = range.start.row;
18029
18030                if range.start.row != range.end.row {
18031                    let mut found = false;
18032                    let mut row = range.start.row;
18033                    while row <= range.end.row {
18034                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18035                        {
18036                            found = true;
18037                            row = crease.range().end.row + 1;
18038                            to_fold.push(crease);
18039                        } else {
18040                            row += 1
18041                        }
18042                    }
18043                    if found {
18044                        continue;
18045                    }
18046                }
18047
18048                for row in (0..=range.start.row).rev() {
18049                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18050                        && crease.range().end.row >= buffer_start_row
18051                    {
18052                        to_fold.push(crease);
18053                        if row <= range.start.row {
18054                            break;
18055                        }
18056                    }
18057                }
18058            }
18059
18060            self.fold_creases(to_fold, true, window, cx);
18061        } else {
18062            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18063            let buffer_ids = self
18064                .selections
18065                .disjoint_anchor_ranges()
18066                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18067                .collect::<HashSet<_>>();
18068            for buffer_id in buffer_ids {
18069                self.fold_buffer(buffer_id, cx);
18070            }
18071        }
18072    }
18073
18074    pub fn toggle_fold_all(
18075        &mut self,
18076        _: &actions::ToggleFoldAll,
18077        window: &mut Window,
18078        cx: &mut Context<Self>,
18079    ) {
18080        if self.buffer.read(cx).is_singleton() {
18081            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18082            let has_folds = display_map
18083                .folds_in_range(0..display_map.buffer_snapshot.len())
18084                .next()
18085                .is_some();
18086
18087            if has_folds {
18088                self.unfold_all(&actions::UnfoldAll, window, cx);
18089            } else {
18090                self.fold_all(&actions::FoldAll, window, cx);
18091            }
18092        } else {
18093            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18094            let should_unfold = buffer_ids
18095                .iter()
18096                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18097
18098            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18099                editor
18100                    .update_in(cx, |editor, _, cx| {
18101                        for buffer_id in buffer_ids {
18102                            if should_unfold {
18103                                editor.unfold_buffer(buffer_id, cx);
18104                            } else {
18105                                editor.fold_buffer(buffer_id, cx);
18106                            }
18107                        }
18108                    })
18109                    .ok();
18110            });
18111        }
18112    }
18113
18114    fn fold_at_level(
18115        &mut self,
18116        fold_at: &FoldAtLevel,
18117        window: &mut Window,
18118        cx: &mut Context<Self>,
18119    ) {
18120        if !self.buffer.read(cx).is_singleton() {
18121            return;
18122        }
18123
18124        let fold_at_level = fold_at.0;
18125        let snapshot = self.buffer.read(cx).snapshot(cx);
18126        let mut to_fold = Vec::new();
18127        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18128
18129        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18130            while start_row < end_row {
18131                match self
18132                    .snapshot(window, cx)
18133                    .crease_for_buffer_row(MultiBufferRow(start_row))
18134                {
18135                    Some(crease) => {
18136                        let nested_start_row = crease.range().start.row + 1;
18137                        let nested_end_row = crease.range().end.row;
18138
18139                        if current_level < fold_at_level {
18140                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18141                        } else if current_level == fold_at_level {
18142                            to_fold.push(crease);
18143                        }
18144
18145                        start_row = nested_end_row + 1;
18146                    }
18147                    None => start_row += 1,
18148                }
18149            }
18150        }
18151
18152        self.fold_creases(to_fold, true, window, cx);
18153    }
18154
18155    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18156        if self.buffer.read(cx).is_singleton() {
18157            let mut fold_ranges = Vec::new();
18158            let snapshot = self.buffer.read(cx).snapshot(cx);
18159
18160            for row in 0..snapshot.max_row().0 {
18161                if let Some(foldable_range) = self
18162                    .snapshot(window, cx)
18163                    .crease_for_buffer_row(MultiBufferRow(row))
18164                {
18165                    fold_ranges.push(foldable_range);
18166                }
18167            }
18168
18169            self.fold_creases(fold_ranges, true, window, cx);
18170        } else {
18171            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18172                editor
18173                    .update_in(cx, |editor, _, cx| {
18174                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18175                            editor.fold_buffer(buffer_id, cx);
18176                        }
18177                    })
18178                    .ok();
18179            });
18180        }
18181    }
18182
18183    pub fn fold_function_bodies(
18184        &mut self,
18185        _: &actions::FoldFunctionBodies,
18186        window: &mut Window,
18187        cx: &mut Context<Self>,
18188    ) {
18189        let snapshot = self.buffer.read(cx).snapshot(cx);
18190
18191        let ranges = snapshot
18192            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18193            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18194            .collect::<Vec<_>>();
18195
18196        let creases = ranges
18197            .into_iter()
18198            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18199            .collect();
18200
18201        self.fold_creases(creases, true, window, cx);
18202    }
18203
18204    pub fn fold_recursive(
18205        &mut self,
18206        _: &actions::FoldRecursive,
18207        window: &mut Window,
18208        cx: &mut Context<Self>,
18209    ) {
18210        let mut to_fold = Vec::new();
18211        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18212        let selections = self.selections.all_adjusted(cx);
18213
18214        for selection in selections {
18215            let range = selection.range().sorted();
18216            let buffer_start_row = range.start.row;
18217
18218            if range.start.row != range.end.row {
18219                let mut found = false;
18220                for row in range.start.row..=range.end.row {
18221                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18222                        found = true;
18223                        to_fold.push(crease);
18224                    }
18225                }
18226                if found {
18227                    continue;
18228                }
18229            }
18230
18231            for row in (0..=range.start.row).rev() {
18232                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18233                    if crease.range().end.row >= buffer_start_row {
18234                        to_fold.push(crease);
18235                    } else {
18236                        break;
18237                    }
18238                }
18239            }
18240        }
18241
18242        self.fold_creases(to_fold, true, window, cx);
18243    }
18244
18245    pub fn fold_at(
18246        &mut self,
18247        buffer_row: MultiBufferRow,
18248        window: &mut Window,
18249        cx: &mut Context<Self>,
18250    ) {
18251        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18252
18253        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18254            let autoscroll = self
18255                .selections
18256                .all::<Point>(cx)
18257                .iter()
18258                .any(|selection| crease.range().overlaps(&selection.range()));
18259
18260            self.fold_creases(vec![crease], autoscroll, window, cx);
18261        }
18262    }
18263
18264    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18265        if self.is_singleton(cx) {
18266            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18267            let buffer = &display_map.buffer_snapshot;
18268            let selections = self.selections.all::<Point>(cx);
18269            let ranges = selections
18270                .iter()
18271                .map(|s| {
18272                    let range = s.display_range(&display_map).sorted();
18273                    let mut start = range.start.to_point(&display_map);
18274                    let mut end = range.end.to_point(&display_map);
18275                    start.column = 0;
18276                    end.column = buffer.line_len(MultiBufferRow(end.row));
18277                    start..end
18278                })
18279                .collect::<Vec<_>>();
18280
18281            self.unfold_ranges(&ranges, true, true, cx);
18282        } else {
18283            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18284            let buffer_ids = self
18285                .selections
18286                .disjoint_anchor_ranges()
18287                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18288                .collect::<HashSet<_>>();
18289            for buffer_id in buffer_ids {
18290                self.unfold_buffer(buffer_id, cx);
18291            }
18292        }
18293    }
18294
18295    pub fn unfold_recursive(
18296        &mut self,
18297        _: &UnfoldRecursive,
18298        _window: &mut Window,
18299        cx: &mut Context<Self>,
18300    ) {
18301        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18302        let selections = self.selections.all::<Point>(cx);
18303        let ranges = selections
18304            .iter()
18305            .map(|s| {
18306                let mut range = s.display_range(&display_map).sorted();
18307                *range.start.column_mut() = 0;
18308                *range.end.column_mut() = display_map.line_len(range.end.row());
18309                let start = range.start.to_point(&display_map);
18310                let end = range.end.to_point(&display_map);
18311                start..end
18312            })
18313            .collect::<Vec<_>>();
18314
18315        self.unfold_ranges(&ranges, true, true, cx);
18316    }
18317
18318    pub fn unfold_at(
18319        &mut self,
18320        buffer_row: MultiBufferRow,
18321        _window: &mut Window,
18322        cx: &mut Context<Self>,
18323    ) {
18324        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18325
18326        let intersection_range = Point::new(buffer_row.0, 0)
18327            ..Point::new(
18328                buffer_row.0,
18329                display_map.buffer_snapshot.line_len(buffer_row),
18330            );
18331
18332        let autoscroll = self
18333            .selections
18334            .all::<Point>(cx)
18335            .iter()
18336            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18337
18338        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18339    }
18340
18341    pub fn unfold_all(
18342        &mut self,
18343        _: &actions::UnfoldAll,
18344        _window: &mut Window,
18345        cx: &mut Context<Self>,
18346    ) {
18347        if self.buffer.read(cx).is_singleton() {
18348            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18349            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18350        } else {
18351            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18352                editor
18353                    .update(cx, |editor, cx| {
18354                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18355                            editor.unfold_buffer(buffer_id, cx);
18356                        }
18357                    })
18358                    .ok();
18359            });
18360        }
18361    }
18362
18363    pub fn fold_selected_ranges(
18364        &mut self,
18365        _: &FoldSelectedRanges,
18366        window: &mut Window,
18367        cx: &mut Context<Self>,
18368    ) {
18369        let selections = self.selections.all_adjusted(cx);
18370        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18371        let ranges = selections
18372            .into_iter()
18373            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18374            .collect::<Vec<_>>();
18375        self.fold_creases(ranges, true, window, cx);
18376    }
18377
18378    pub fn fold_ranges<T: ToOffset + Clone>(
18379        &mut self,
18380        ranges: Vec<Range<T>>,
18381        auto_scroll: bool,
18382        window: &mut Window,
18383        cx: &mut Context<Self>,
18384    ) {
18385        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18386        let ranges = ranges
18387            .into_iter()
18388            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18389            .collect::<Vec<_>>();
18390        self.fold_creases(ranges, auto_scroll, window, cx);
18391    }
18392
18393    pub fn fold_creases<T: ToOffset + Clone>(
18394        &mut self,
18395        creases: Vec<Crease<T>>,
18396        auto_scroll: bool,
18397        _window: &mut Window,
18398        cx: &mut Context<Self>,
18399    ) {
18400        if creases.is_empty() {
18401            return;
18402        }
18403
18404        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18405
18406        if auto_scroll {
18407            self.request_autoscroll(Autoscroll::fit(), cx);
18408        }
18409
18410        cx.notify();
18411
18412        self.scrollbar_marker_state.dirty = true;
18413        self.folds_did_change(cx);
18414    }
18415
18416    /// Removes any folds whose ranges intersect any of the given ranges.
18417    pub fn unfold_ranges<T: ToOffset + Clone>(
18418        &mut self,
18419        ranges: &[Range<T>],
18420        inclusive: bool,
18421        auto_scroll: bool,
18422        cx: &mut Context<Self>,
18423    ) {
18424        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18425            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18426        });
18427        self.folds_did_change(cx);
18428    }
18429
18430    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18431        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18432            return;
18433        }
18434        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18435        self.display_map.update(cx, |display_map, cx| {
18436            display_map.fold_buffers([buffer_id], cx)
18437        });
18438        cx.emit(EditorEvent::BufferFoldToggled {
18439            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18440            folded: true,
18441        });
18442        cx.notify();
18443    }
18444
18445    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18446        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18447            return;
18448        }
18449        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18450        self.display_map.update(cx, |display_map, cx| {
18451            display_map.unfold_buffers([buffer_id], cx);
18452        });
18453        cx.emit(EditorEvent::BufferFoldToggled {
18454            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18455            folded: false,
18456        });
18457        cx.notify();
18458    }
18459
18460    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18461        self.display_map.read(cx).is_buffer_folded(buffer)
18462    }
18463
18464    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18465        self.display_map.read(cx).folded_buffers()
18466    }
18467
18468    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18469        self.display_map.update(cx, |display_map, cx| {
18470            display_map.disable_header_for_buffer(buffer_id, cx);
18471        });
18472        cx.notify();
18473    }
18474
18475    /// Removes any folds with the given ranges.
18476    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18477        &mut self,
18478        ranges: &[Range<T>],
18479        type_id: TypeId,
18480        auto_scroll: bool,
18481        cx: &mut Context<Self>,
18482    ) {
18483        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18484            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18485        });
18486        self.folds_did_change(cx);
18487    }
18488
18489    fn remove_folds_with<T: ToOffset + Clone>(
18490        &mut self,
18491        ranges: &[Range<T>],
18492        auto_scroll: bool,
18493        cx: &mut Context<Self>,
18494        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18495    ) {
18496        if ranges.is_empty() {
18497            return;
18498        }
18499
18500        let mut buffers_affected = HashSet::default();
18501        let multi_buffer = self.buffer().read(cx);
18502        for range in ranges {
18503            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18504                buffers_affected.insert(buffer.read(cx).remote_id());
18505            };
18506        }
18507
18508        self.display_map.update(cx, update);
18509
18510        if auto_scroll {
18511            self.request_autoscroll(Autoscroll::fit(), cx);
18512        }
18513
18514        cx.notify();
18515        self.scrollbar_marker_state.dirty = true;
18516        self.active_indent_guides_state.dirty = true;
18517    }
18518
18519    pub fn update_renderer_widths(
18520        &mut self,
18521        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18522        cx: &mut Context<Self>,
18523    ) -> bool {
18524        self.display_map
18525            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18526    }
18527
18528    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18529        self.display_map.read(cx).fold_placeholder.clone()
18530    }
18531
18532    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18533        self.buffer.update(cx, |buffer, cx| {
18534            buffer.set_all_diff_hunks_expanded(cx);
18535        });
18536    }
18537
18538    pub fn expand_all_diff_hunks(
18539        &mut self,
18540        _: &ExpandAllDiffHunks,
18541        _window: &mut Window,
18542        cx: &mut Context<Self>,
18543    ) {
18544        self.buffer.update(cx, |buffer, cx| {
18545            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18546        });
18547    }
18548
18549    pub fn toggle_selected_diff_hunks(
18550        &mut self,
18551        _: &ToggleSelectedDiffHunks,
18552        _window: &mut Window,
18553        cx: &mut Context<Self>,
18554    ) {
18555        let ranges: Vec<_> = self
18556            .selections
18557            .disjoint_anchors()
18558            .iter()
18559            .map(|s| s.range())
18560            .collect();
18561        self.toggle_diff_hunks_in_ranges(ranges, cx);
18562    }
18563
18564    pub fn diff_hunks_in_ranges<'a>(
18565        &'a self,
18566        ranges: &'a [Range<Anchor>],
18567        buffer: &'a MultiBufferSnapshot,
18568    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18569        ranges.iter().flat_map(move |range| {
18570            let end_excerpt_id = range.end.excerpt_id;
18571            let range = range.to_point(buffer);
18572            let mut peek_end = range.end;
18573            if range.end.row < buffer.max_row().0 {
18574                peek_end = Point::new(range.end.row + 1, 0);
18575            }
18576            buffer
18577                .diff_hunks_in_range(range.start..peek_end)
18578                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18579        })
18580    }
18581
18582    pub fn has_stageable_diff_hunks_in_ranges(
18583        &self,
18584        ranges: &[Range<Anchor>],
18585        snapshot: &MultiBufferSnapshot,
18586    ) -> bool {
18587        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18588        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18589    }
18590
18591    pub fn toggle_staged_selected_diff_hunks(
18592        &mut self,
18593        _: &::git::ToggleStaged,
18594        _: &mut Window,
18595        cx: &mut Context<Self>,
18596    ) {
18597        let snapshot = self.buffer.read(cx).snapshot(cx);
18598        let ranges: Vec<_> = self
18599            .selections
18600            .disjoint_anchors()
18601            .iter()
18602            .map(|s| s.range())
18603            .collect();
18604        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18605        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18606    }
18607
18608    pub fn set_render_diff_hunk_controls(
18609        &mut self,
18610        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18611        cx: &mut Context<Self>,
18612    ) {
18613        self.render_diff_hunk_controls = render_diff_hunk_controls;
18614        cx.notify();
18615    }
18616
18617    pub fn stage_and_next(
18618        &mut self,
18619        _: &::git::StageAndNext,
18620        window: &mut Window,
18621        cx: &mut Context<Self>,
18622    ) {
18623        self.do_stage_or_unstage_and_next(true, window, cx);
18624    }
18625
18626    pub fn unstage_and_next(
18627        &mut self,
18628        _: &::git::UnstageAndNext,
18629        window: &mut Window,
18630        cx: &mut Context<Self>,
18631    ) {
18632        self.do_stage_or_unstage_and_next(false, window, cx);
18633    }
18634
18635    pub fn stage_or_unstage_diff_hunks(
18636        &mut self,
18637        stage: bool,
18638        ranges: Vec<Range<Anchor>>,
18639        cx: &mut Context<Self>,
18640    ) {
18641        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18642        cx.spawn(async move |this, cx| {
18643            task.await?;
18644            this.update(cx, |this, cx| {
18645                let snapshot = this.buffer.read(cx).snapshot(cx);
18646                let chunk_by = this
18647                    .diff_hunks_in_ranges(&ranges, &snapshot)
18648                    .chunk_by(|hunk| hunk.buffer_id);
18649                for (buffer_id, hunks) in &chunk_by {
18650                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18651                }
18652            })
18653        })
18654        .detach_and_log_err(cx);
18655    }
18656
18657    fn save_buffers_for_ranges_if_needed(
18658        &mut self,
18659        ranges: &[Range<Anchor>],
18660        cx: &mut Context<Editor>,
18661    ) -> Task<Result<()>> {
18662        let multibuffer = self.buffer.read(cx);
18663        let snapshot = multibuffer.read(cx);
18664        let buffer_ids: HashSet<_> = ranges
18665            .iter()
18666            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18667            .collect();
18668        drop(snapshot);
18669
18670        let mut buffers = HashSet::default();
18671        for buffer_id in buffer_ids {
18672            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18673                let buffer = buffer_entity.read(cx);
18674                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18675                {
18676                    buffers.insert(buffer_entity);
18677                }
18678            }
18679        }
18680
18681        if let Some(project) = &self.project {
18682            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18683        } else {
18684            Task::ready(Ok(()))
18685        }
18686    }
18687
18688    fn do_stage_or_unstage_and_next(
18689        &mut self,
18690        stage: bool,
18691        window: &mut Window,
18692        cx: &mut Context<Self>,
18693    ) {
18694        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18695
18696        if ranges.iter().any(|range| range.start != range.end) {
18697            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18698            return;
18699        }
18700
18701        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18702        let snapshot = self.snapshot(window, cx);
18703        let position = self.selections.newest::<Point>(cx).head();
18704        let mut row = snapshot
18705            .buffer_snapshot
18706            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18707            .find(|hunk| hunk.row_range.start.0 > position.row)
18708            .map(|hunk| hunk.row_range.start);
18709
18710        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18711        // Outside of the project diff editor, wrap around to the beginning.
18712        if !all_diff_hunks_expanded {
18713            row = row.or_else(|| {
18714                snapshot
18715                    .buffer_snapshot
18716                    .diff_hunks_in_range(Point::zero()..position)
18717                    .find(|hunk| hunk.row_range.end.0 < position.row)
18718                    .map(|hunk| hunk.row_range.start)
18719            });
18720        }
18721
18722        if let Some(row) = row {
18723            let destination = Point::new(row.0, 0);
18724            let autoscroll = Autoscroll::center();
18725
18726            self.unfold_ranges(&[destination..destination], false, false, cx);
18727            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18728                s.select_ranges([destination..destination]);
18729            });
18730        }
18731    }
18732
18733    fn do_stage_or_unstage(
18734        &self,
18735        stage: bool,
18736        buffer_id: BufferId,
18737        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18738        cx: &mut App,
18739    ) -> Option<()> {
18740        let project = self.project()?;
18741        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18742        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18743        let buffer_snapshot = buffer.read(cx).snapshot();
18744        let file_exists = buffer_snapshot
18745            .file()
18746            .is_some_and(|file| file.disk_state().exists());
18747        diff.update(cx, |diff, cx| {
18748            diff.stage_or_unstage_hunks(
18749                stage,
18750                &hunks
18751                    .map(|hunk| buffer_diff::DiffHunk {
18752                        buffer_range: hunk.buffer_range,
18753                        diff_base_byte_range: hunk.diff_base_byte_range,
18754                        secondary_status: hunk.secondary_status,
18755                        range: Point::zero()..Point::zero(), // unused
18756                    })
18757                    .collect::<Vec<_>>(),
18758                &buffer_snapshot,
18759                file_exists,
18760                cx,
18761            )
18762        });
18763        None
18764    }
18765
18766    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18767        let ranges: Vec<_> = self
18768            .selections
18769            .disjoint_anchors()
18770            .iter()
18771            .map(|s| s.range())
18772            .collect();
18773        self.buffer
18774            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18775    }
18776
18777    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18778        self.buffer.update(cx, |buffer, cx| {
18779            let ranges = vec![Anchor::min()..Anchor::max()];
18780            if !buffer.all_diff_hunks_expanded()
18781                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18782            {
18783                buffer.collapse_diff_hunks(ranges, cx);
18784                true
18785            } else {
18786                false
18787            }
18788        })
18789    }
18790
18791    fn toggle_diff_hunks_in_ranges(
18792        &mut self,
18793        ranges: Vec<Range<Anchor>>,
18794        cx: &mut Context<Editor>,
18795    ) {
18796        self.buffer.update(cx, |buffer, cx| {
18797            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18798            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18799        })
18800    }
18801
18802    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18803        self.buffer.update(cx, |buffer, cx| {
18804            let snapshot = buffer.snapshot(cx);
18805            let excerpt_id = range.end.excerpt_id;
18806            let point_range = range.to_point(&snapshot);
18807            let expand = !buffer.single_hunk_is_expanded(range, cx);
18808            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18809        })
18810    }
18811
18812    pub(crate) fn apply_all_diff_hunks(
18813        &mut self,
18814        _: &ApplyAllDiffHunks,
18815        window: &mut Window,
18816        cx: &mut Context<Self>,
18817    ) {
18818        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18819
18820        let buffers = self.buffer.read(cx).all_buffers();
18821        for branch_buffer in buffers {
18822            branch_buffer.update(cx, |branch_buffer, cx| {
18823                branch_buffer.merge_into_base(Vec::new(), cx);
18824            });
18825        }
18826
18827        if let Some(project) = self.project.clone() {
18828            self.save(
18829                SaveOptions {
18830                    format: true,
18831                    autosave: false,
18832                },
18833                project,
18834                window,
18835                cx,
18836            )
18837            .detach_and_log_err(cx);
18838        }
18839    }
18840
18841    pub(crate) fn apply_selected_diff_hunks(
18842        &mut self,
18843        _: &ApplyDiffHunk,
18844        window: &mut Window,
18845        cx: &mut Context<Self>,
18846    ) {
18847        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18848        let snapshot = self.snapshot(window, cx);
18849        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18850        let mut ranges_by_buffer = HashMap::default();
18851        self.transact(window, cx, |editor, _window, cx| {
18852            for hunk in hunks {
18853                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18854                    ranges_by_buffer
18855                        .entry(buffer.clone())
18856                        .or_insert_with(Vec::new)
18857                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18858                }
18859            }
18860
18861            for (buffer, ranges) in ranges_by_buffer {
18862                buffer.update(cx, |buffer, cx| {
18863                    buffer.merge_into_base(ranges, cx);
18864                });
18865            }
18866        });
18867
18868        if let Some(project) = self.project.clone() {
18869            self.save(
18870                SaveOptions {
18871                    format: true,
18872                    autosave: false,
18873                },
18874                project,
18875                window,
18876                cx,
18877            )
18878            .detach_and_log_err(cx);
18879        }
18880    }
18881
18882    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18883        if hovered != self.gutter_hovered {
18884            self.gutter_hovered = hovered;
18885            cx.notify();
18886        }
18887    }
18888
18889    pub fn insert_blocks(
18890        &mut self,
18891        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18892        autoscroll: Option<Autoscroll>,
18893        cx: &mut Context<Self>,
18894    ) -> Vec<CustomBlockId> {
18895        let blocks = self
18896            .display_map
18897            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18898        if let Some(autoscroll) = autoscroll {
18899            self.request_autoscroll(autoscroll, cx);
18900        }
18901        cx.notify();
18902        blocks
18903    }
18904
18905    pub fn resize_blocks(
18906        &mut self,
18907        heights: HashMap<CustomBlockId, u32>,
18908        autoscroll: Option<Autoscroll>,
18909        cx: &mut Context<Self>,
18910    ) {
18911        self.display_map
18912            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18913        if let Some(autoscroll) = autoscroll {
18914            self.request_autoscroll(autoscroll, cx);
18915        }
18916        cx.notify();
18917    }
18918
18919    pub fn replace_blocks(
18920        &mut self,
18921        renderers: HashMap<CustomBlockId, RenderBlock>,
18922        autoscroll: Option<Autoscroll>,
18923        cx: &mut Context<Self>,
18924    ) {
18925        self.display_map
18926            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18927        if let Some(autoscroll) = autoscroll {
18928            self.request_autoscroll(autoscroll, cx);
18929        }
18930        cx.notify();
18931    }
18932
18933    pub fn remove_blocks(
18934        &mut self,
18935        block_ids: HashSet<CustomBlockId>,
18936        autoscroll: Option<Autoscroll>,
18937        cx: &mut Context<Self>,
18938    ) {
18939        self.display_map.update(cx, |display_map, cx| {
18940            display_map.remove_blocks(block_ids, cx)
18941        });
18942        if let Some(autoscroll) = autoscroll {
18943            self.request_autoscroll(autoscroll, cx);
18944        }
18945        cx.notify();
18946    }
18947
18948    pub fn row_for_block(
18949        &self,
18950        block_id: CustomBlockId,
18951        cx: &mut Context<Self>,
18952    ) -> Option<DisplayRow> {
18953        self.display_map
18954            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18955    }
18956
18957    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18958        self.focused_block = Some(focused_block);
18959    }
18960
18961    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18962        self.focused_block.take()
18963    }
18964
18965    pub fn insert_creases(
18966        &mut self,
18967        creases: impl IntoIterator<Item = Crease<Anchor>>,
18968        cx: &mut Context<Self>,
18969    ) -> Vec<CreaseId> {
18970        self.display_map
18971            .update(cx, |map, cx| map.insert_creases(creases, cx))
18972    }
18973
18974    pub fn remove_creases(
18975        &mut self,
18976        ids: impl IntoIterator<Item = CreaseId>,
18977        cx: &mut Context<Self>,
18978    ) -> Vec<(CreaseId, Range<Anchor>)> {
18979        self.display_map
18980            .update(cx, |map, cx| map.remove_creases(ids, cx))
18981    }
18982
18983    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18984        self.display_map
18985            .update(cx, |map, cx| map.snapshot(cx))
18986            .longest_row()
18987    }
18988
18989    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18990        self.display_map
18991            .update(cx, |map, cx| map.snapshot(cx))
18992            .max_point()
18993    }
18994
18995    pub fn text(&self, cx: &App) -> String {
18996        self.buffer.read(cx).read(cx).text()
18997    }
18998
18999    pub fn is_empty(&self, cx: &App) -> bool {
19000        self.buffer.read(cx).read(cx).is_empty()
19001    }
19002
19003    pub fn text_option(&self, cx: &App) -> Option<String> {
19004        let text = self.text(cx);
19005        let text = text.trim();
19006
19007        if text.is_empty() {
19008            return None;
19009        }
19010
19011        Some(text.to_string())
19012    }
19013
19014    pub fn set_text(
19015        &mut self,
19016        text: impl Into<Arc<str>>,
19017        window: &mut Window,
19018        cx: &mut Context<Self>,
19019    ) {
19020        self.transact(window, cx, |this, _, cx| {
19021            this.buffer
19022                .read(cx)
19023                .as_singleton()
19024                .expect("you can only call set_text on editors for singleton buffers")
19025                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19026        });
19027    }
19028
19029    pub fn display_text(&self, cx: &mut App) -> String {
19030        self.display_map
19031            .update(cx, |map, cx| map.snapshot(cx))
19032            .text()
19033    }
19034
19035    fn create_minimap(
19036        &self,
19037        minimap_settings: MinimapSettings,
19038        window: &mut Window,
19039        cx: &mut Context<Self>,
19040    ) -> Option<Entity<Self>> {
19041        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
19042            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19043    }
19044
19045    fn initialize_new_minimap(
19046        &self,
19047        minimap_settings: MinimapSettings,
19048        window: &mut Window,
19049        cx: &mut Context<Self>,
19050    ) -> Entity<Self> {
19051        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19052
19053        let mut minimap = Editor::new_internal(
19054            EditorMode::Minimap {
19055                parent: cx.weak_entity(),
19056            },
19057            self.buffer.clone(),
19058            None,
19059            Some(self.display_map.clone()),
19060            window,
19061            cx,
19062        );
19063        minimap.scroll_manager.clone_state(&self.scroll_manager);
19064        minimap.set_text_style_refinement(TextStyleRefinement {
19065            font_size: Some(MINIMAP_FONT_SIZE),
19066            font_weight: Some(MINIMAP_FONT_WEIGHT),
19067            ..Default::default()
19068        });
19069        minimap.update_minimap_configuration(minimap_settings, cx);
19070        cx.new(|_| minimap)
19071    }
19072
19073    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19074        let current_line_highlight = minimap_settings
19075            .current_line_highlight
19076            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19077        self.set_current_line_highlight(Some(current_line_highlight));
19078    }
19079
19080    pub fn minimap(&self) -> Option<&Entity<Self>> {
19081        self.minimap
19082            .as_ref()
19083            .filter(|_| self.minimap_visibility.visible())
19084    }
19085
19086    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19087        let mut wrap_guides = smallvec![];
19088
19089        if self.show_wrap_guides == Some(false) {
19090            return wrap_guides;
19091        }
19092
19093        let settings = self.buffer.read(cx).language_settings(cx);
19094        if settings.show_wrap_guides {
19095            match self.soft_wrap_mode(cx) {
19096                SoftWrap::Column(soft_wrap) => {
19097                    wrap_guides.push((soft_wrap as usize, true));
19098                }
19099                SoftWrap::Bounded(soft_wrap) => {
19100                    wrap_guides.push((soft_wrap as usize, true));
19101                }
19102                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19103            }
19104            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19105        }
19106
19107        wrap_guides
19108    }
19109
19110    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19111        let settings = self.buffer.read(cx).language_settings(cx);
19112        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19113        match mode {
19114            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19115                SoftWrap::None
19116            }
19117            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19118            language_settings::SoftWrap::PreferredLineLength => {
19119                SoftWrap::Column(settings.preferred_line_length)
19120            }
19121            language_settings::SoftWrap::Bounded => {
19122                SoftWrap::Bounded(settings.preferred_line_length)
19123            }
19124        }
19125    }
19126
19127    pub fn set_soft_wrap_mode(
19128        &mut self,
19129        mode: language_settings::SoftWrap,
19130
19131        cx: &mut Context<Self>,
19132    ) {
19133        self.soft_wrap_mode_override = Some(mode);
19134        cx.notify();
19135    }
19136
19137    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19138        self.hard_wrap = hard_wrap;
19139        cx.notify();
19140    }
19141
19142    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19143        self.text_style_refinement = Some(style);
19144    }
19145
19146    /// called by the Element so we know what style we were most recently rendered with.
19147    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19148        // We intentionally do not inform the display map about the minimap style
19149        // so that wrapping is not recalculated and stays consistent for the editor
19150        // and its linked minimap.
19151        if !self.mode.is_minimap() {
19152            let font = style.text.font();
19153            let font_size = style.text.font_size.to_pixels(window.rem_size());
19154            let display_map = self
19155                .placeholder_display_map
19156                .as_ref()
19157                .filter(|_| self.is_empty(cx))
19158                .unwrap_or(&self.display_map);
19159
19160            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19161        }
19162        self.style = Some(style);
19163    }
19164
19165    pub fn style(&self) -> Option<&EditorStyle> {
19166        self.style.as_ref()
19167    }
19168
19169    // Called by the element. This method is not designed to be called outside of the editor
19170    // element's layout code because it does not notify when rewrapping is computed synchronously.
19171    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19172        if self.is_empty(cx) {
19173            self.placeholder_display_map
19174                .as_ref()
19175                .map_or(false, |display_map| {
19176                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19177                })
19178        } else {
19179            self.display_map
19180                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19181        }
19182    }
19183
19184    pub fn set_soft_wrap(&mut self) {
19185        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19186    }
19187
19188    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19189        if self.soft_wrap_mode_override.is_some() {
19190            self.soft_wrap_mode_override.take();
19191        } else {
19192            let soft_wrap = match self.soft_wrap_mode(cx) {
19193                SoftWrap::GitDiff => return,
19194                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19195                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19196                    language_settings::SoftWrap::None
19197                }
19198            };
19199            self.soft_wrap_mode_override = Some(soft_wrap);
19200        }
19201        cx.notify();
19202    }
19203
19204    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19205        let Some(workspace) = self.workspace() else {
19206            return;
19207        };
19208        let fs = workspace.read(cx).app_state().fs.clone();
19209        let current_show = TabBarSettings::get_global(cx).show;
19210        update_settings_file(fs, cx, move |setting, _| {
19211            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19212        });
19213    }
19214
19215    pub fn toggle_indent_guides(
19216        &mut self,
19217        _: &ToggleIndentGuides,
19218        _: &mut Window,
19219        cx: &mut Context<Self>,
19220    ) {
19221        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19222            self.buffer
19223                .read(cx)
19224                .language_settings(cx)
19225                .indent_guides
19226                .enabled
19227        });
19228        self.show_indent_guides = Some(!currently_enabled);
19229        cx.notify();
19230    }
19231
19232    fn should_show_indent_guides(&self) -> Option<bool> {
19233        self.show_indent_guides
19234    }
19235
19236    pub fn toggle_line_numbers(
19237        &mut self,
19238        _: &ToggleLineNumbers,
19239        _: &mut Window,
19240        cx: &mut Context<Self>,
19241    ) {
19242        let mut editor_settings = EditorSettings::get_global(cx).clone();
19243        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19244        EditorSettings::override_global(editor_settings, cx);
19245    }
19246
19247    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19248        if let Some(show_line_numbers) = self.show_line_numbers {
19249            return show_line_numbers;
19250        }
19251        EditorSettings::get_global(cx).gutter.line_numbers
19252    }
19253
19254    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19255        self.use_relative_line_numbers
19256            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19257    }
19258
19259    pub fn toggle_relative_line_numbers(
19260        &mut self,
19261        _: &ToggleRelativeLineNumbers,
19262        _: &mut Window,
19263        cx: &mut Context<Self>,
19264    ) {
19265        let is_relative = self.should_use_relative_line_numbers(cx);
19266        self.set_relative_line_number(Some(!is_relative), cx)
19267    }
19268
19269    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19270        self.use_relative_line_numbers = is_relative;
19271        cx.notify();
19272    }
19273
19274    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19275        self.show_gutter = show_gutter;
19276        cx.notify();
19277    }
19278
19279    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19280        self.show_scrollbars = ScrollbarAxes {
19281            horizontal: show,
19282            vertical: show,
19283        };
19284        cx.notify();
19285    }
19286
19287    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19288        self.show_scrollbars.vertical = show;
19289        cx.notify();
19290    }
19291
19292    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19293        self.show_scrollbars.horizontal = show;
19294        cx.notify();
19295    }
19296
19297    pub fn set_minimap_visibility(
19298        &mut self,
19299        minimap_visibility: MinimapVisibility,
19300        window: &mut Window,
19301        cx: &mut Context<Self>,
19302    ) {
19303        if self.minimap_visibility != minimap_visibility {
19304            if minimap_visibility.visible() && self.minimap.is_none() {
19305                let minimap_settings = EditorSettings::get_global(cx).minimap;
19306                self.minimap =
19307                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19308            }
19309            self.minimap_visibility = minimap_visibility;
19310            cx.notify();
19311        }
19312    }
19313
19314    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19315        self.set_show_scrollbars(false, cx);
19316        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19317    }
19318
19319    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19320        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19321    }
19322
19323    /// Normally the text in full mode and auto height editors is padded on the
19324    /// left side by roughly half a character width for improved hit testing.
19325    ///
19326    /// Use this method to disable this for cases where this is not wanted (e.g.
19327    /// if you want to align the editor text with some other text above or below)
19328    /// or if you want to add this padding to single-line editors.
19329    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19330        self.offset_content = offset_content;
19331        cx.notify();
19332    }
19333
19334    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19335        self.show_line_numbers = Some(show_line_numbers);
19336        cx.notify();
19337    }
19338
19339    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19340        self.disable_expand_excerpt_buttons = true;
19341        cx.notify();
19342    }
19343
19344    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19345        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19346        cx.notify();
19347    }
19348
19349    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19350        self.show_code_actions = Some(show_code_actions);
19351        cx.notify();
19352    }
19353
19354    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19355        self.show_runnables = Some(show_runnables);
19356        cx.notify();
19357    }
19358
19359    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19360        self.show_breakpoints = Some(show_breakpoints);
19361        cx.notify();
19362    }
19363
19364    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19365        if self.display_map.read(cx).masked != masked {
19366            self.display_map.update(cx, |map, _| map.masked = masked);
19367        }
19368        cx.notify()
19369    }
19370
19371    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19372        self.show_wrap_guides = Some(show_wrap_guides);
19373        cx.notify();
19374    }
19375
19376    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19377        self.show_indent_guides = Some(show_indent_guides);
19378        cx.notify();
19379    }
19380
19381    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19382        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19383            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19384                && let Some(dir) = file.abs_path(cx).parent()
19385            {
19386                return Some(dir.to_owned());
19387            }
19388        }
19389
19390        None
19391    }
19392
19393    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19394        self.active_excerpt(cx)?
19395            .1
19396            .read(cx)
19397            .file()
19398            .and_then(|f| f.as_local())
19399    }
19400
19401    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19402        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19403            let buffer = buffer.read(cx);
19404            if let Some(project_path) = buffer.project_path(cx) {
19405                let project = self.project()?.read(cx);
19406                project.absolute_path(&project_path, cx)
19407            } else {
19408                buffer
19409                    .file()
19410                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19411            }
19412        })
19413    }
19414
19415    pub fn reveal_in_finder(
19416        &mut self,
19417        _: &RevealInFileManager,
19418        _window: &mut Window,
19419        cx: &mut Context<Self>,
19420    ) {
19421        if let Some(target) = self.target_file(cx) {
19422            cx.reveal_path(&target.abs_path(cx));
19423        }
19424    }
19425
19426    pub fn copy_path(
19427        &mut self,
19428        _: &zed_actions::workspace::CopyPath,
19429        _window: &mut Window,
19430        cx: &mut Context<Self>,
19431    ) {
19432        if let Some(path) = self.target_file_abs_path(cx)
19433            && let Some(path) = path.to_str()
19434        {
19435            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19436        } else {
19437            cx.propagate();
19438        }
19439    }
19440
19441    pub fn copy_relative_path(
19442        &mut self,
19443        _: &zed_actions::workspace::CopyRelativePath,
19444        _window: &mut Window,
19445        cx: &mut Context<Self>,
19446    ) {
19447        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19448            let project = self.project()?.read(cx);
19449            let path = buffer.read(cx).file()?.path();
19450            let path = path.display(project.path_style(cx));
19451            Some(path)
19452        }) {
19453            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19454        } else {
19455            cx.propagate();
19456        }
19457    }
19458
19459    /// Returns the project path for the editor's buffer, if any buffer is
19460    /// opened in the editor.
19461    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19462        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19463            buffer.read(cx).project_path(cx)
19464        } else {
19465            None
19466        }
19467    }
19468
19469    // Returns true if the editor handled a go-to-line request
19470    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19471        maybe!({
19472            let breakpoint_store = self.breakpoint_store.as_ref()?;
19473
19474            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19475            else {
19476                self.clear_row_highlights::<ActiveDebugLine>();
19477                return None;
19478            };
19479
19480            let position = active_stack_frame.position;
19481            let buffer_id = position.buffer_id?;
19482            let snapshot = self
19483                .project
19484                .as_ref()?
19485                .read(cx)
19486                .buffer_for_id(buffer_id, cx)?
19487                .read(cx)
19488                .snapshot();
19489
19490            let mut handled = false;
19491            for (id, ExcerptRange { context, .. }) in
19492                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19493            {
19494                if context.start.cmp(&position, &snapshot).is_ge()
19495                    || context.end.cmp(&position, &snapshot).is_lt()
19496                {
19497                    continue;
19498                }
19499                let snapshot = self.buffer.read(cx).snapshot(cx);
19500                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19501
19502                handled = true;
19503                self.clear_row_highlights::<ActiveDebugLine>();
19504
19505                self.go_to_line::<ActiveDebugLine>(
19506                    multibuffer_anchor,
19507                    Some(cx.theme().colors().editor_debugger_active_line_background),
19508                    window,
19509                    cx,
19510                );
19511
19512                cx.notify();
19513            }
19514
19515            handled.then_some(())
19516        })
19517        .is_some()
19518    }
19519
19520    pub fn copy_file_name_without_extension(
19521        &mut self,
19522        _: &CopyFileNameWithoutExtension,
19523        _: &mut Window,
19524        cx: &mut Context<Self>,
19525    ) {
19526        if let Some(file) = self.target_file(cx)
19527            && let Some(file_stem) = file.path().file_stem()
19528        {
19529            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19530        }
19531    }
19532
19533    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19534        if let Some(file) = self.target_file(cx)
19535            && let Some(name) = file.path().file_name()
19536        {
19537            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19538        }
19539    }
19540
19541    pub fn toggle_git_blame(
19542        &mut self,
19543        _: &::git::Blame,
19544        window: &mut Window,
19545        cx: &mut Context<Self>,
19546    ) {
19547        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19548
19549        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19550            self.start_git_blame(true, window, cx);
19551        }
19552
19553        cx.notify();
19554    }
19555
19556    pub fn toggle_git_blame_inline(
19557        &mut self,
19558        _: &ToggleGitBlameInline,
19559        window: &mut Window,
19560        cx: &mut Context<Self>,
19561    ) {
19562        self.toggle_git_blame_inline_internal(true, window, cx);
19563        cx.notify();
19564    }
19565
19566    pub fn open_git_blame_commit(
19567        &mut self,
19568        _: &OpenGitBlameCommit,
19569        window: &mut Window,
19570        cx: &mut Context<Self>,
19571    ) {
19572        self.open_git_blame_commit_internal(window, cx);
19573    }
19574
19575    fn open_git_blame_commit_internal(
19576        &mut self,
19577        window: &mut Window,
19578        cx: &mut Context<Self>,
19579    ) -> Option<()> {
19580        let blame = self.blame.as_ref()?;
19581        let snapshot = self.snapshot(window, cx);
19582        let cursor = self.selections.newest::<Point>(cx).head();
19583        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19584        let (_, blame_entry) = blame
19585            .update(cx, |blame, cx| {
19586                blame
19587                    .blame_for_rows(
19588                        &[RowInfo {
19589                            buffer_id: Some(buffer.remote_id()),
19590                            buffer_row: Some(point.row),
19591                            ..Default::default()
19592                        }],
19593                        cx,
19594                    )
19595                    .next()
19596            })
19597            .flatten()?;
19598        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19599        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19600        let workspace = self.workspace()?.downgrade();
19601        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19602        None
19603    }
19604
19605    pub fn git_blame_inline_enabled(&self) -> bool {
19606        self.git_blame_inline_enabled
19607    }
19608
19609    pub fn toggle_selection_menu(
19610        &mut self,
19611        _: &ToggleSelectionMenu,
19612        _: &mut Window,
19613        cx: &mut Context<Self>,
19614    ) {
19615        self.show_selection_menu = self
19616            .show_selection_menu
19617            .map(|show_selections_menu| !show_selections_menu)
19618            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19619
19620        cx.notify();
19621    }
19622
19623    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19624        self.show_selection_menu
19625            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19626    }
19627
19628    fn start_git_blame(
19629        &mut self,
19630        user_triggered: bool,
19631        window: &mut Window,
19632        cx: &mut Context<Self>,
19633    ) {
19634        if let Some(project) = self.project() {
19635            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19636                && buffer.read(cx).file().is_none()
19637            {
19638                return;
19639            }
19640
19641            let focused = self.focus_handle(cx).contains_focused(window, cx);
19642
19643            let project = project.clone();
19644            let blame = cx
19645                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19646            self.blame_subscription =
19647                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19648            self.blame = Some(blame);
19649        }
19650    }
19651
19652    fn toggle_git_blame_inline_internal(
19653        &mut self,
19654        user_triggered: bool,
19655        window: &mut Window,
19656        cx: &mut Context<Self>,
19657    ) {
19658        if self.git_blame_inline_enabled {
19659            self.git_blame_inline_enabled = false;
19660            self.show_git_blame_inline = false;
19661            self.show_git_blame_inline_delay_task.take();
19662        } else {
19663            self.git_blame_inline_enabled = true;
19664            self.start_git_blame_inline(user_triggered, window, cx);
19665        }
19666
19667        cx.notify();
19668    }
19669
19670    fn start_git_blame_inline(
19671        &mut self,
19672        user_triggered: bool,
19673        window: &mut Window,
19674        cx: &mut Context<Self>,
19675    ) {
19676        self.start_git_blame(user_triggered, window, cx);
19677
19678        if ProjectSettings::get_global(cx)
19679            .git
19680            .inline_blame_delay()
19681            .is_some()
19682        {
19683            self.start_inline_blame_timer(window, cx);
19684        } else {
19685            self.show_git_blame_inline = true
19686        }
19687    }
19688
19689    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19690        self.blame.as_ref()
19691    }
19692
19693    pub fn show_git_blame_gutter(&self) -> bool {
19694        self.show_git_blame_gutter
19695    }
19696
19697    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19698        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19699    }
19700
19701    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19702        self.show_git_blame_inline
19703            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19704            && !self.newest_selection_head_on_empty_line(cx)
19705            && self.has_blame_entries(cx)
19706    }
19707
19708    fn has_blame_entries(&self, cx: &App) -> bool {
19709        self.blame()
19710            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19711    }
19712
19713    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19714        let cursor_anchor = self.selections.newest_anchor().head();
19715
19716        let snapshot = self.buffer.read(cx).snapshot(cx);
19717        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19718
19719        snapshot.line_len(buffer_row) == 0
19720    }
19721
19722    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19723        let buffer_and_selection = maybe!({
19724            let selection = self.selections.newest::<Point>(cx);
19725            let selection_range = selection.range();
19726
19727            let multi_buffer = self.buffer().read(cx);
19728            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19729            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19730
19731            let (buffer, range, _) = if selection.reversed {
19732                buffer_ranges.first()
19733            } else {
19734                buffer_ranges.last()
19735            }?;
19736
19737            let selection = text::ToPoint::to_point(&range.start, buffer).row
19738                ..text::ToPoint::to_point(&range.end, buffer).row;
19739            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19740        });
19741
19742        let Some((buffer, selection)) = buffer_and_selection else {
19743            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19744        };
19745
19746        let Some(project) = self.project() else {
19747            return Task::ready(Err(anyhow!("editor does not have project")));
19748        };
19749
19750        project.update(cx, |project, cx| {
19751            project.get_permalink_to_line(&buffer, selection, cx)
19752        })
19753    }
19754
19755    pub fn copy_permalink_to_line(
19756        &mut self,
19757        _: &CopyPermalinkToLine,
19758        window: &mut Window,
19759        cx: &mut Context<Self>,
19760    ) {
19761        let permalink_task = self.get_permalink_to_line(cx);
19762        let workspace = self.workspace();
19763
19764        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19765            Ok(permalink) => {
19766                cx.update(|_, cx| {
19767                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19768                })
19769                .ok();
19770            }
19771            Err(err) => {
19772                let message = format!("Failed to copy permalink: {err}");
19773
19774                anyhow::Result::<()>::Err(err).log_err();
19775
19776                if let Some(workspace) = workspace {
19777                    workspace
19778                        .update_in(cx, |workspace, _, cx| {
19779                            struct CopyPermalinkToLine;
19780
19781                            workspace.show_toast(
19782                                Toast::new(
19783                                    NotificationId::unique::<CopyPermalinkToLine>(),
19784                                    message,
19785                                ),
19786                                cx,
19787                            )
19788                        })
19789                        .ok();
19790                }
19791            }
19792        })
19793        .detach();
19794    }
19795
19796    pub fn copy_file_location(
19797        &mut self,
19798        _: &CopyFileLocation,
19799        _: &mut Window,
19800        cx: &mut Context<Self>,
19801    ) {
19802        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19803        if let Some(file) = self.target_file(cx) {
19804            let path = file.path().display(file.path_style(cx));
19805            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19806        }
19807    }
19808
19809    pub fn open_permalink_to_line(
19810        &mut self,
19811        _: &OpenPermalinkToLine,
19812        window: &mut Window,
19813        cx: &mut Context<Self>,
19814    ) {
19815        let permalink_task = self.get_permalink_to_line(cx);
19816        let workspace = self.workspace();
19817
19818        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19819            Ok(permalink) => {
19820                cx.update(|_, cx| {
19821                    cx.open_url(permalink.as_ref());
19822                })
19823                .ok();
19824            }
19825            Err(err) => {
19826                let message = format!("Failed to open permalink: {err}");
19827
19828                anyhow::Result::<()>::Err(err).log_err();
19829
19830                if let Some(workspace) = workspace {
19831                    workspace
19832                        .update(cx, |workspace, cx| {
19833                            struct OpenPermalinkToLine;
19834
19835                            workspace.show_toast(
19836                                Toast::new(
19837                                    NotificationId::unique::<OpenPermalinkToLine>(),
19838                                    message,
19839                                ),
19840                                cx,
19841                            )
19842                        })
19843                        .ok();
19844                }
19845            }
19846        })
19847        .detach();
19848    }
19849
19850    pub fn insert_uuid_v4(
19851        &mut self,
19852        _: &InsertUuidV4,
19853        window: &mut Window,
19854        cx: &mut Context<Self>,
19855    ) {
19856        self.insert_uuid(UuidVersion::V4, window, cx);
19857    }
19858
19859    pub fn insert_uuid_v7(
19860        &mut self,
19861        _: &InsertUuidV7,
19862        window: &mut Window,
19863        cx: &mut Context<Self>,
19864    ) {
19865        self.insert_uuid(UuidVersion::V7, window, cx);
19866    }
19867
19868    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19869        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19870        self.transact(window, cx, |this, window, cx| {
19871            let edits = this
19872                .selections
19873                .all::<Point>(cx)
19874                .into_iter()
19875                .map(|selection| {
19876                    let uuid = match version {
19877                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19878                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19879                    };
19880
19881                    (selection.range(), uuid.to_string())
19882                });
19883            this.edit(edits, cx);
19884            this.refresh_edit_prediction(true, false, window, cx);
19885        });
19886    }
19887
19888    pub fn open_selections_in_multibuffer(
19889        &mut self,
19890        _: &OpenSelectionsInMultibuffer,
19891        window: &mut Window,
19892        cx: &mut Context<Self>,
19893    ) {
19894        let multibuffer = self.buffer.read(cx);
19895
19896        let Some(buffer) = multibuffer.as_singleton() else {
19897            return;
19898        };
19899
19900        let Some(workspace) = self.workspace() else {
19901            return;
19902        };
19903
19904        let title = multibuffer.title(cx).to_string();
19905
19906        let locations = self
19907            .selections
19908            .all_anchors(cx)
19909            .iter()
19910            .map(|selection| {
19911                (
19912                    buffer.clone(),
19913                    (selection.start.text_anchor..selection.end.text_anchor)
19914                        .to_point(buffer.read(cx)),
19915                )
19916            })
19917            .into_group_map();
19918
19919        cx.spawn_in(window, async move |_, cx| {
19920            workspace.update_in(cx, |workspace, window, cx| {
19921                Self::open_locations_in_multibuffer(
19922                    workspace,
19923                    locations,
19924                    format!("Selections for '{title}'"),
19925                    false,
19926                    MultibufferSelectionMode::All,
19927                    window,
19928                    cx,
19929                );
19930            })
19931        })
19932        .detach();
19933    }
19934
19935    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19936    /// last highlight added will be used.
19937    ///
19938    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19939    pub fn highlight_rows<T: 'static>(
19940        &mut self,
19941        range: Range<Anchor>,
19942        color: Hsla,
19943        options: RowHighlightOptions,
19944        cx: &mut Context<Self>,
19945    ) {
19946        let snapshot = self.buffer().read(cx).snapshot(cx);
19947        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19948        let ix = row_highlights.binary_search_by(|highlight| {
19949            Ordering::Equal
19950                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19951                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19952        });
19953
19954        if let Err(mut ix) = ix {
19955            let index = post_inc(&mut self.highlight_order);
19956
19957            // If this range intersects with the preceding highlight, then merge it with
19958            // the preceding highlight. Otherwise insert a new highlight.
19959            let mut merged = false;
19960            if ix > 0 {
19961                let prev_highlight = &mut row_highlights[ix - 1];
19962                if prev_highlight
19963                    .range
19964                    .end
19965                    .cmp(&range.start, &snapshot)
19966                    .is_ge()
19967                {
19968                    ix -= 1;
19969                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19970                        prev_highlight.range.end = range.end;
19971                    }
19972                    merged = true;
19973                    prev_highlight.index = index;
19974                    prev_highlight.color = color;
19975                    prev_highlight.options = options;
19976                }
19977            }
19978
19979            if !merged {
19980                row_highlights.insert(
19981                    ix,
19982                    RowHighlight {
19983                        range,
19984                        index,
19985                        color,
19986                        options,
19987                        type_id: TypeId::of::<T>(),
19988                    },
19989                );
19990            }
19991
19992            // If any of the following highlights intersect with this one, merge them.
19993            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19994                let highlight = &row_highlights[ix];
19995                if next_highlight
19996                    .range
19997                    .start
19998                    .cmp(&highlight.range.end, &snapshot)
19999                    .is_le()
20000                {
20001                    if next_highlight
20002                        .range
20003                        .end
20004                        .cmp(&highlight.range.end, &snapshot)
20005                        .is_gt()
20006                    {
20007                        row_highlights[ix].range.end = next_highlight.range.end;
20008                    }
20009                    row_highlights.remove(ix + 1);
20010                } else {
20011                    break;
20012                }
20013            }
20014        }
20015    }
20016
20017    /// Remove any highlighted row ranges of the given type that intersect the
20018    /// given ranges.
20019    pub fn remove_highlighted_rows<T: 'static>(
20020        &mut self,
20021        ranges_to_remove: Vec<Range<Anchor>>,
20022        cx: &mut Context<Self>,
20023    ) {
20024        let snapshot = self.buffer().read(cx).snapshot(cx);
20025        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20026        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20027        row_highlights.retain(|highlight| {
20028            while let Some(range_to_remove) = ranges_to_remove.peek() {
20029                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20030                    Ordering::Less | Ordering::Equal => {
20031                        ranges_to_remove.next();
20032                    }
20033                    Ordering::Greater => {
20034                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20035                            Ordering::Less | Ordering::Equal => {
20036                                return false;
20037                            }
20038                            Ordering::Greater => break,
20039                        }
20040                    }
20041                }
20042            }
20043
20044            true
20045        })
20046    }
20047
20048    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20049    pub fn clear_row_highlights<T: 'static>(&mut self) {
20050        self.highlighted_rows.remove(&TypeId::of::<T>());
20051    }
20052
20053    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20054    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20055        self.highlighted_rows
20056            .get(&TypeId::of::<T>())
20057            .map_or(&[] as &[_], |vec| vec.as_slice())
20058            .iter()
20059            .map(|highlight| (highlight.range.clone(), highlight.color))
20060    }
20061
20062    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20063    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20064    /// Allows to ignore certain kinds of highlights.
20065    pub fn highlighted_display_rows(
20066        &self,
20067        window: &mut Window,
20068        cx: &mut App,
20069    ) -> BTreeMap<DisplayRow, LineHighlight> {
20070        let snapshot = self.snapshot(window, cx);
20071        let mut used_highlight_orders = HashMap::default();
20072        self.highlighted_rows
20073            .iter()
20074            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20075            .fold(
20076                BTreeMap::<DisplayRow, LineHighlight>::new(),
20077                |mut unique_rows, highlight| {
20078                    let start = highlight.range.start.to_display_point(&snapshot);
20079                    let end = highlight.range.end.to_display_point(&snapshot);
20080                    let start_row = start.row().0;
20081                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20082                        && end.column() == 0
20083                    {
20084                        end.row().0.saturating_sub(1)
20085                    } else {
20086                        end.row().0
20087                    };
20088                    for row in start_row..=end_row {
20089                        let used_index =
20090                            used_highlight_orders.entry(row).or_insert(highlight.index);
20091                        if highlight.index >= *used_index {
20092                            *used_index = highlight.index;
20093                            unique_rows.insert(
20094                                DisplayRow(row),
20095                                LineHighlight {
20096                                    include_gutter: highlight.options.include_gutter,
20097                                    border: None,
20098                                    background: highlight.color.into(),
20099                                    type_id: Some(highlight.type_id),
20100                                },
20101                            );
20102                        }
20103                    }
20104                    unique_rows
20105                },
20106            )
20107    }
20108
20109    pub fn highlighted_display_row_for_autoscroll(
20110        &self,
20111        snapshot: &DisplaySnapshot,
20112    ) -> Option<DisplayRow> {
20113        self.highlighted_rows
20114            .values()
20115            .flat_map(|highlighted_rows| highlighted_rows.iter())
20116            .filter_map(|highlight| {
20117                if highlight.options.autoscroll {
20118                    Some(highlight.range.start.to_display_point(snapshot).row())
20119                } else {
20120                    None
20121                }
20122            })
20123            .min()
20124    }
20125
20126    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20127        self.highlight_background::<SearchWithinRange>(
20128            ranges,
20129            |colors| colors.colors().editor_document_highlight_read_background,
20130            cx,
20131        )
20132    }
20133
20134    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20135        self.breadcrumb_header = Some(new_header);
20136    }
20137
20138    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20139        self.clear_background_highlights::<SearchWithinRange>(cx);
20140    }
20141
20142    pub fn highlight_background<T: 'static>(
20143        &mut self,
20144        ranges: &[Range<Anchor>],
20145        color_fetcher: fn(&Theme) -> Hsla,
20146        cx: &mut Context<Self>,
20147    ) {
20148        self.background_highlights.insert(
20149            HighlightKey::Type(TypeId::of::<T>()),
20150            (color_fetcher, Arc::from(ranges)),
20151        );
20152        self.scrollbar_marker_state.dirty = true;
20153        cx.notify();
20154    }
20155
20156    pub fn highlight_background_key<T: 'static>(
20157        &mut self,
20158        key: usize,
20159        ranges: &[Range<Anchor>],
20160        color_fetcher: fn(&Theme) -> Hsla,
20161        cx: &mut Context<Self>,
20162    ) {
20163        self.background_highlights.insert(
20164            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20165            (color_fetcher, Arc::from(ranges)),
20166        );
20167        self.scrollbar_marker_state.dirty = true;
20168        cx.notify();
20169    }
20170
20171    pub fn clear_background_highlights<T: 'static>(
20172        &mut self,
20173        cx: &mut Context<Self>,
20174    ) -> Option<BackgroundHighlight> {
20175        let text_highlights = self
20176            .background_highlights
20177            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20178        if !text_highlights.1.is_empty() {
20179            self.scrollbar_marker_state.dirty = true;
20180            cx.notify();
20181        }
20182        Some(text_highlights)
20183    }
20184
20185    pub fn highlight_gutter<T: 'static>(
20186        &mut self,
20187        ranges: impl Into<Vec<Range<Anchor>>>,
20188        color_fetcher: fn(&App) -> Hsla,
20189        cx: &mut Context<Self>,
20190    ) {
20191        self.gutter_highlights
20192            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20193        cx.notify();
20194    }
20195
20196    pub fn clear_gutter_highlights<T: 'static>(
20197        &mut self,
20198        cx: &mut Context<Self>,
20199    ) -> Option<GutterHighlight> {
20200        cx.notify();
20201        self.gutter_highlights.remove(&TypeId::of::<T>())
20202    }
20203
20204    pub fn insert_gutter_highlight<T: 'static>(
20205        &mut self,
20206        range: Range<Anchor>,
20207        color_fetcher: fn(&App) -> Hsla,
20208        cx: &mut Context<Self>,
20209    ) {
20210        let snapshot = self.buffer().read(cx).snapshot(cx);
20211        let mut highlights = self
20212            .gutter_highlights
20213            .remove(&TypeId::of::<T>())
20214            .map(|(_, highlights)| highlights)
20215            .unwrap_or_default();
20216        let ix = highlights.binary_search_by(|highlight| {
20217            Ordering::Equal
20218                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20219                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20220        });
20221        if let Err(ix) = ix {
20222            highlights.insert(ix, range);
20223        }
20224        self.gutter_highlights
20225            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20226    }
20227
20228    pub fn remove_gutter_highlights<T: 'static>(
20229        &mut self,
20230        ranges_to_remove: Vec<Range<Anchor>>,
20231        cx: &mut Context<Self>,
20232    ) {
20233        let snapshot = self.buffer().read(cx).snapshot(cx);
20234        let Some((color_fetcher, mut gutter_highlights)) =
20235            self.gutter_highlights.remove(&TypeId::of::<T>())
20236        else {
20237            return;
20238        };
20239        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20240        gutter_highlights.retain(|highlight| {
20241            while let Some(range_to_remove) = ranges_to_remove.peek() {
20242                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20243                    Ordering::Less | Ordering::Equal => {
20244                        ranges_to_remove.next();
20245                    }
20246                    Ordering::Greater => {
20247                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20248                            Ordering::Less | Ordering::Equal => {
20249                                return false;
20250                            }
20251                            Ordering::Greater => break,
20252                        }
20253                    }
20254                }
20255            }
20256
20257            true
20258        });
20259        self.gutter_highlights
20260            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20261    }
20262
20263    #[cfg(feature = "test-support")]
20264    pub fn all_text_highlights(
20265        &self,
20266        window: &mut Window,
20267        cx: &mut Context<Self>,
20268    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20269        let snapshot = self.snapshot(window, cx);
20270        self.display_map.update(cx, |display_map, _| {
20271            display_map
20272                .all_text_highlights()
20273                .map(|highlight| {
20274                    let (style, ranges) = highlight.as_ref();
20275                    (
20276                        *style,
20277                        ranges
20278                            .iter()
20279                            .map(|range| range.clone().to_display_points(&snapshot))
20280                            .collect(),
20281                    )
20282                })
20283                .collect()
20284        })
20285    }
20286
20287    #[cfg(feature = "test-support")]
20288    pub fn all_text_background_highlights(
20289        &self,
20290        window: &mut Window,
20291        cx: &mut Context<Self>,
20292    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20293        let snapshot = self.snapshot(window, cx);
20294        let buffer = &snapshot.buffer_snapshot;
20295        let start = buffer.anchor_before(0);
20296        let end = buffer.anchor_after(buffer.len());
20297        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20298    }
20299
20300    #[cfg(any(test, feature = "test-support"))]
20301    pub fn sorted_background_highlights_in_range(
20302        &self,
20303        search_range: Range<Anchor>,
20304        display_snapshot: &DisplaySnapshot,
20305        theme: &Theme,
20306    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20307        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20308        res.sort_by(|a, b| {
20309            a.0.start
20310                .cmp(&b.0.start)
20311                .then_with(|| a.0.end.cmp(&b.0.end))
20312                .then_with(|| a.1.cmp(&b.1))
20313        });
20314        res
20315    }
20316
20317    #[cfg(feature = "test-support")]
20318    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20319        let snapshot = self.buffer().read(cx).snapshot(cx);
20320
20321        let highlights = self
20322            .background_highlights
20323            .get(&HighlightKey::Type(TypeId::of::<
20324                items::BufferSearchHighlights,
20325            >()));
20326
20327        if let Some((_color, ranges)) = highlights {
20328            ranges
20329                .iter()
20330                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20331                .collect_vec()
20332        } else {
20333            vec![]
20334        }
20335    }
20336
20337    fn document_highlights_for_position<'a>(
20338        &'a self,
20339        position: Anchor,
20340        buffer: &'a MultiBufferSnapshot,
20341    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20342        let read_highlights = self
20343            .background_highlights
20344            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20345            .map(|h| &h.1);
20346        let write_highlights = self
20347            .background_highlights
20348            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20349            .map(|h| &h.1);
20350        let left_position = position.bias_left(buffer);
20351        let right_position = position.bias_right(buffer);
20352        read_highlights
20353            .into_iter()
20354            .chain(write_highlights)
20355            .flat_map(move |ranges| {
20356                let start_ix = match ranges.binary_search_by(|probe| {
20357                    let cmp = probe.end.cmp(&left_position, buffer);
20358                    if cmp.is_ge() {
20359                        Ordering::Greater
20360                    } else {
20361                        Ordering::Less
20362                    }
20363                }) {
20364                    Ok(i) | Err(i) => i,
20365                };
20366
20367                ranges[start_ix..]
20368                    .iter()
20369                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20370            })
20371    }
20372
20373    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20374        self.background_highlights
20375            .get(&HighlightKey::Type(TypeId::of::<T>()))
20376            .is_some_and(|(_, highlights)| !highlights.is_empty())
20377    }
20378
20379    /// Returns all background highlights for a given range.
20380    ///
20381    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20382    pub fn background_highlights_in_range(
20383        &self,
20384        search_range: Range<Anchor>,
20385        display_snapshot: &DisplaySnapshot,
20386        theme: &Theme,
20387    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20388        let mut results = Vec::new();
20389        for (color_fetcher, ranges) in self.background_highlights.values() {
20390            let color = color_fetcher(theme);
20391            let start_ix = match ranges.binary_search_by(|probe| {
20392                let cmp = probe
20393                    .end
20394                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20395                if cmp.is_gt() {
20396                    Ordering::Greater
20397                } else {
20398                    Ordering::Less
20399                }
20400            }) {
20401                Ok(i) | Err(i) => i,
20402            };
20403            for range in &ranges[start_ix..] {
20404                if range
20405                    .start
20406                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20407                    .is_ge()
20408                {
20409                    break;
20410                }
20411
20412                let start = range.start.to_display_point(display_snapshot);
20413                let end = range.end.to_display_point(display_snapshot);
20414                results.push((start..end, color))
20415            }
20416        }
20417        results
20418    }
20419
20420    pub fn gutter_highlights_in_range(
20421        &self,
20422        search_range: Range<Anchor>,
20423        display_snapshot: &DisplaySnapshot,
20424        cx: &App,
20425    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20426        let mut results = Vec::new();
20427        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20428            let color = color_fetcher(cx);
20429            let start_ix = match ranges.binary_search_by(|probe| {
20430                let cmp = probe
20431                    .end
20432                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20433                if cmp.is_gt() {
20434                    Ordering::Greater
20435                } else {
20436                    Ordering::Less
20437                }
20438            }) {
20439                Ok(i) | Err(i) => i,
20440            };
20441            for range in &ranges[start_ix..] {
20442                if range
20443                    .start
20444                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20445                    .is_ge()
20446                {
20447                    break;
20448                }
20449
20450                let start = range.start.to_display_point(display_snapshot);
20451                let end = range.end.to_display_point(display_snapshot);
20452                results.push((start..end, color))
20453            }
20454        }
20455        results
20456    }
20457
20458    /// Get the text ranges corresponding to the redaction query
20459    pub fn redacted_ranges(
20460        &self,
20461        search_range: Range<Anchor>,
20462        display_snapshot: &DisplaySnapshot,
20463        cx: &App,
20464    ) -> Vec<Range<DisplayPoint>> {
20465        display_snapshot
20466            .buffer_snapshot
20467            .redacted_ranges(search_range, |file| {
20468                if let Some(file) = file {
20469                    file.is_private()
20470                        && EditorSettings::get(
20471                            Some(SettingsLocation {
20472                                worktree_id: file.worktree_id(cx),
20473                                path: file.path().as_ref(),
20474                            }),
20475                            cx,
20476                        )
20477                        .redact_private_values
20478                } else {
20479                    false
20480                }
20481            })
20482            .map(|range| {
20483                range.start.to_display_point(display_snapshot)
20484                    ..range.end.to_display_point(display_snapshot)
20485            })
20486            .collect()
20487    }
20488
20489    pub fn highlight_text_key<T: 'static>(
20490        &mut self,
20491        key: usize,
20492        ranges: Vec<Range<Anchor>>,
20493        style: HighlightStyle,
20494        cx: &mut Context<Self>,
20495    ) {
20496        self.display_map.update(cx, |map, _| {
20497            map.highlight_text(
20498                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20499                ranges,
20500                style,
20501            );
20502        });
20503        cx.notify();
20504    }
20505
20506    pub fn highlight_text<T: 'static>(
20507        &mut self,
20508        ranges: Vec<Range<Anchor>>,
20509        style: HighlightStyle,
20510        cx: &mut Context<Self>,
20511    ) {
20512        self.display_map.update(cx, |map, _| {
20513            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20514        });
20515        cx.notify();
20516    }
20517
20518    pub(crate) fn highlight_inlays<T: 'static>(
20519        &mut self,
20520        highlights: Vec<InlayHighlight>,
20521        style: HighlightStyle,
20522        cx: &mut Context<Self>,
20523    ) {
20524        self.display_map.update(cx, |map, _| {
20525            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20526        });
20527        cx.notify();
20528    }
20529
20530    pub fn text_highlights<'a, T: 'static>(
20531        &'a self,
20532        cx: &'a App,
20533    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20534        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20535    }
20536
20537    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20538        let cleared = self
20539            .display_map
20540            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20541        if cleared {
20542            cx.notify();
20543        }
20544    }
20545
20546    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20547        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20548            && self.focus_handle.is_focused(window)
20549    }
20550
20551    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20552        self.show_cursor_when_unfocused = is_enabled;
20553        cx.notify();
20554    }
20555
20556    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20557        cx.notify();
20558    }
20559
20560    fn on_debug_session_event(
20561        &mut self,
20562        _session: Entity<Session>,
20563        event: &SessionEvent,
20564        cx: &mut Context<Self>,
20565    ) {
20566        if let SessionEvent::InvalidateInlineValue = event {
20567            self.refresh_inline_values(cx);
20568        }
20569    }
20570
20571    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20572        let Some(project) = self.project.clone() else {
20573            return;
20574        };
20575
20576        if !self.inline_value_cache.enabled {
20577            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20578            self.splice_inlays(&inlays, Vec::new(), cx);
20579            return;
20580        }
20581
20582        let current_execution_position = self
20583            .highlighted_rows
20584            .get(&TypeId::of::<ActiveDebugLine>())
20585            .and_then(|lines| lines.last().map(|line| line.range.end));
20586
20587        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20588            let inline_values = editor
20589                .update(cx, |editor, cx| {
20590                    let Some(current_execution_position) = current_execution_position else {
20591                        return Some(Task::ready(Ok(Vec::new())));
20592                    };
20593
20594                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20595                        let snapshot = buffer.snapshot(cx);
20596
20597                        let excerpt = snapshot.excerpt_containing(
20598                            current_execution_position..current_execution_position,
20599                        )?;
20600
20601                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20602                    })?;
20603
20604                    let range =
20605                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20606
20607                    project.inline_values(buffer, range, cx)
20608                })
20609                .ok()
20610                .flatten()?
20611                .await
20612                .context("refreshing debugger inlays")
20613                .log_err()?;
20614
20615            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20616
20617            for (buffer_id, inline_value) in inline_values
20618                .into_iter()
20619                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20620            {
20621                buffer_inline_values
20622                    .entry(buffer_id)
20623                    .or_default()
20624                    .push(inline_value);
20625            }
20626
20627            editor
20628                .update(cx, |editor, cx| {
20629                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20630                    let mut new_inlays = Vec::default();
20631
20632                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20633                        let buffer_id = buffer_snapshot.remote_id();
20634                        buffer_inline_values
20635                            .get(&buffer_id)
20636                            .into_iter()
20637                            .flatten()
20638                            .for_each(|hint| {
20639                                let inlay = Inlay::debugger(
20640                                    post_inc(&mut editor.next_inlay_id),
20641                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20642                                    hint.text(),
20643                                );
20644                                if !inlay.text().chars().contains(&'\n') {
20645                                    new_inlays.push(inlay);
20646                                }
20647                            });
20648                    }
20649
20650                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20651                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20652
20653                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20654                })
20655                .ok()?;
20656            Some(())
20657        });
20658    }
20659
20660    fn on_buffer_event(
20661        &mut self,
20662        multibuffer: &Entity<MultiBuffer>,
20663        event: &multi_buffer::Event,
20664        window: &mut Window,
20665        cx: &mut Context<Self>,
20666    ) {
20667        match event {
20668            multi_buffer::Event::Edited {
20669                singleton_buffer_edited,
20670                edited_buffer,
20671            } => {
20672                self.scrollbar_marker_state.dirty = true;
20673                self.active_indent_guides_state.dirty = true;
20674                self.refresh_active_diagnostics(cx);
20675                self.refresh_code_actions(window, cx);
20676                self.refresh_selected_text_highlights(true, window, cx);
20677                self.refresh_single_line_folds(window, cx);
20678                refresh_matching_bracket_highlights(self, window, cx);
20679                if self.has_active_edit_prediction() {
20680                    self.update_visible_edit_prediction(window, cx);
20681                }
20682                if let Some(project) = self.project.as_ref()
20683                    && let Some(edited_buffer) = edited_buffer
20684                {
20685                    project.update(cx, |project, cx| {
20686                        self.registered_buffers
20687                            .entry(edited_buffer.read(cx).remote_id())
20688                            .or_insert_with(|| {
20689                                project.register_buffer_with_language_servers(edited_buffer, cx)
20690                            });
20691                    });
20692                }
20693                cx.emit(EditorEvent::BufferEdited);
20694                cx.emit(SearchEvent::MatchesInvalidated);
20695
20696                if let Some(buffer) = edited_buffer {
20697                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20698                }
20699
20700                if *singleton_buffer_edited {
20701                    if let Some(buffer) = edited_buffer
20702                        && buffer.read(cx).file().is_none()
20703                    {
20704                        cx.emit(EditorEvent::TitleChanged);
20705                    }
20706                    if let Some(project) = &self.project {
20707                        #[allow(clippy::mutable_key_type)]
20708                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20709                            multibuffer
20710                                .all_buffers()
20711                                .into_iter()
20712                                .filter_map(|buffer| {
20713                                    buffer.update(cx, |buffer, cx| {
20714                                        let language = buffer.language()?;
20715                                        let should_discard = project.update(cx, |project, cx| {
20716                                            project.is_local()
20717                                                && !project.has_language_servers_for(buffer, cx)
20718                                        });
20719                                        should_discard.not().then_some(language.clone())
20720                                    })
20721                                })
20722                                .collect::<HashSet<_>>()
20723                        });
20724                        if !languages_affected.is_empty() {
20725                            self.refresh_inlay_hints(
20726                                InlayHintRefreshReason::BufferEdited(languages_affected),
20727                                cx,
20728                            );
20729                        }
20730                    }
20731                }
20732
20733                let Some(project) = &self.project else { return };
20734                let (telemetry, is_via_ssh) = {
20735                    let project = project.read(cx);
20736                    let telemetry = project.client().telemetry().clone();
20737                    let is_via_ssh = project.is_via_remote_server();
20738                    (telemetry, is_via_ssh)
20739                };
20740                refresh_linked_ranges(self, window, cx);
20741                telemetry.log_edit_event("editor", is_via_ssh);
20742            }
20743            multi_buffer::Event::ExcerptsAdded {
20744                buffer,
20745                predecessor,
20746                excerpts,
20747            } => {
20748                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20749                let buffer_id = buffer.read(cx).remote_id();
20750                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20751                    && let Some(project) = &self.project
20752                {
20753                    update_uncommitted_diff_for_buffer(
20754                        cx.entity(),
20755                        project,
20756                        [buffer.clone()],
20757                        self.buffer.clone(),
20758                        cx,
20759                    )
20760                    .detach();
20761                }
20762                if self.active_diagnostics != ActiveDiagnostic::All {
20763                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20764                }
20765                cx.emit(EditorEvent::ExcerptsAdded {
20766                    buffer: buffer.clone(),
20767                    predecessor: *predecessor,
20768                    excerpts: excerpts.clone(),
20769                });
20770                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20771            }
20772            multi_buffer::Event::ExcerptsRemoved {
20773                ids,
20774                removed_buffer_ids,
20775            } => {
20776                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20777                let buffer = self.buffer.read(cx);
20778                self.registered_buffers
20779                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20780                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20781                cx.emit(EditorEvent::ExcerptsRemoved {
20782                    ids: ids.clone(),
20783                    removed_buffer_ids: removed_buffer_ids.clone(),
20784                });
20785            }
20786            multi_buffer::Event::ExcerptsEdited {
20787                excerpt_ids,
20788                buffer_ids,
20789            } => {
20790                self.display_map.update(cx, |map, cx| {
20791                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20792                });
20793                cx.emit(EditorEvent::ExcerptsEdited {
20794                    ids: excerpt_ids.clone(),
20795                });
20796            }
20797            multi_buffer::Event::ExcerptsExpanded { ids } => {
20798                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20799                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20800            }
20801            multi_buffer::Event::Reparsed(buffer_id) => {
20802                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20803                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20804
20805                cx.emit(EditorEvent::Reparsed(*buffer_id));
20806            }
20807            multi_buffer::Event::DiffHunksToggled => {
20808                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20809            }
20810            multi_buffer::Event::LanguageChanged(buffer_id) => {
20811                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20812                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20813                cx.emit(EditorEvent::Reparsed(*buffer_id));
20814                cx.notify();
20815            }
20816            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20817            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20818            multi_buffer::Event::FileHandleChanged
20819            | multi_buffer::Event::Reloaded
20820            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20821            multi_buffer::Event::DiagnosticsUpdated => {
20822                self.update_diagnostics_state(window, cx);
20823            }
20824            _ => {}
20825        };
20826    }
20827
20828    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20829        if !self.diagnostics_enabled() {
20830            return;
20831        }
20832        self.refresh_active_diagnostics(cx);
20833        self.refresh_inline_diagnostics(true, window, cx);
20834        self.scrollbar_marker_state.dirty = true;
20835        cx.notify();
20836    }
20837
20838    pub fn start_temporary_diff_override(&mut self) {
20839        self.load_diff_task.take();
20840        self.temporary_diff_override = true;
20841    }
20842
20843    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20844        self.temporary_diff_override = false;
20845        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20846        self.buffer.update(cx, |buffer, cx| {
20847            buffer.set_all_diff_hunks_collapsed(cx);
20848        });
20849
20850        if let Some(project) = self.project.clone() {
20851            self.load_diff_task = Some(
20852                update_uncommitted_diff_for_buffer(
20853                    cx.entity(),
20854                    &project,
20855                    self.buffer.read(cx).all_buffers(),
20856                    self.buffer.clone(),
20857                    cx,
20858                )
20859                .shared(),
20860            );
20861        }
20862    }
20863
20864    fn on_display_map_changed(
20865        &mut self,
20866        _: Entity<DisplayMap>,
20867        _: &mut Window,
20868        cx: &mut Context<Self>,
20869    ) {
20870        cx.notify();
20871    }
20872
20873    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20874        if self.diagnostics_enabled() {
20875            let new_severity = EditorSettings::get_global(cx)
20876                .diagnostics_max_severity
20877                .unwrap_or(DiagnosticSeverity::Hint);
20878            self.set_max_diagnostics_severity(new_severity, cx);
20879        }
20880        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20881        self.update_edit_prediction_settings(cx);
20882        self.refresh_edit_prediction(true, false, window, cx);
20883        self.refresh_inline_values(cx);
20884        self.refresh_inlay_hints(
20885            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20886                self.selections.newest_anchor().head(),
20887                &self.buffer.read(cx).snapshot(cx),
20888                cx,
20889            )),
20890            cx,
20891        );
20892
20893        let old_cursor_shape = self.cursor_shape;
20894        let old_show_breadcrumbs = self.show_breadcrumbs;
20895
20896        {
20897            let editor_settings = EditorSettings::get_global(cx);
20898            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20899            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20900            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20901            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20902        }
20903
20904        if old_cursor_shape != self.cursor_shape {
20905            cx.emit(EditorEvent::CursorShapeChanged);
20906        }
20907
20908        if old_show_breadcrumbs != self.show_breadcrumbs {
20909            cx.emit(EditorEvent::BreadcrumbsChanged);
20910        }
20911
20912        let project_settings = ProjectSettings::get_global(cx);
20913        self.serialize_dirty_buffers =
20914            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20915
20916        if self.mode.is_full() {
20917            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20918            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20919            if self.show_inline_diagnostics != show_inline_diagnostics {
20920                self.show_inline_diagnostics = show_inline_diagnostics;
20921                self.refresh_inline_diagnostics(false, window, cx);
20922            }
20923
20924            if self.git_blame_inline_enabled != inline_blame_enabled {
20925                self.toggle_git_blame_inline_internal(false, window, cx);
20926            }
20927
20928            let minimap_settings = EditorSettings::get_global(cx).minimap;
20929            if self.minimap_visibility != MinimapVisibility::Disabled {
20930                if self.minimap_visibility.settings_visibility()
20931                    != minimap_settings.minimap_enabled()
20932                {
20933                    self.set_minimap_visibility(
20934                        MinimapVisibility::for_mode(self.mode(), cx),
20935                        window,
20936                        cx,
20937                    );
20938                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20939                    minimap_entity.update(cx, |minimap_editor, cx| {
20940                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20941                    })
20942                }
20943            }
20944        }
20945
20946        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20947            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20948        }) {
20949            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20950                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20951            }
20952            self.refresh_colors(false, None, window, cx);
20953        }
20954
20955        cx.notify();
20956    }
20957
20958    pub fn set_searchable(&mut self, searchable: bool) {
20959        self.searchable = searchable;
20960    }
20961
20962    pub fn searchable(&self) -> bool {
20963        self.searchable
20964    }
20965
20966    fn open_proposed_changes_editor(
20967        &mut self,
20968        _: &OpenProposedChangesEditor,
20969        window: &mut Window,
20970        cx: &mut Context<Self>,
20971    ) {
20972        let Some(workspace) = self.workspace() else {
20973            cx.propagate();
20974            return;
20975        };
20976
20977        let selections = self.selections.all::<usize>(cx);
20978        let multi_buffer = self.buffer.read(cx);
20979        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20980        let mut new_selections_by_buffer = HashMap::default();
20981        for selection in selections {
20982            for (buffer, range, _) in
20983                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20984            {
20985                let mut range = range.to_point(buffer);
20986                range.start.column = 0;
20987                range.end.column = buffer.line_len(range.end.row);
20988                new_selections_by_buffer
20989                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20990                    .or_insert(Vec::new())
20991                    .push(range)
20992            }
20993        }
20994
20995        let proposed_changes_buffers = new_selections_by_buffer
20996            .into_iter()
20997            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20998            .collect::<Vec<_>>();
20999        let proposed_changes_editor = cx.new(|cx| {
21000            ProposedChangesEditor::new(
21001                "Proposed changes",
21002                proposed_changes_buffers,
21003                self.project.clone(),
21004                window,
21005                cx,
21006            )
21007        });
21008
21009        window.defer(cx, move |window, cx| {
21010            workspace.update(cx, |workspace, cx| {
21011                workspace.active_pane().update(cx, |pane, cx| {
21012                    pane.add_item(
21013                        Box::new(proposed_changes_editor),
21014                        true,
21015                        true,
21016                        None,
21017                        window,
21018                        cx,
21019                    );
21020                });
21021            });
21022        });
21023    }
21024
21025    pub fn open_excerpts_in_split(
21026        &mut self,
21027        _: &OpenExcerptsSplit,
21028        window: &mut Window,
21029        cx: &mut Context<Self>,
21030    ) {
21031        self.open_excerpts_common(None, true, window, cx)
21032    }
21033
21034    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21035        self.open_excerpts_common(None, false, window, cx)
21036    }
21037
21038    fn open_excerpts_common(
21039        &mut self,
21040        jump_data: Option<JumpData>,
21041        split: bool,
21042        window: &mut Window,
21043        cx: &mut Context<Self>,
21044    ) {
21045        let Some(workspace) = self.workspace() else {
21046            cx.propagate();
21047            return;
21048        };
21049
21050        if self.buffer.read(cx).is_singleton() {
21051            cx.propagate();
21052            return;
21053        }
21054
21055        let mut new_selections_by_buffer = HashMap::default();
21056        match &jump_data {
21057            Some(JumpData::MultiBufferPoint {
21058                excerpt_id,
21059                position,
21060                anchor,
21061                line_offset_from_top,
21062            }) => {
21063                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21064                if let Some(buffer) = multi_buffer_snapshot
21065                    .buffer_id_for_excerpt(*excerpt_id)
21066                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21067                {
21068                    let buffer_snapshot = buffer.read(cx).snapshot();
21069                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21070                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21071                    } else {
21072                        buffer_snapshot.clip_point(*position, Bias::Left)
21073                    };
21074                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21075                    new_selections_by_buffer.insert(
21076                        buffer,
21077                        (
21078                            vec![jump_to_offset..jump_to_offset],
21079                            Some(*line_offset_from_top),
21080                        ),
21081                    );
21082                }
21083            }
21084            Some(JumpData::MultiBufferRow {
21085                row,
21086                line_offset_from_top,
21087            }) => {
21088                let point = MultiBufferPoint::new(row.0, 0);
21089                if let Some((buffer, buffer_point, _)) =
21090                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21091                {
21092                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21093                    new_selections_by_buffer
21094                        .entry(buffer)
21095                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21096                        .0
21097                        .push(buffer_offset..buffer_offset)
21098                }
21099            }
21100            None => {
21101                let selections = self.selections.all::<usize>(cx);
21102                let multi_buffer = self.buffer.read(cx);
21103                for selection in selections {
21104                    for (snapshot, range, _, anchor) in multi_buffer
21105                        .snapshot(cx)
21106                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21107                    {
21108                        if let Some(anchor) = anchor {
21109                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21110                            else {
21111                                continue;
21112                            };
21113                            let offset = text::ToOffset::to_offset(
21114                                &anchor.text_anchor,
21115                                &buffer_handle.read(cx).snapshot(),
21116                            );
21117                            let range = offset..offset;
21118                            new_selections_by_buffer
21119                                .entry(buffer_handle)
21120                                .or_insert((Vec::new(), None))
21121                                .0
21122                                .push(range)
21123                        } else {
21124                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21125                            else {
21126                                continue;
21127                            };
21128                            new_selections_by_buffer
21129                                .entry(buffer_handle)
21130                                .or_insert((Vec::new(), None))
21131                                .0
21132                                .push(range)
21133                        }
21134                    }
21135                }
21136            }
21137        }
21138
21139        new_selections_by_buffer
21140            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21141
21142        if new_selections_by_buffer.is_empty() {
21143            return;
21144        }
21145
21146        // We defer the pane interaction because we ourselves are a workspace item
21147        // and activating a new item causes the pane to call a method on us reentrantly,
21148        // which panics if we're on the stack.
21149        window.defer(cx, move |window, cx| {
21150            workspace.update(cx, |workspace, cx| {
21151                let pane = if split {
21152                    workspace.adjacent_pane(window, cx)
21153                } else {
21154                    workspace.active_pane().clone()
21155                };
21156
21157                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21158                    let editor = buffer
21159                        .read(cx)
21160                        .file()
21161                        .is_none()
21162                        .then(|| {
21163                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21164                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21165                            // Instead, we try to activate the existing editor in the pane first.
21166                            let (editor, pane_item_index) =
21167                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21168                                    let editor = item.downcast::<Editor>()?;
21169                                    let singleton_buffer =
21170                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21171                                    if singleton_buffer == buffer {
21172                                        Some((editor, i))
21173                                    } else {
21174                                        None
21175                                    }
21176                                })?;
21177                            pane.update(cx, |pane, cx| {
21178                                pane.activate_item(pane_item_index, true, true, window, cx)
21179                            });
21180                            Some(editor)
21181                        })
21182                        .flatten()
21183                        .unwrap_or_else(|| {
21184                            workspace.open_project_item::<Self>(
21185                                pane.clone(),
21186                                buffer,
21187                                true,
21188                                true,
21189                                window,
21190                                cx,
21191                            )
21192                        });
21193
21194                    editor.update(cx, |editor, cx| {
21195                        let autoscroll = match scroll_offset {
21196                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21197                            None => Autoscroll::newest(),
21198                        };
21199                        let nav_history = editor.nav_history.take();
21200                        editor.change_selections(
21201                            SelectionEffects::scroll(autoscroll),
21202                            window,
21203                            cx,
21204                            |s| {
21205                                s.select_ranges(ranges);
21206                            },
21207                        );
21208                        editor.nav_history = nav_history;
21209                    });
21210                }
21211            })
21212        });
21213    }
21214
21215    // For now, don't allow opening excerpts in buffers that aren't backed by
21216    // regular project files.
21217    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21218        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21219    }
21220
21221    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21222        let snapshot = self.buffer.read(cx).read(cx);
21223        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21224        Some(
21225            ranges
21226                .iter()
21227                .map(move |range| {
21228                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21229                })
21230                .collect(),
21231        )
21232    }
21233
21234    fn selection_replacement_ranges(
21235        &self,
21236        range: Range<OffsetUtf16>,
21237        cx: &mut App,
21238    ) -> Vec<Range<OffsetUtf16>> {
21239        let selections = self.selections.all::<OffsetUtf16>(cx);
21240        let newest_selection = selections
21241            .iter()
21242            .max_by_key(|selection| selection.id)
21243            .unwrap();
21244        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21245        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21246        let snapshot = self.buffer.read(cx).read(cx);
21247        selections
21248            .into_iter()
21249            .map(|mut selection| {
21250                selection.start.0 =
21251                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21252                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21253                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21254                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21255            })
21256            .collect()
21257    }
21258
21259    fn report_editor_event(
21260        &self,
21261        reported_event: ReportEditorEvent,
21262        file_extension: Option<String>,
21263        cx: &App,
21264    ) {
21265        if cfg!(any(test, feature = "test-support")) {
21266            return;
21267        }
21268
21269        let Some(project) = &self.project else { return };
21270
21271        // If None, we are in a file without an extension
21272        let file = self
21273            .buffer
21274            .read(cx)
21275            .as_singleton()
21276            .and_then(|b| b.read(cx).file());
21277        let file_extension = file_extension.or(file
21278            .as_ref()
21279            .and_then(|file| Path::new(file.file_name(cx)).extension())
21280            .and_then(|e| e.to_str())
21281            .map(|a| a.to_string()));
21282
21283        let vim_mode = vim_enabled(cx);
21284
21285        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21286        let copilot_enabled = edit_predictions_provider
21287            == language::language_settings::EditPredictionProvider::Copilot;
21288        let copilot_enabled_for_language = self
21289            .buffer
21290            .read(cx)
21291            .language_settings(cx)
21292            .show_edit_predictions;
21293
21294        let project = project.read(cx);
21295        let event_type = reported_event.event_type();
21296
21297        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21298            telemetry::event!(
21299                event_type,
21300                type = if auto_saved {"autosave"} else {"manual"},
21301                file_extension,
21302                vim_mode,
21303                copilot_enabled,
21304                copilot_enabled_for_language,
21305                edit_predictions_provider,
21306                is_via_ssh = project.is_via_remote_server(),
21307            );
21308        } else {
21309            telemetry::event!(
21310                event_type,
21311                file_extension,
21312                vim_mode,
21313                copilot_enabled,
21314                copilot_enabled_for_language,
21315                edit_predictions_provider,
21316                is_via_ssh = project.is_via_remote_server(),
21317            );
21318        };
21319    }
21320
21321    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21322    /// with each line being an array of {text, highlight} objects.
21323    fn copy_highlight_json(
21324        &mut self,
21325        _: &CopyHighlightJson,
21326        window: &mut Window,
21327        cx: &mut Context<Self>,
21328    ) {
21329        #[derive(Serialize)]
21330        struct Chunk<'a> {
21331            text: String,
21332            highlight: Option<&'a str>,
21333        }
21334
21335        let snapshot = self.buffer.read(cx).snapshot(cx);
21336        let range = self
21337            .selected_text_range(false, window, cx)
21338            .and_then(|selection| {
21339                if selection.range.is_empty() {
21340                    None
21341                } else {
21342                    Some(selection.range)
21343                }
21344            })
21345            .unwrap_or_else(|| 0..snapshot.len());
21346
21347        let chunks = snapshot.chunks(range, true);
21348        let mut lines = Vec::new();
21349        let mut line: VecDeque<Chunk> = VecDeque::new();
21350
21351        let Some(style) = self.style.as_ref() else {
21352            return;
21353        };
21354
21355        for chunk in chunks {
21356            let highlight = chunk
21357                .syntax_highlight_id
21358                .and_then(|id| id.name(&style.syntax));
21359            let mut chunk_lines = chunk.text.split('\n').peekable();
21360            while let Some(text) = chunk_lines.next() {
21361                let mut merged_with_last_token = false;
21362                if let Some(last_token) = line.back_mut()
21363                    && last_token.highlight == highlight
21364                {
21365                    last_token.text.push_str(text);
21366                    merged_with_last_token = true;
21367                }
21368
21369                if !merged_with_last_token {
21370                    line.push_back(Chunk {
21371                        text: text.into(),
21372                        highlight,
21373                    });
21374                }
21375
21376                if chunk_lines.peek().is_some() {
21377                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21378                        line.pop_front();
21379                    }
21380                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21381                        line.pop_back();
21382                    }
21383
21384                    lines.push(mem::take(&mut line));
21385                }
21386            }
21387        }
21388
21389        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21390            return;
21391        };
21392        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21393    }
21394
21395    pub fn open_context_menu(
21396        &mut self,
21397        _: &OpenContextMenu,
21398        window: &mut Window,
21399        cx: &mut Context<Self>,
21400    ) {
21401        self.request_autoscroll(Autoscroll::newest(), cx);
21402        let position = self.selections.newest_display(cx).start;
21403        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21404    }
21405
21406    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21407        &self.inlay_hint_cache
21408    }
21409
21410    pub fn replay_insert_event(
21411        &mut self,
21412        text: &str,
21413        relative_utf16_range: Option<Range<isize>>,
21414        window: &mut Window,
21415        cx: &mut Context<Self>,
21416    ) {
21417        if !self.input_enabled {
21418            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21419            return;
21420        }
21421        if let Some(relative_utf16_range) = relative_utf16_range {
21422            let selections = self.selections.all::<OffsetUtf16>(cx);
21423            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21424                let new_ranges = selections.into_iter().map(|range| {
21425                    let start = OffsetUtf16(
21426                        range
21427                            .head()
21428                            .0
21429                            .saturating_add_signed(relative_utf16_range.start),
21430                    );
21431                    let end = OffsetUtf16(
21432                        range
21433                            .head()
21434                            .0
21435                            .saturating_add_signed(relative_utf16_range.end),
21436                    );
21437                    start..end
21438                });
21439                s.select_ranges(new_ranges);
21440            });
21441        }
21442
21443        self.handle_input(text, window, cx);
21444    }
21445
21446    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21447        let Some(provider) = self.semantics_provider.as_ref() else {
21448            return false;
21449        };
21450
21451        let mut supports = false;
21452        self.buffer().update(cx, |this, cx| {
21453            this.for_each_buffer(|buffer| {
21454                supports |= provider.supports_inlay_hints(buffer, cx);
21455            });
21456        });
21457
21458        supports
21459    }
21460
21461    pub fn is_focused(&self, window: &Window) -> bool {
21462        self.focus_handle.is_focused(window)
21463    }
21464
21465    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21466        cx.emit(EditorEvent::Focused);
21467
21468        if let Some(descendant) = self
21469            .last_focused_descendant
21470            .take()
21471            .and_then(|descendant| descendant.upgrade())
21472        {
21473            window.focus(&descendant);
21474        } else {
21475            if let Some(blame) = self.blame.as_ref() {
21476                blame.update(cx, GitBlame::focus)
21477            }
21478
21479            self.blink_manager.update(cx, BlinkManager::enable);
21480            self.show_cursor_names(window, cx);
21481            self.buffer.update(cx, |buffer, cx| {
21482                buffer.finalize_last_transaction(cx);
21483                if self.leader_id.is_none() {
21484                    buffer.set_active_selections(
21485                        &self.selections.disjoint_anchors_arc(),
21486                        self.selections.line_mode(),
21487                        self.cursor_shape,
21488                        cx,
21489                    );
21490                }
21491            });
21492        }
21493    }
21494
21495    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21496        cx.emit(EditorEvent::FocusedIn)
21497    }
21498
21499    fn handle_focus_out(
21500        &mut self,
21501        event: FocusOutEvent,
21502        _window: &mut Window,
21503        cx: &mut Context<Self>,
21504    ) {
21505        if event.blurred != self.focus_handle {
21506            self.last_focused_descendant = Some(event.blurred);
21507        }
21508        self.selection_drag_state = SelectionDragState::None;
21509        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21510    }
21511
21512    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21513        self.blink_manager.update(cx, BlinkManager::disable);
21514        self.buffer
21515            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21516
21517        if let Some(blame) = self.blame.as_ref() {
21518            blame.update(cx, GitBlame::blur)
21519        }
21520        if !self.hover_state.focused(window, cx) {
21521            hide_hover(self, cx);
21522        }
21523        if !self
21524            .context_menu
21525            .borrow()
21526            .as_ref()
21527            .is_some_and(|context_menu| context_menu.focused(window, cx))
21528        {
21529            self.hide_context_menu(window, cx);
21530        }
21531        self.take_active_edit_prediction(cx);
21532        cx.emit(EditorEvent::Blurred);
21533        cx.notify();
21534    }
21535
21536    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21537        let mut pending: String = window
21538            .pending_input_keystrokes()
21539            .into_iter()
21540            .flatten()
21541            .filter_map(|keystroke| {
21542                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21543                    keystroke.key_char.clone()
21544                } else {
21545                    None
21546                }
21547            })
21548            .collect();
21549
21550        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21551            pending = "".to_string();
21552        }
21553
21554        let existing_pending = self
21555            .text_highlights::<PendingInput>(cx)
21556            .map(|(_, ranges)| ranges.to_vec());
21557        if existing_pending.is_none() && pending.is_empty() {
21558            return;
21559        }
21560        let transaction =
21561            self.transact(window, cx, |this, window, cx| {
21562                let selections = this.selections.all::<usize>(cx);
21563                let edits = selections
21564                    .iter()
21565                    .map(|selection| (selection.end..selection.end, pending.clone()));
21566                this.edit(edits, cx);
21567                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21568                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21569                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21570                    }));
21571                });
21572                if let Some(existing_ranges) = existing_pending {
21573                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21574                    this.edit(edits, cx);
21575                }
21576            });
21577
21578        let snapshot = self.snapshot(window, cx);
21579        let ranges = self
21580            .selections
21581            .all::<usize>(cx)
21582            .into_iter()
21583            .map(|selection| {
21584                snapshot.buffer_snapshot.anchor_after(selection.end)
21585                    ..snapshot
21586                        .buffer_snapshot
21587                        .anchor_before(selection.end + pending.len())
21588            })
21589            .collect();
21590
21591        if pending.is_empty() {
21592            self.clear_highlights::<PendingInput>(cx);
21593        } else {
21594            self.highlight_text::<PendingInput>(
21595                ranges,
21596                HighlightStyle {
21597                    underline: Some(UnderlineStyle {
21598                        thickness: px(1.),
21599                        color: None,
21600                        wavy: false,
21601                    }),
21602                    ..Default::default()
21603                },
21604                cx,
21605            );
21606        }
21607
21608        self.ime_transaction = self.ime_transaction.or(transaction);
21609        if let Some(transaction) = self.ime_transaction {
21610            self.buffer.update(cx, |buffer, cx| {
21611                buffer.group_until_transaction(transaction, cx);
21612            });
21613        }
21614
21615        if self.text_highlights::<PendingInput>(cx).is_none() {
21616            self.ime_transaction.take();
21617        }
21618    }
21619
21620    pub fn register_action_renderer(
21621        &mut self,
21622        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21623    ) -> Subscription {
21624        let id = self.next_editor_action_id.post_inc();
21625        self.editor_actions
21626            .borrow_mut()
21627            .insert(id, Box::new(listener));
21628
21629        let editor_actions = self.editor_actions.clone();
21630        Subscription::new(move || {
21631            editor_actions.borrow_mut().remove(&id);
21632        })
21633    }
21634
21635    pub fn register_action<A: Action>(
21636        &mut self,
21637        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21638    ) -> Subscription {
21639        let id = self.next_editor_action_id.post_inc();
21640        let listener = Arc::new(listener);
21641        self.editor_actions.borrow_mut().insert(
21642            id,
21643            Box::new(move |_, window, _| {
21644                let listener = listener.clone();
21645                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21646                    let action = action.downcast_ref().unwrap();
21647                    if phase == DispatchPhase::Bubble {
21648                        listener(action, window, cx)
21649                    }
21650                })
21651            }),
21652        );
21653
21654        let editor_actions = self.editor_actions.clone();
21655        Subscription::new(move || {
21656            editor_actions.borrow_mut().remove(&id);
21657        })
21658    }
21659
21660    pub fn file_header_size(&self) -> u32 {
21661        FILE_HEADER_HEIGHT
21662    }
21663
21664    pub fn restore(
21665        &mut self,
21666        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21667        window: &mut Window,
21668        cx: &mut Context<Self>,
21669    ) {
21670        let workspace = self.workspace();
21671        let project = self.project();
21672        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21673            let mut tasks = Vec::new();
21674            for (buffer_id, changes) in revert_changes {
21675                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21676                    buffer.update(cx, |buffer, cx| {
21677                        buffer.edit(
21678                            changes
21679                                .into_iter()
21680                                .map(|(range, text)| (range, text.to_string())),
21681                            None,
21682                            cx,
21683                        );
21684                    });
21685
21686                    if let Some(project) =
21687                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21688                    {
21689                        project.update(cx, |project, cx| {
21690                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21691                        })
21692                    }
21693                }
21694            }
21695            tasks
21696        });
21697        cx.spawn_in(window, async move |_, cx| {
21698            for (buffer, task) in save_tasks {
21699                let result = task.await;
21700                if result.is_err() {
21701                    let Some(path) = buffer
21702                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21703                        .ok()
21704                    else {
21705                        continue;
21706                    };
21707                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21708                        let Some(task) = cx
21709                            .update_window_entity(workspace, |workspace, window, cx| {
21710                                workspace
21711                                    .open_path_preview(path, None, false, false, false, window, cx)
21712                            })
21713                            .ok()
21714                        else {
21715                            continue;
21716                        };
21717                        task.await.log_err();
21718                    }
21719                }
21720            }
21721        })
21722        .detach();
21723        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21724            selections.refresh()
21725        });
21726    }
21727
21728    pub fn to_pixel_point(
21729        &self,
21730        source: multi_buffer::Anchor,
21731        editor_snapshot: &EditorSnapshot,
21732        window: &mut Window,
21733    ) -> Option<gpui::Point<Pixels>> {
21734        let source_point = source.to_display_point(editor_snapshot);
21735        self.display_to_pixel_point(source_point, editor_snapshot, window)
21736    }
21737
21738    pub fn display_to_pixel_point(
21739        &self,
21740        source: DisplayPoint,
21741        editor_snapshot: &EditorSnapshot,
21742        window: &mut Window,
21743    ) -> Option<gpui::Point<Pixels>> {
21744        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21745        let text_layout_details = self.text_layout_details(window);
21746        let scroll_top = text_layout_details
21747            .scroll_anchor
21748            .scroll_position(editor_snapshot)
21749            .y;
21750
21751        if source.row().as_f64() < scroll_top.floor() {
21752            return None;
21753        }
21754        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21755        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21756        Some(gpui::Point::new(source_x, source_y))
21757    }
21758
21759    pub fn has_visible_completions_menu(&self) -> bool {
21760        !self.edit_prediction_preview_is_active()
21761            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21762                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21763            })
21764    }
21765
21766    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21767        if self.mode.is_minimap() {
21768            return;
21769        }
21770        self.addons
21771            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21772    }
21773
21774    pub fn unregister_addon<T: Addon>(&mut self) {
21775        self.addons.remove(&std::any::TypeId::of::<T>());
21776    }
21777
21778    pub fn addon<T: Addon>(&self) -> Option<&T> {
21779        let type_id = std::any::TypeId::of::<T>();
21780        self.addons
21781            .get(&type_id)
21782            .and_then(|item| item.to_any().downcast_ref::<T>())
21783    }
21784
21785    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21786        let type_id = std::any::TypeId::of::<T>();
21787        self.addons
21788            .get_mut(&type_id)
21789            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21790    }
21791
21792    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21793        let text_layout_details = self.text_layout_details(window);
21794        let style = &text_layout_details.editor_style;
21795        let font_id = window.text_system().resolve_font(&style.text.font());
21796        let font_size = style.text.font_size.to_pixels(window.rem_size());
21797        let line_height = style.text.line_height_in_pixels(window.rem_size());
21798        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21799        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21800
21801        CharacterDimensions {
21802            em_width,
21803            em_advance,
21804            line_height,
21805        }
21806    }
21807
21808    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21809        self.load_diff_task.clone()
21810    }
21811
21812    fn read_metadata_from_db(
21813        &mut self,
21814        item_id: u64,
21815        workspace_id: WorkspaceId,
21816        window: &mut Window,
21817        cx: &mut Context<Editor>,
21818    ) {
21819        if self.is_singleton(cx)
21820            && !self.mode.is_minimap()
21821            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21822        {
21823            let buffer_snapshot = OnceCell::new();
21824
21825            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21826                && !folds.is_empty()
21827            {
21828                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21829                self.fold_ranges(
21830                    folds
21831                        .into_iter()
21832                        .map(|(start, end)| {
21833                            snapshot.clip_offset(start, Bias::Left)
21834                                ..snapshot.clip_offset(end, Bias::Right)
21835                        })
21836                        .collect(),
21837                    false,
21838                    window,
21839                    cx,
21840                );
21841            }
21842
21843            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21844                && !selections.is_empty()
21845            {
21846                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21847                // skip adding the initial selection to selection history
21848                self.selection_history.mode = SelectionHistoryMode::Skipping;
21849                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21850                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21851                        snapshot.clip_offset(start, Bias::Left)
21852                            ..snapshot.clip_offset(end, Bias::Right)
21853                    }));
21854                });
21855                self.selection_history.mode = SelectionHistoryMode::Normal;
21856            };
21857        }
21858
21859        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21860    }
21861
21862    fn update_lsp_data(
21863        &mut self,
21864        ignore_cache: bool,
21865        for_buffer: Option<BufferId>,
21866        window: &mut Window,
21867        cx: &mut Context<'_, Self>,
21868    ) {
21869        self.pull_diagnostics(for_buffer, window, cx);
21870        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21871    }
21872}
21873
21874fn edit_for_markdown_paste<'a>(
21875    buffer: &MultiBufferSnapshot,
21876    range: Range<usize>,
21877    to_insert: &'a str,
21878    url: Option<url::Url>,
21879) -> (Range<usize>, Cow<'a, str>) {
21880    if url.is_none() {
21881        return (range, Cow::Borrowed(to_insert));
21882    };
21883
21884    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21885
21886    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21887        Cow::Borrowed(to_insert)
21888    } else {
21889        Cow::Owned(format!("[{old_text}]({to_insert})"))
21890    };
21891    (range, new_text)
21892}
21893
21894fn vim_enabled(cx: &App) -> bool {
21895    vim_mode_setting::VimModeSetting::try_get(cx)
21896        .map(|vim_mode| vim_mode.0)
21897        .unwrap_or(false)
21898}
21899
21900fn process_completion_for_edit(
21901    completion: &Completion,
21902    intent: CompletionIntent,
21903    buffer: &Entity<Buffer>,
21904    cursor_position: &text::Anchor,
21905    cx: &mut Context<Editor>,
21906) -> CompletionEdit {
21907    let buffer = buffer.read(cx);
21908    let buffer_snapshot = buffer.snapshot();
21909    let (snippet, new_text) = if completion.is_snippet() {
21910        // Workaround for typescript language server issues so that methods don't expand within
21911        // strings and functions with type expressions. The previous point is used because the query
21912        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21913        let mut snippet_source = completion.new_text.clone();
21914        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21915        previous_point.column = previous_point.column.saturating_sub(1);
21916        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21917            && scope.prefers_label_for_snippet_in_completion()
21918            && let Some(label) = completion.label()
21919            && matches!(
21920                completion.kind(),
21921                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21922            )
21923        {
21924            snippet_source = label;
21925        }
21926        match Snippet::parse(&snippet_source).log_err() {
21927            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21928            None => (None, completion.new_text.clone()),
21929        }
21930    } else {
21931        (None, completion.new_text.clone())
21932    };
21933
21934    let mut range_to_replace = {
21935        let replace_range = &completion.replace_range;
21936        if let CompletionSource::Lsp {
21937            insert_range: Some(insert_range),
21938            ..
21939        } = &completion.source
21940        {
21941            debug_assert_eq!(
21942                insert_range.start, replace_range.start,
21943                "insert_range and replace_range should start at the same position"
21944            );
21945            debug_assert!(
21946                insert_range
21947                    .start
21948                    .cmp(cursor_position, &buffer_snapshot)
21949                    .is_le(),
21950                "insert_range should start before or at cursor position"
21951            );
21952            debug_assert!(
21953                replace_range
21954                    .start
21955                    .cmp(cursor_position, &buffer_snapshot)
21956                    .is_le(),
21957                "replace_range should start before or at cursor position"
21958            );
21959
21960            let should_replace = match intent {
21961                CompletionIntent::CompleteWithInsert => false,
21962                CompletionIntent::CompleteWithReplace => true,
21963                CompletionIntent::Complete | CompletionIntent::Compose => {
21964                    let insert_mode =
21965                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21966                            .completions
21967                            .lsp_insert_mode;
21968                    match insert_mode {
21969                        LspInsertMode::Insert => false,
21970                        LspInsertMode::Replace => true,
21971                        LspInsertMode::ReplaceSubsequence => {
21972                            let mut text_to_replace = buffer.chars_for_range(
21973                                buffer.anchor_before(replace_range.start)
21974                                    ..buffer.anchor_after(replace_range.end),
21975                            );
21976                            let mut current_needle = text_to_replace.next();
21977                            for haystack_ch in completion.label.text.chars() {
21978                                if let Some(needle_ch) = current_needle
21979                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21980                                {
21981                                    current_needle = text_to_replace.next();
21982                                }
21983                            }
21984                            current_needle.is_none()
21985                        }
21986                        LspInsertMode::ReplaceSuffix => {
21987                            if replace_range
21988                                .end
21989                                .cmp(cursor_position, &buffer_snapshot)
21990                                .is_gt()
21991                            {
21992                                let range_after_cursor = *cursor_position..replace_range.end;
21993                                let text_after_cursor = buffer
21994                                    .text_for_range(
21995                                        buffer.anchor_before(range_after_cursor.start)
21996                                            ..buffer.anchor_after(range_after_cursor.end),
21997                                    )
21998                                    .collect::<String>()
21999                                    .to_ascii_lowercase();
22000                                completion
22001                                    .label
22002                                    .text
22003                                    .to_ascii_lowercase()
22004                                    .ends_with(&text_after_cursor)
22005                            } else {
22006                                true
22007                            }
22008                        }
22009                    }
22010                }
22011            };
22012
22013            if should_replace {
22014                replace_range.clone()
22015            } else {
22016                insert_range.clone()
22017            }
22018        } else {
22019            replace_range.clone()
22020        }
22021    };
22022
22023    if range_to_replace
22024        .end
22025        .cmp(cursor_position, &buffer_snapshot)
22026        .is_lt()
22027    {
22028        range_to_replace.end = *cursor_position;
22029    }
22030
22031    CompletionEdit {
22032        new_text,
22033        replace_range: range_to_replace.to_offset(buffer),
22034        snippet,
22035    }
22036}
22037
22038struct CompletionEdit {
22039    new_text: String,
22040    replace_range: Range<usize>,
22041    snippet: Option<Snippet>,
22042}
22043
22044fn insert_extra_newline_brackets(
22045    buffer: &MultiBufferSnapshot,
22046    range: Range<usize>,
22047    language: &language::LanguageScope,
22048) -> bool {
22049    let leading_whitespace_len = buffer
22050        .reversed_chars_at(range.start)
22051        .take_while(|c| c.is_whitespace() && *c != '\n')
22052        .map(|c| c.len_utf8())
22053        .sum::<usize>();
22054    let trailing_whitespace_len = buffer
22055        .chars_at(range.end)
22056        .take_while(|c| c.is_whitespace() && *c != '\n')
22057        .map(|c| c.len_utf8())
22058        .sum::<usize>();
22059    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22060
22061    language.brackets().any(|(pair, enabled)| {
22062        let pair_start = pair.start.trim_end();
22063        let pair_end = pair.end.trim_start();
22064
22065        enabled
22066            && pair.newline
22067            && buffer.contains_str_at(range.end, pair_end)
22068            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22069    })
22070}
22071
22072fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22073    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22074        [(buffer, range, _)] => (*buffer, range.clone()),
22075        _ => return false,
22076    };
22077    let pair = {
22078        let mut result: Option<BracketMatch> = None;
22079
22080        for pair in buffer
22081            .all_bracket_ranges(range.clone())
22082            .filter(move |pair| {
22083                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22084            })
22085        {
22086            let len = pair.close_range.end - pair.open_range.start;
22087
22088            if let Some(existing) = &result {
22089                let existing_len = existing.close_range.end - existing.open_range.start;
22090                if len > existing_len {
22091                    continue;
22092                }
22093            }
22094
22095            result = Some(pair);
22096        }
22097
22098        result
22099    };
22100    let Some(pair) = pair else {
22101        return false;
22102    };
22103    pair.newline_only
22104        && buffer
22105            .chars_for_range(pair.open_range.end..range.start)
22106            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22107            .all(|c| c.is_whitespace() && c != '\n')
22108}
22109
22110fn update_uncommitted_diff_for_buffer(
22111    editor: Entity<Editor>,
22112    project: &Entity<Project>,
22113    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22114    buffer: Entity<MultiBuffer>,
22115    cx: &mut App,
22116) -> Task<()> {
22117    let mut tasks = Vec::new();
22118    project.update(cx, |project, cx| {
22119        for buffer in buffers {
22120            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22121                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22122            }
22123        }
22124    });
22125    cx.spawn(async move |cx| {
22126        let diffs = future::join_all(tasks).await;
22127        if editor
22128            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22129            .unwrap_or(false)
22130        {
22131            return;
22132        }
22133
22134        buffer
22135            .update(cx, |buffer, cx| {
22136                for diff in diffs.into_iter().flatten() {
22137                    buffer.add_diff(diff, cx);
22138                }
22139            })
22140            .ok();
22141    })
22142}
22143
22144fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22145    let tab_size = tab_size.get() as usize;
22146    let mut width = offset;
22147
22148    for ch in text.chars() {
22149        width += if ch == '\t' {
22150            tab_size - (width % tab_size)
22151        } else {
22152            1
22153        };
22154    }
22155
22156    width - offset
22157}
22158
22159#[cfg(test)]
22160mod tests {
22161    use super::*;
22162
22163    #[test]
22164    fn test_string_size_with_expanded_tabs() {
22165        let nz = |val| NonZeroU32::new(val).unwrap();
22166        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22167        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22168        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22169        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22170        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22171        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22172        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22173        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22174    }
22175}
22176
22177/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22178struct WordBreakingTokenizer<'a> {
22179    input: &'a str,
22180}
22181
22182impl<'a> WordBreakingTokenizer<'a> {
22183    fn new(input: &'a str) -> Self {
22184        Self { input }
22185    }
22186}
22187
22188fn is_char_ideographic(ch: char) -> bool {
22189    use unicode_script::Script::*;
22190    use unicode_script::UnicodeScript;
22191    matches!(ch.script(), Han | Tangut | Yi)
22192}
22193
22194fn is_grapheme_ideographic(text: &str) -> bool {
22195    text.chars().any(is_char_ideographic)
22196}
22197
22198fn is_grapheme_whitespace(text: &str) -> bool {
22199    text.chars().any(|x| x.is_whitespace())
22200}
22201
22202fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22203    text.chars()
22204        .next()
22205        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22206}
22207
22208#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22209enum WordBreakToken<'a> {
22210    Word { token: &'a str, grapheme_len: usize },
22211    InlineWhitespace { token: &'a str, grapheme_len: usize },
22212    Newline,
22213}
22214
22215impl<'a> Iterator for WordBreakingTokenizer<'a> {
22216    /// Yields a span, the count of graphemes in the token, and whether it was
22217    /// whitespace. Note that it also breaks at word boundaries.
22218    type Item = WordBreakToken<'a>;
22219
22220    fn next(&mut self) -> Option<Self::Item> {
22221        use unicode_segmentation::UnicodeSegmentation;
22222        if self.input.is_empty() {
22223            return None;
22224        }
22225
22226        let mut iter = self.input.graphemes(true).peekable();
22227        let mut offset = 0;
22228        let mut grapheme_len = 0;
22229        if let Some(first_grapheme) = iter.next() {
22230            let is_newline = first_grapheme == "\n";
22231            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22232            offset += first_grapheme.len();
22233            grapheme_len += 1;
22234            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22235                if let Some(grapheme) = iter.peek().copied()
22236                    && should_stay_with_preceding_ideograph(grapheme)
22237                {
22238                    offset += grapheme.len();
22239                    grapheme_len += 1;
22240                }
22241            } else {
22242                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22243                let mut next_word_bound = words.peek().copied();
22244                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22245                    next_word_bound = words.next();
22246                }
22247                while let Some(grapheme) = iter.peek().copied() {
22248                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22249                        break;
22250                    };
22251                    if is_grapheme_whitespace(grapheme) != is_whitespace
22252                        || (grapheme == "\n") != is_newline
22253                    {
22254                        break;
22255                    };
22256                    offset += grapheme.len();
22257                    grapheme_len += 1;
22258                    iter.next();
22259                }
22260            }
22261            let token = &self.input[..offset];
22262            self.input = &self.input[offset..];
22263            if token == "\n" {
22264                Some(WordBreakToken::Newline)
22265            } else if is_whitespace {
22266                Some(WordBreakToken::InlineWhitespace {
22267                    token,
22268                    grapheme_len,
22269                })
22270            } else {
22271                Some(WordBreakToken::Word {
22272                    token,
22273                    grapheme_len,
22274                })
22275            }
22276        } else {
22277            None
22278        }
22279    }
22280}
22281
22282#[test]
22283fn test_word_breaking_tokenizer() {
22284    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22285        ("", &[]),
22286        ("  ", &[whitespace("  ", 2)]),
22287        ("Ʒ", &[word("Ʒ", 1)]),
22288        ("Ǽ", &[word("Ǽ", 1)]),
22289        ("", &[word("", 1)]),
22290        ("⋑⋑", &[word("⋑⋑", 2)]),
22291        (
22292            "原理,进而",
22293            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22294        ),
22295        (
22296            "hello world",
22297            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22298        ),
22299        (
22300            "hello, world",
22301            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22302        ),
22303        (
22304            "  hello world",
22305            &[
22306                whitespace("  ", 2),
22307                word("hello", 5),
22308                whitespace(" ", 1),
22309                word("world", 5),
22310            ],
22311        ),
22312        (
22313            "这是什么 \n 钢笔",
22314            &[
22315                word("", 1),
22316                word("", 1),
22317                word("", 1),
22318                word("", 1),
22319                whitespace(" ", 1),
22320                newline(),
22321                whitespace(" ", 1),
22322                word("", 1),
22323                word("", 1),
22324            ],
22325        ),
22326        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22327    ];
22328
22329    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22330        WordBreakToken::Word {
22331            token,
22332            grapheme_len,
22333        }
22334    }
22335
22336    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22337        WordBreakToken::InlineWhitespace {
22338            token,
22339            grapheme_len,
22340        }
22341    }
22342
22343    fn newline() -> WordBreakToken<'static> {
22344        WordBreakToken::Newline
22345    }
22346
22347    for (input, result) in tests {
22348        assert_eq!(
22349            WordBreakingTokenizer::new(input)
22350                .collect::<Vec<_>>()
22351                .as_slice(),
22352            *result,
22353        );
22354    }
22355}
22356
22357fn wrap_with_prefix(
22358    first_line_prefix: String,
22359    subsequent_lines_prefix: String,
22360    unwrapped_text: String,
22361    wrap_column: usize,
22362    tab_size: NonZeroU32,
22363    preserve_existing_whitespace: bool,
22364) -> String {
22365    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22366    let subsequent_lines_prefix_len =
22367        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22368    let mut wrapped_text = String::new();
22369    let mut current_line = first_line_prefix;
22370    let mut is_first_line = true;
22371
22372    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22373    let mut current_line_len = first_line_prefix_len;
22374    let mut in_whitespace = false;
22375    for token in tokenizer {
22376        let have_preceding_whitespace = in_whitespace;
22377        match token {
22378            WordBreakToken::Word {
22379                token,
22380                grapheme_len,
22381            } => {
22382                in_whitespace = false;
22383                let current_prefix_len = if is_first_line {
22384                    first_line_prefix_len
22385                } else {
22386                    subsequent_lines_prefix_len
22387                };
22388                if current_line_len + grapheme_len > wrap_column
22389                    && current_line_len != current_prefix_len
22390                {
22391                    wrapped_text.push_str(current_line.trim_end());
22392                    wrapped_text.push('\n');
22393                    is_first_line = false;
22394                    current_line = subsequent_lines_prefix.clone();
22395                    current_line_len = subsequent_lines_prefix_len;
22396                }
22397                current_line.push_str(token);
22398                current_line_len += grapheme_len;
22399            }
22400            WordBreakToken::InlineWhitespace {
22401                mut token,
22402                mut grapheme_len,
22403            } => {
22404                in_whitespace = true;
22405                if have_preceding_whitespace && !preserve_existing_whitespace {
22406                    continue;
22407                }
22408                if !preserve_existing_whitespace {
22409                    // Keep a single whitespace grapheme as-is
22410                    if let Some(first) =
22411                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22412                    {
22413                        token = first;
22414                    } else {
22415                        token = " ";
22416                    }
22417                    grapheme_len = 1;
22418                }
22419                let current_prefix_len = if is_first_line {
22420                    first_line_prefix_len
22421                } else {
22422                    subsequent_lines_prefix_len
22423                };
22424                if current_line_len + grapheme_len > wrap_column {
22425                    wrapped_text.push_str(current_line.trim_end());
22426                    wrapped_text.push('\n');
22427                    is_first_line = false;
22428                    current_line = subsequent_lines_prefix.clone();
22429                    current_line_len = subsequent_lines_prefix_len;
22430                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22431                    current_line.push_str(token);
22432                    current_line_len += grapheme_len;
22433                }
22434            }
22435            WordBreakToken::Newline => {
22436                in_whitespace = true;
22437                let current_prefix_len = if is_first_line {
22438                    first_line_prefix_len
22439                } else {
22440                    subsequent_lines_prefix_len
22441                };
22442                if preserve_existing_whitespace {
22443                    wrapped_text.push_str(current_line.trim_end());
22444                    wrapped_text.push('\n');
22445                    is_first_line = false;
22446                    current_line = subsequent_lines_prefix.clone();
22447                    current_line_len = subsequent_lines_prefix_len;
22448                } else if have_preceding_whitespace {
22449                    continue;
22450                } else if current_line_len + 1 > wrap_column
22451                    && current_line_len != current_prefix_len
22452                {
22453                    wrapped_text.push_str(current_line.trim_end());
22454                    wrapped_text.push('\n');
22455                    is_first_line = false;
22456                    current_line = subsequent_lines_prefix.clone();
22457                    current_line_len = subsequent_lines_prefix_len;
22458                } else if current_line_len != current_prefix_len {
22459                    current_line.push(' ');
22460                    current_line_len += 1;
22461                }
22462            }
22463        }
22464    }
22465
22466    if !current_line.is_empty() {
22467        wrapped_text.push_str(&current_line);
22468    }
22469    wrapped_text
22470}
22471
22472#[test]
22473fn test_wrap_with_prefix() {
22474    assert_eq!(
22475        wrap_with_prefix(
22476            "# ".to_string(),
22477            "# ".to_string(),
22478            "abcdefg".to_string(),
22479            4,
22480            NonZeroU32::new(4).unwrap(),
22481            false,
22482        ),
22483        "# abcdefg"
22484    );
22485    assert_eq!(
22486        wrap_with_prefix(
22487            "".to_string(),
22488            "".to_string(),
22489            "\thello world".to_string(),
22490            8,
22491            NonZeroU32::new(4).unwrap(),
22492            false,
22493        ),
22494        "hello\nworld"
22495    );
22496    assert_eq!(
22497        wrap_with_prefix(
22498            "// ".to_string(),
22499            "// ".to_string(),
22500            "xx \nyy zz aa bb cc".to_string(),
22501            12,
22502            NonZeroU32::new(4).unwrap(),
22503            false,
22504        ),
22505        "// xx yy zz\n// aa bb cc"
22506    );
22507    assert_eq!(
22508        wrap_with_prefix(
22509            String::new(),
22510            String::new(),
22511            "这是什么 \n 钢笔".to_string(),
22512            3,
22513            NonZeroU32::new(4).unwrap(),
22514            false,
22515        ),
22516        "这是什\n么 钢\n"
22517    );
22518    assert_eq!(
22519        wrap_with_prefix(
22520            String::new(),
22521            String::new(),
22522            format!("foo{}bar", '\u{2009}'), // thin space
22523            80,
22524            NonZeroU32::new(4).unwrap(),
22525            false,
22526        ),
22527        format!("foo{}bar", '\u{2009}')
22528    );
22529}
22530
22531pub trait CollaborationHub {
22532    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22533    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22534    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22535}
22536
22537impl CollaborationHub for Entity<Project> {
22538    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22539        self.read(cx).collaborators()
22540    }
22541
22542    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22543        self.read(cx).user_store().read(cx).participant_indices()
22544    }
22545
22546    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22547        let this = self.read(cx);
22548        let user_ids = this.collaborators().values().map(|c| c.user_id);
22549        this.user_store().read(cx).participant_names(user_ids, cx)
22550    }
22551}
22552
22553pub trait SemanticsProvider {
22554    fn hover(
22555        &self,
22556        buffer: &Entity<Buffer>,
22557        position: text::Anchor,
22558        cx: &mut App,
22559    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22560
22561    fn inline_values(
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 inlay_hints(
22569        &self,
22570        buffer_handle: Entity<Buffer>,
22571        range: Range<text::Anchor>,
22572        cx: &mut App,
22573    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22574
22575    fn resolve_inlay_hint(
22576        &self,
22577        hint: InlayHint,
22578        buffer_handle: Entity<Buffer>,
22579        server_id: LanguageServerId,
22580        cx: &mut App,
22581    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22582
22583    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22584
22585    fn document_highlights(
22586        &self,
22587        buffer: &Entity<Buffer>,
22588        position: text::Anchor,
22589        cx: &mut App,
22590    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22591
22592    fn definitions(
22593        &self,
22594        buffer: &Entity<Buffer>,
22595        position: text::Anchor,
22596        kind: GotoDefinitionKind,
22597        cx: &mut App,
22598    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22599
22600    fn range_for_rename(
22601        &self,
22602        buffer: &Entity<Buffer>,
22603        position: text::Anchor,
22604        cx: &mut App,
22605    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22606
22607    fn perform_rename(
22608        &self,
22609        buffer: &Entity<Buffer>,
22610        position: text::Anchor,
22611        new_name: String,
22612        cx: &mut App,
22613    ) -> Option<Task<Result<ProjectTransaction>>>;
22614}
22615
22616pub trait CompletionProvider {
22617    fn completions(
22618        &self,
22619        excerpt_id: ExcerptId,
22620        buffer: &Entity<Buffer>,
22621        buffer_position: text::Anchor,
22622        trigger: CompletionContext,
22623        window: &mut Window,
22624        cx: &mut Context<Editor>,
22625    ) -> Task<Result<Vec<CompletionResponse>>>;
22626
22627    fn resolve_completions(
22628        &self,
22629        _buffer: Entity<Buffer>,
22630        _completion_indices: Vec<usize>,
22631        _completions: Rc<RefCell<Box<[Completion]>>>,
22632        _cx: &mut Context<Editor>,
22633    ) -> Task<Result<bool>> {
22634        Task::ready(Ok(false))
22635    }
22636
22637    fn apply_additional_edits_for_completion(
22638        &self,
22639        _buffer: Entity<Buffer>,
22640        _completions: Rc<RefCell<Box<[Completion]>>>,
22641        _completion_index: usize,
22642        _push_to_history: bool,
22643        _cx: &mut Context<Editor>,
22644    ) -> Task<Result<Option<language::Transaction>>> {
22645        Task::ready(Ok(None))
22646    }
22647
22648    fn is_completion_trigger(
22649        &self,
22650        buffer: &Entity<Buffer>,
22651        position: language::Anchor,
22652        text: &str,
22653        trigger_in_words: bool,
22654        menu_is_open: bool,
22655        cx: &mut Context<Editor>,
22656    ) -> bool;
22657
22658    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22659
22660    fn sort_completions(&self) -> bool {
22661        true
22662    }
22663
22664    fn filter_completions(&self) -> bool {
22665        true
22666    }
22667}
22668
22669pub trait CodeActionProvider {
22670    fn id(&self) -> Arc<str>;
22671
22672    fn code_actions(
22673        &self,
22674        buffer: &Entity<Buffer>,
22675        range: Range<text::Anchor>,
22676        window: &mut Window,
22677        cx: &mut App,
22678    ) -> Task<Result<Vec<CodeAction>>>;
22679
22680    fn apply_code_action(
22681        &self,
22682        buffer_handle: Entity<Buffer>,
22683        action: CodeAction,
22684        excerpt_id: ExcerptId,
22685        push_to_history: bool,
22686        window: &mut Window,
22687        cx: &mut App,
22688    ) -> Task<Result<ProjectTransaction>>;
22689}
22690
22691impl CodeActionProvider for Entity<Project> {
22692    fn id(&self) -> Arc<str> {
22693        "project".into()
22694    }
22695
22696    fn code_actions(
22697        &self,
22698        buffer: &Entity<Buffer>,
22699        range: Range<text::Anchor>,
22700        _window: &mut Window,
22701        cx: &mut App,
22702    ) -> Task<Result<Vec<CodeAction>>> {
22703        self.update(cx, |project, cx| {
22704            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22705            let code_actions = project.code_actions(buffer, range, None, cx);
22706            cx.background_spawn(async move {
22707                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22708                Ok(code_lens_actions
22709                    .context("code lens fetch")?
22710                    .into_iter()
22711                    .flatten()
22712                    .chain(
22713                        code_actions
22714                            .context("code action fetch")?
22715                            .into_iter()
22716                            .flatten(),
22717                    )
22718                    .collect())
22719            })
22720        })
22721    }
22722
22723    fn apply_code_action(
22724        &self,
22725        buffer_handle: Entity<Buffer>,
22726        action: CodeAction,
22727        _excerpt_id: ExcerptId,
22728        push_to_history: bool,
22729        _window: &mut Window,
22730        cx: &mut App,
22731    ) -> Task<Result<ProjectTransaction>> {
22732        self.update(cx, |project, cx| {
22733            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22734        })
22735    }
22736}
22737
22738fn snippet_completions(
22739    project: &Project,
22740    buffer: &Entity<Buffer>,
22741    buffer_position: text::Anchor,
22742    cx: &mut App,
22743) -> Task<Result<CompletionResponse>> {
22744    let languages = buffer.read(cx).languages_at(buffer_position);
22745    let snippet_store = project.snippets().read(cx);
22746
22747    let scopes: Vec<_> = languages
22748        .iter()
22749        .filter_map(|language| {
22750            let language_name = language.lsp_id();
22751            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22752
22753            if snippets.is_empty() {
22754                None
22755            } else {
22756                Some((language.default_scope(), snippets))
22757            }
22758        })
22759        .collect();
22760
22761    if scopes.is_empty() {
22762        return Task::ready(Ok(CompletionResponse {
22763            completions: vec![],
22764            display_options: CompletionDisplayOptions::default(),
22765            is_incomplete: false,
22766        }));
22767    }
22768
22769    let snapshot = buffer.read(cx).text_snapshot();
22770    let chars: String = snapshot
22771        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22772        .collect();
22773    let executor = cx.background_executor().clone();
22774
22775    cx.background_spawn(async move {
22776        let mut is_incomplete = false;
22777        let mut completions: Vec<Completion> = Vec::new();
22778        for (scope, snippets) in scopes.into_iter() {
22779            let classifier =
22780                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22781            let mut last_word = chars
22782                .chars()
22783                .take_while(|c| classifier.is_word(*c))
22784                .collect::<String>();
22785            last_word = last_word.chars().rev().collect();
22786
22787            if last_word.is_empty() {
22788                return Ok(CompletionResponse {
22789                    completions: vec![],
22790                    display_options: CompletionDisplayOptions::default(),
22791                    is_incomplete: true,
22792                });
22793            }
22794
22795            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22796            let to_lsp = |point: &text::Anchor| {
22797                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22798                point_to_lsp(end)
22799            };
22800            let lsp_end = to_lsp(&buffer_position);
22801
22802            let candidates = snippets
22803                .iter()
22804                .enumerate()
22805                .flat_map(|(ix, snippet)| {
22806                    snippet
22807                        .prefix
22808                        .iter()
22809                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22810                })
22811                .collect::<Vec<StringMatchCandidate>>();
22812
22813            const MAX_RESULTS: usize = 100;
22814            let mut matches = fuzzy::match_strings(
22815                &candidates,
22816                &last_word,
22817                last_word.chars().any(|c| c.is_uppercase()),
22818                true,
22819                MAX_RESULTS,
22820                &Default::default(),
22821                executor.clone(),
22822            )
22823            .await;
22824
22825            if matches.len() >= MAX_RESULTS {
22826                is_incomplete = true;
22827            }
22828
22829            // Remove all candidates where the query's start does not match the start of any word in the candidate
22830            if let Some(query_start) = last_word.chars().next() {
22831                matches.retain(|string_match| {
22832                    split_words(&string_match.string).any(|word| {
22833                        // Check that the first codepoint of the word as lowercase matches the first
22834                        // codepoint of the query as lowercase
22835                        word.chars()
22836                            .flat_map(|codepoint| codepoint.to_lowercase())
22837                            .zip(query_start.to_lowercase())
22838                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22839                    })
22840                });
22841            }
22842
22843            let matched_strings = matches
22844                .into_iter()
22845                .map(|m| m.string)
22846                .collect::<HashSet<_>>();
22847
22848            completions.extend(snippets.iter().filter_map(|snippet| {
22849                let matching_prefix = snippet
22850                    .prefix
22851                    .iter()
22852                    .find(|prefix| matched_strings.contains(*prefix))?;
22853                let start = as_offset - last_word.len();
22854                let start = snapshot.anchor_before(start);
22855                let range = start..buffer_position;
22856                let lsp_start = to_lsp(&start);
22857                let lsp_range = lsp::Range {
22858                    start: lsp_start,
22859                    end: lsp_end,
22860                };
22861                Some(Completion {
22862                    replace_range: range,
22863                    new_text: snippet.body.clone(),
22864                    source: CompletionSource::Lsp {
22865                        insert_range: None,
22866                        server_id: LanguageServerId(usize::MAX),
22867                        resolved: true,
22868                        lsp_completion: Box::new(lsp::CompletionItem {
22869                            label: snippet.prefix.first().unwrap().clone(),
22870                            kind: Some(CompletionItemKind::SNIPPET),
22871                            label_details: snippet.description.as_ref().map(|description| {
22872                                lsp::CompletionItemLabelDetails {
22873                                    detail: Some(description.clone()),
22874                                    description: None,
22875                                }
22876                            }),
22877                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22878                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22879                                lsp::InsertReplaceEdit {
22880                                    new_text: snippet.body.clone(),
22881                                    insert: lsp_range,
22882                                    replace: lsp_range,
22883                                },
22884                            )),
22885                            filter_text: Some(snippet.body.clone()),
22886                            sort_text: Some(char::MAX.to_string()),
22887                            ..lsp::CompletionItem::default()
22888                        }),
22889                        lsp_defaults: None,
22890                    },
22891                    label: CodeLabel {
22892                        text: matching_prefix.clone(),
22893                        runs: Vec::new(),
22894                        filter_range: 0..matching_prefix.len(),
22895                    },
22896                    icon_path: None,
22897                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22898                        single_line: snippet.name.clone().into(),
22899                        plain_text: snippet
22900                            .description
22901                            .clone()
22902                            .map(|description| description.into()),
22903                    }),
22904                    insert_text_mode: None,
22905                    confirm: None,
22906                })
22907            }))
22908        }
22909
22910        Ok(CompletionResponse {
22911            completions,
22912            display_options: CompletionDisplayOptions::default(),
22913            is_incomplete,
22914        })
22915    })
22916}
22917
22918impl CompletionProvider for Entity<Project> {
22919    fn completions(
22920        &self,
22921        _excerpt_id: ExcerptId,
22922        buffer: &Entity<Buffer>,
22923        buffer_position: text::Anchor,
22924        options: CompletionContext,
22925        _window: &mut Window,
22926        cx: &mut Context<Editor>,
22927    ) -> Task<Result<Vec<CompletionResponse>>> {
22928        self.update(cx, |project, cx| {
22929            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22930            let project_completions = project.completions(buffer, buffer_position, options, cx);
22931            cx.background_spawn(async move {
22932                let mut responses = project_completions.await?;
22933                let snippets = snippets.await?;
22934                if !snippets.completions.is_empty() {
22935                    responses.push(snippets);
22936                }
22937                Ok(responses)
22938            })
22939        })
22940    }
22941
22942    fn resolve_completions(
22943        &self,
22944        buffer: Entity<Buffer>,
22945        completion_indices: Vec<usize>,
22946        completions: Rc<RefCell<Box<[Completion]>>>,
22947        cx: &mut Context<Editor>,
22948    ) -> Task<Result<bool>> {
22949        self.update(cx, |project, cx| {
22950            project.lsp_store().update(cx, |lsp_store, cx| {
22951                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22952            })
22953        })
22954    }
22955
22956    fn apply_additional_edits_for_completion(
22957        &self,
22958        buffer: Entity<Buffer>,
22959        completions: Rc<RefCell<Box<[Completion]>>>,
22960        completion_index: usize,
22961        push_to_history: bool,
22962        cx: &mut Context<Editor>,
22963    ) -> Task<Result<Option<language::Transaction>>> {
22964        self.update(cx, |project, cx| {
22965            project.lsp_store().update(cx, |lsp_store, cx| {
22966                lsp_store.apply_additional_edits_for_completion(
22967                    buffer,
22968                    completions,
22969                    completion_index,
22970                    push_to_history,
22971                    cx,
22972                )
22973            })
22974        })
22975    }
22976
22977    fn is_completion_trigger(
22978        &self,
22979        buffer: &Entity<Buffer>,
22980        position: language::Anchor,
22981        text: &str,
22982        trigger_in_words: bool,
22983        menu_is_open: bool,
22984        cx: &mut Context<Editor>,
22985    ) -> bool {
22986        let mut chars = text.chars();
22987        let char = if let Some(char) = chars.next() {
22988            char
22989        } else {
22990            return false;
22991        };
22992        if chars.next().is_some() {
22993            return false;
22994        }
22995
22996        let buffer = buffer.read(cx);
22997        let snapshot = buffer.snapshot();
22998        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22999            return false;
23000        }
23001        let classifier = snapshot
23002            .char_classifier_at(position)
23003            .scope_context(Some(CharScopeContext::Completion));
23004        if trigger_in_words && classifier.is_word(char) {
23005            return true;
23006        }
23007
23008        buffer.completion_triggers().contains(text)
23009    }
23010}
23011
23012impl SemanticsProvider for Entity<Project> {
23013    fn hover(
23014        &self,
23015        buffer: &Entity<Buffer>,
23016        position: text::Anchor,
23017        cx: &mut App,
23018    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23019        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23020    }
23021
23022    fn document_highlights(
23023        &self,
23024        buffer: &Entity<Buffer>,
23025        position: text::Anchor,
23026        cx: &mut App,
23027    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23028        Some(self.update(cx, |project, cx| {
23029            project.document_highlights(buffer, position, cx)
23030        }))
23031    }
23032
23033    fn definitions(
23034        &self,
23035        buffer: &Entity<Buffer>,
23036        position: text::Anchor,
23037        kind: GotoDefinitionKind,
23038        cx: &mut App,
23039    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23040        Some(self.update(cx, |project, cx| match kind {
23041            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23042            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23043            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23044            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23045        }))
23046    }
23047
23048    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23049        self.update(cx, |project, cx| {
23050            if project
23051                .active_debug_session(cx)
23052                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23053            {
23054                return true;
23055            }
23056
23057            buffer.update(cx, |buffer, cx| {
23058                project.any_language_server_supports_inlay_hints(buffer, cx)
23059            })
23060        })
23061    }
23062
23063    fn inline_values(
23064        &self,
23065        buffer_handle: Entity<Buffer>,
23066        range: Range<text::Anchor>,
23067        cx: &mut App,
23068    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23069        self.update(cx, |project, cx| {
23070            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23071
23072            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23073        })
23074    }
23075
23076    fn inlay_hints(
23077        &self,
23078        buffer_handle: Entity<Buffer>,
23079        range: Range<text::Anchor>,
23080        cx: &mut App,
23081    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23082        Some(self.update(cx, |project, cx| {
23083            project.inlay_hints(buffer_handle, range, cx)
23084        }))
23085    }
23086
23087    fn resolve_inlay_hint(
23088        &self,
23089        hint: InlayHint,
23090        buffer_handle: Entity<Buffer>,
23091        server_id: LanguageServerId,
23092        cx: &mut App,
23093    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23094        Some(self.update(cx, |project, cx| {
23095            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23096        }))
23097    }
23098
23099    fn range_for_rename(
23100        &self,
23101        buffer: &Entity<Buffer>,
23102        position: text::Anchor,
23103        cx: &mut App,
23104    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23105        Some(self.update(cx, |project, cx| {
23106            let buffer = buffer.clone();
23107            let task = project.prepare_rename(buffer.clone(), position, cx);
23108            cx.spawn(async move |_, cx| {
23109                Ok(match task.await? {
23110                    PrepareRenameResponse::Success(range) => Some(range),
23111                    PrepareRenameResponse::InvalidPosition => None,
23112                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23113                        // Fallback on using TreeSitter info to determine identifier range
23114                        buffer.read_with(cx, |buffer, _| {
23115                            let snapshot = buffer.snapshot();
23116                            let (range, kind) = snapshot.surrounding_word(position, None);
23117                            if kind != Some(CharKind::Word) {
23118                                return None;
23119                            }
23120                            Some(
23121                                snapshot.anchor_before(range.start)
23122                                    ..snapshot.anchor_after(range.end),
23123                            )
23124                        })?
23125                    }
23126                })
23127            })
23128        }))
23129    }
23130
23131    fn perform_rename(
23132        &self,
23133        buffer: &Entity<Buffer>,
23134        position: text::Anchor,
23135        new_name: String,
23136        cx: &mut App,
23137    ) -> Option<Task<Result<ProjectTransaction>>> {
23138        Some(self.update(cx, |project, cx| {
23139            project.perform_rename(buffer.clone(), position, new_name, cx)
23140        }))
23141    }
23142}
23143
23144fn inlay_hint_settings(
23145    location: Anchor,
23146    snapshot: &MultiBufferSnapshot,
23147    cx: &mut Context<Editor>,
23148) -> InlayHintSettings {
23149    let file = snapshot.file_at(location);
23150    let language = snapshot.language_at(location).map(|l| l.name());
23151    language_settings(language, file, cx).inlay_hints
23152}
23153
23154fn consume_contiguous_rows(
23155    contiguous_row_selections: &mut Vec<Selection<Point>>,
23156    selection: &Selection<Point>,
23157    display_map: &DisplaySnapshot,
23158    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23159) -> (MultiBufferRow, MultiBufferRow) {
23160    contiguous_row_selections.push(selection.clone());
23161    let start_row = starting_row(selection, display_map);
23162    let mut end_row = ending_row(selection, display_map);
23163
23164    while let Some(next_selection) = selections.peek() {
23165        if next_selection.start.row <= end_row.0 {
23166            end_row = ending_row(next_selection, display_map);
23167            contiguous_row_selections.push(selections.next().unwrap().clone());
23168        } else {
23169            break;
23170        }
23171    }
23172    (start_row, end_row)
23173}
23174
23175fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23176    if selection.start.column > 0 {
23177        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23178    } else {
23179        MultiBufferRow(selection.start.row)
23180    }
23181}
23182
23183fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23184    if next_selection.end.column > 0 || next_selection.is_empty() {
23185        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23186    } else {
23187        MultiBufferRow(next_selection.end.row)
23188    }
23189}
23190
23191impl EditorSnapshot {
23192    pub fn remote_selections_in_range<'a>(
23193        &'a self,
23194        range: &'a Range<Anchor>,
23195        collaboration_hub: &dyn CollaborationHub,
23196        cx: &'a App,
23197    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23198        let participant_names = collaboration_hub.user_names(cx);
23199        let participant_indices = collaboration_hub.user_participant_indices(cx);
23200        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23201        let collaborators_by_replica_id = collaborators_by_peer_id
23202            .values()
23203            .map(|collaborator| (collaborator.replica_id, collaborator))
23204            .collect::<HashMap<_, _>>();
23205        self.buffer_snapshot
23206            .selections_in_range(range, false)
23207            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23208                if replica_id == AGENT_REPLICA_ID {
23209                    Some(RemoteSelection {
23210                        replica_id,
23211                        selection,
23212                        cursor_shape,
23213                        line_mode,
23214                        collaborator_id: CollaboratorId::Agent,
23215                        user_name: Some("Agent".into()),
23216                        color: cx.theme().players().agent(),
23217                    })
23218                } else {
23219                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23220                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23221                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23222                    Some(RemoteSelection {
23223                        replica_id,
23224                        selection,
23225                        cursor_shape,
23226                        line_mode,
23227                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23228                        user_name,
23229                        color: if let Some(index) = participant_index {
23230                            cx.theme().players().color_for_participant(index.0)
23231                        } else {
23232                            cx.theme().players().absent()
23233                        },
23234                    })
23235                }
23236            })
23237    }
23238
23239    pub fn hunks_for_ranges(
23240        &self,
23241        ranges: impl IntoIterator<Item = Range<Point>>,
23242    ) -> Vec<MultiBufferDiffHunk> {
23243        let mut hunks = Vec::new();
23244        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23245            HashMap::default();
23246        for query_range in ranges {
23247            let query_rows =
23248                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23249            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23250                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23251            ) {
23252                // Include deleted hunks that are adjacent to the query range, because
23253                // otherwise they would be missed.
23254                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23255                if hunk.status().is_deleted() {
23256                    intersects_range |= hunk.row_range.start == query_rows.end;
23257                    intersects_range |= hunk.row_range.end == query_rows.start;
23258                }
23259                if intersects_range {
23260                    if !processed_buffer_rows
23261                        .entry(hunk.buffer_id)
23262                        .or_default()
23263                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23264                    {
23265                        continue;
23266                    }
23267                    hunks.push(hunk);
23268                }
23269            }
23270        }
23271
23272        hunks
23273    }
23274
23275    fn display_diff_hunks_for_rows<'a>(
23276        &'a self,
23277        display_rows: Range<DisplayRow>,
23278        folded_buffers: &'a HashSet<BufferId>,
23279    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23280        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23281        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23282
23283        self.buffer_snapshot
23284            .diff_hunks_in_range(buffer_start..buffer_end)
23285            .filter_map(|hunk| {
23286                if folded_buffers.contains(&hunk.buffer_id) {
23287                    return None;
23288                }
23289
23290                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23291                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23292
23293                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23294                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23295
23296                let display_hunk = if hunk_display_start.column() != 0 {
23297                    DisplayDiffHunk::Folded {
23298                        display_row: hunk_display_start.row(),
23299                    }
23300                } else {
23301                    let mut end_row = hunk_display_end.row();
23302                    if hunk_display_end.column() > 0 {
23303                        end_row.0 += 1;
23304                    }
23305                    let is_created_file = hunk.is_created_file();
23306                    DisplayDiffHunk::Unfolded {
23307                        status: hunk.status(),
23308                        diff_base_byte_range: hunk.diff_base_byte_range,
23309                        display_row_range: hunk_display_start.row()..end_row,
23310                        multi_buffer_range: Anchor::range_in_buffer(
23311                            hunk.excerpt_id,
23312                            hunk.buffer_id,
23313                            hunk.buffer_range,
23314                        ),
23315                        is_created_file,
23316                    }
23317                };
23318
23319                Some(display_hunk)
23320            })
23321    }
23322
23323    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23324        self.display_snapshot.buffer_snapshot.language_at(position)
23325    }
23326
23327    pub fn is_focused(&self) -> bool {
23328        self.is_focused
23329    }
23330
23331    pub fn placeholder_text(&self) -> Option<String> {
23332        self.placeholder_display_snapshot
23333            .as_ref()
23334            .map(|display_map| display_map.text())
23335    }
23336
23337    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23338        self.scroll_anchor.scroll_position(&self.display_snapshot)
23339    }
23340
23341    fn gutter_dimensions(
23342        &self,
23343        font_id: FontId,
23344        font_size: Pixels,
23345        max_line_number_width: Pixels,
23346        cx: &App,
23347    ) -> Option<GutterDimensions> {
23348        if !self.show_gutter {
23349            return None;
23350        }
23351
23352        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23353        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23354
23355        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23356            matches!(
23357                ProjectSettings::get_global(cx).git.git_gutter,
23358                GitGutterSetting::TrackedFiles
23359            )
23360        });
23361        let gutter_settings = EditorSettings::get_global(cx).gutter;
23362        let show_line_numbers = self
23363            .show_line_numbers
23364            .unwrap_or(gutter_settings.line_numbers);
23365        let line_gutter_width = if show_line_numbers {
23366            // Avoid flicker-like gutter resizes when the line number gains another digit by
23367            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23368            let min_width_for_number_on_gutter =
23369                ch_advance * gutter_settings.min_line_number_digits as f32;
23370            max_line_number_width.max(min_width_for_number_on_gutter)
23371        } else {
23372            0.0.into()
23373        };
23374
23375        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23376        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23377
23378        let git_blame_entries_width =
23379            self.git_blame_gutter_max_author_length
23380                .map(|max_author_length| {
23381                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23382                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23383
23384                    /// The number of characters to dedicate to gaps and margins.
23385                    const SPACING_WIDTH: usize = 4;
23386
23387                    let max_char_count = max_author_length.min(renderer.max_author_length())
23388                        + ::git::SHORT_SHA_LENGTH
23389                        + MAX_RELATIVE_TIMESTAMP.len()
23390                        + SPACING_WIDTH;
23391
23392                    ch_advance * max_char_count
23393                });
23394
23395        let is_singleton = self.buffer_snapshot.is_singleton();
23396
23397        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23398        left_padding += if !is_singleton {
23399            ch_width * 4.0
23400        } else if show_runnables || show_breakpoints {
23401            ch_width * 3.0
23402        } else if show_git_gutter && show_line_numbers {
23403            ch_width * 2.0
23404        } else if show_git_gutter || show_line_numbers {
23405            ch_width
23406        } else {
23407            px(0.)
23408        };
23409
23410        let shows_folds = is_singleton && gutter_settings.folds;
23411
23412        let right_padding = if shows_folds && show_line_numbers {
23413            ch_width * 4.0
23414        } else if shows_folds || (!is_singleton && show_line_numbers) {
23415            ch_width * 3.0
23416        } else if show_line_numbers {
23417            ch_width
23418        } else {
23419            px(0.)
23420        };
23421
23422        Some(GutterDimensions {
23423            left_padding,
23424            right_padding,
23425            width: line_gutter_width + left_padding + right_padding,
23426            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23427            git_blame_entries_width,
23428        })
23429    }
23430
23431    pub fn render_crease_toggle(
23432        &self,
23433        buffer_row: MultiBufferRow,
23434        row_contains_cursor: bool,
23435        editor: Entity<Editor>,
23436        window: &mut Window,
23437        cx: &mut App,
23438    ) -> Option<AnyElement> {
23439        let folded = self.is_line_folded(buffer_row);
23440        let mut is_foldable = false;
23441
23442        if let Some(crease) = self
23443            .crease_snapshot
23444            .query_row(buffer_row, &self.buffer_snapshot)
23445        {
23446            is_foldable = true;
23447            match crease {
23448                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23449                    if let Some(render_toggle) = render_toggle {
23450                        let toggle_callback =
23451                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23452                                if folded {
23453                                    editor.update(cx, |editor, cx| {
23454                                        editor.fold_at(buffer_row, window, cx)
23455                                    });
23456                                } else {
23457                                    editor.update(cx, |editor, cx| {
23458                                        editor.unfold_at(buffer_row, window, cx)
23459                                    });
23460                                }
23461                            });
23462                        return Some((render_toggle)(
23463                            buffer_row,
23464                            folded,
23465                            toggle_callback,
23466                            window,
23467                            cx,
23468                        ));
23469                    }
23470                }
23471            }
23472        }
23473
23474        is_foldable |= self.starts_indent(buffer_row);
23475
23476        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23477            Some(
23478                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23479                    .toggle_state(folded)
23480                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23481                        if folded {
23482                            this.unfold_at(buffer_row, window, cx);
23483                        } else {
23484                            this.fold_at(buffer_row, window, cx);
23485                        }
23486                    }))
23487                    .into_any_element(),
23488            )
23489        } else {
23490            None
23491        }
23492    }
23493
23494    pub fn render_crease_trailer(
23495        &self,
23496        buffer_row: MultiBufferRow,
23497        window: &mut Window,
23498        cx: &mut App,
23499    ) -> Option<AnyElement> {
23500        let folded = self.is_line_folded(buffer_row);
23501        if let Crease::Inline { render_trailer, .. } = self
23502            .crease_snapshot
23503            .query_row(buffer_row, &self.buffer_snapshot)?
23504        {
23505            let render_trailer = render_trailer.as_ref()?;
23506            Some(render_trailer(buffer_row, folded, window, cx))
23507        } else {
23508            None
23509        }
23510    }
23511}
23512
23513impl Deref for EditorSnapshot {
23514    type Target = DisplaySnapshot;
23515
23516    fn deref(&self) -> &Self::Target {
23517        &self.display_snapshot
23518    }
23519}
23520
23521#[derive(Clone, Debug, PartialEq, Eq)]
23522pub enum EditorEvent {
23523    InputIgnored {
23524        text: Arc<str>,
23525    },
23526    InputHandled {
23527        utf16_range_to_replace: Option<Range<isize>>,
23528        text: Arc<str>,
23529    },
23530    ExcerptsAdded {
23531        buffer: Entity<Buffer>,
23532        predecessor: ExcerptId,
23533        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23534    },
23535    ExcerptsRemoved {
23536        ids: Vec<ExcerptId>,
23537        removed_buffer_ids: Vec<BufferId>,
23538    },
23539    BufferFoldToggled {
23540        ids: Vec<ExcerptId>,
23541        folded: bool,
23542    },
23543    ExcerptsEdited {
23544        ids: Vec<ExcerptId>,
23545    },
23546    ExcerptsExpanded {
23547        ids: Vec<ExcerptId>,
23548    },
23549    BufferEdited,
23550    Edited {
23551        transaction_id: clock::Lamport,
23552    },
23553    Reparsed(BufferId),
23554    Focused,
23555    FocusedIn,
23556    Blurred,
23557    DirtyChanged,
23558    Saved,
23559    TitleChanged,
23560    SelectionsChanged {
23561        local: bool,
23562    },
23563    ScrollPositionChanged {
23564        local: bool,
23565        autoscroll: bool,
23566    },
23567    TransactionUndone {
23568        transaction_id: clock::Lamport,
23569    },
23570    TransactionBegun {
23571        transaction_id: clock::Lamport,
23572    },
23573    CursorShapeChanged,
23574    BreadcrumbsChanged,
23575    PushedToNavHistory {
23576        anchor: Anchor,
23577        is_deactivate: bool,
23578    },
23579}
23580
23581impl EventEmitter<EditorEvent> for Editor {}
23582
23583impl Focusable for Editor {
23584    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23585        self.focus_handle.clone()
23586    }
23587}
23588
23589impl Render for Editor {
23590    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23591        let settings = ThemeSettings::get_global(cx);
23592
23593        let mut text_style = match self.mode {
23594            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23595                color: cx.theme().colors().editor_foreground,
23596                font_family: settings.ui_font.family.clone(),
23597                font_features: settings.ui_font.features.clone(),
23598                font_fallbacks: settings.ui_font.fallbacks.clone(),
23599                font_size: rems(0.875).into(),
23600                font_weight: settings.ui_font.weight,
23601                line_height: relative(settings.buffer_line_height.value()),
23602                ..Default::default()
23603            },
23604            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23605                color: cx.theme().colors().editor_foreground,
23606                font_family: settings.buffer_font.family.clone(),
23607                font_features: settings.buffer_font.features.clone(),
23608                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23609                font_size: settings.buffer_font_size(cx).into(),
23610                font_weight: settings.buffer_font.weight,
23611                line_height: relative(settings.buffer_line_height.value()),
23612                ..Default::default()
23613            },
23614        };
23615        if let Some(text_style_refinement) = &self.text_style_refinement {
23616            text_style.refine(text_style_refinement)
23617        }
23618
23619        let background = match self.mode {
23620            EditorMode::SingleLine => cx.theme().system().transparent,
23621            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23622            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23623            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23624        };
23625
23626        EditorElement::new(
23627            &cx.entity(),
23628            EditorStyle {
23629                background,
23630                border: cx.theme().colors().border,
23631                local_player: cx.theme().players().local(),
23632                text: text_style,
23633                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23634                syntax: cx.theme().syntax().clone(),
23635                status: cx.theme().status().clone(),
23636                inlay_hints_style: make_inlay_hints_style(cx),
23637                edit_prediction_styles: make_suggestion_styles(cx),
23638                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23639                show_underlines: self.diagnostics_enabled(),
23640            },
23641        )
23642    }
23643}
23644
23645impl EntityInputHandler for Editor {
23646    fn text_for_range(
23647        &mut self,
23648        range_utf16: Range<usize>,
23649        adjusted_range: &mut Option<Range<usize>>,
23650        _: &mut Window,
23651        cx: &mut Context<Self>,
23652    ) -> Option<String> {
23653        let snapshot = self.buffer.read(cx).read(cx);
23654        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23655        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23656        if (start.0..end.0) != range_utf16 {
23657            adjusted_range.replace(start.0..end.0);
23658        }
23659        Some(snapshot.text_for_range(start..end).collect())
23660    }
23661
23662    fn selected_text_range(
23663        &mut self,
23664        ignore_disabled_input: bool,
23665        _: &mut Window,
23666        cx: &mut Context<Self>,
23667    ) -> Option<UTF16Selection> {
23668        // Prevent the IME menu from appearing when holding down an alphabetic key
23669        // while input is disabled.
23670        if !ignore_disabled_input && !self.input_enabled {
23671            return None;
23672        }
23673
23674        let selection = self.selections.newest::<OffsetUtf16>(cx);
23675        let range = selection.range();
23676
23677        Some(UTF16Selection {
23678            range: range.start.0..range.end.0,
23679            reversed: selection.reversed,
23680        })
23681    }
23682
23683    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23684        let snapshot = self.buffer.read(cx).read(cx);
23685        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23686        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23687    }
23688
23689    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23690        self.clear_highlights::<InputComposition>(cx);
23691        self.ime_transaction.take();
23692    }
23693
23694    fn replace_text_in_range(
23695        &mut self,
23696        range_utf16: Option<Range<usize>>,
23697        text: &str,
23698        window: &mut Window,
23699        cx: &mut Context<Self>,
23700    ) {
23701        if !self.input_enabled {
23702            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23703            return;
23704        }
23705
23706        self.transact(window, cx, |this, window, cx| {
23707            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23708                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23709                Some(this.selection_replacement_ranges(range_utf16, cx))
23710            } else {
23711                this.marked_text_ranges(cx)
23712            };
23713
23714            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23715                let newest_selection_id = this.selections.newest_anchor().id;
23716                this.selections
23717                    .all::<OffsetUtf16>(cx)
23718                    .iter()
23719                    .zip(ranges_to_replace.iter())
23720                    .find_map(|(selection, range)| {
23721                        if selection.id == newest_selection_id {
23722                            Some(
23723                                (range.start.0 as isize - selection.head().0 as isize)
23724                                    ..(range.end.0 as isize - selection.head().0 as isize),
23725                            )
23726                        } else {
23727                            None
23728                        }
23729                    })
23730            });
23731
23732            cx.emit(EditorEvent::InputHandled {
23733                utf16_range_to_replace: range_to_replace,
23734                text: text.into(),
23735            });
23736
23737            if let Some(new_selected_ranges) = new_selected_ranges {
23738                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23739                    selections.select_ranges(new_selected_ranges)
23740                });
23741                this.backspace(&Default::default(), window, cx);
23742            }
23743
23744            this.handle_input(text, window, cx);
23745        });
23746
23747        if let Some(transaction) = self.ime_transaction {
23748            self.buffer.update(cx, |buffer, cx| {
23749                buffer.group_until_transaction(transaction, cx);
23750            });
23751        }
23752
23753        self.unmark_text(window, cx);
23754    }
23755
23756    fn replace_and_mark_text_in_range(
23757        &mut self,
23758        range_utf16: Option<Range<usize>>,
23759        text: &str,
23760        new_selected_range_utf16: Option<Range<usize>>,
23761        window: &mut Window,
23762        cx: &mut Context<Self>,
23763    ) {
23764        if !self.input_enabled {
23765            return;
23766        }
23767
23768        let transaction = self.transact(window, cx, |this, window, cx| {
23769            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23770                let snapshot = this.buffer.read(cx).read(cx);
23771                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23772                    for marked_range in &mut marked_ranges {
23773                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23774                        marked_range.start.0 += relative_range_utf16.start;
23775                        marked_range.start =
23776                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23777                        marked_range.end =
23778                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23779                    }
23780                }
23781                Some(marked_ranges)
23782            } else if let Some(range_utf16) = range_utf16 {
23783                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23784                Some(this.selection_replacement_ranges(range_utf16, cx))
23785            } else {
23786                None
23787            };
23788
23789            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23790                let newest_selection_id = this.selections.newest_anchor().id;
23791                this.selections
23792                    .all::<OffsetUtf16>(cx)
23793                    .iter()
23794                    .zip(ranges_to_replace.iter())
23795                    .find_map(|(selection, range)| {
23796                        if selection.id == newest_selection_id {
23797                            Some(
23798                                (range.start.0 as isize - selection.head().0 as isize)
23799                                    ..(range.end.0 as isize - selection.head().0 as isize),
23800                            )
23801                        } else {
23802                            None
23803                        }
23804                    })
23805            });
23806
23807            cx.emit(EditorEvent::InputHandled {
23808                utf16_range_to_replace: range_to_replace,
23809                text: text.into(),
23810            });
23811
23812            if let Some(ranges) = ranges_to_replace {
23813                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23814                    s.select_ranges(ranges)
23815                });
23816            }
23817
23818            let marked_ranges = {
23819                let snapshot = this.buffer.read(cx).read(cx);
23820                this.selections
23821                    .disjoint_anchors_arc()
23822                    .iter()
23823                    .map(|selection| {
23824                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23825                    })
23826                    .collect::<Vec<_>>()
23827            };
23828
23829            if text.is_empty() {
23830                this.unmark_text(window, cx);
23831            } else {
23832                this.highlight_text::<InputComposition>(
23833                    marked_ranges.clone(),
23834                    HighlightStyle {
23835                        underline: Some(UnderlineStyle {
23836                            thickness: px(1.),
23837                            color: None,
23838                            wavy: false,
23839                        }),
23840                        ..Default::default()
23841                    },
23842                    cx,
23843                );
23844            }
23845
23846            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23847            let use_autoclose = this.use_autoclose;
23848            let use_auto_surround = this.use_auto_surround;
23849            this.set_use_autoclose(false);
23850            this.set_use_auto_surround(false);
23851            this.handle_input(text, window, cx);
23852            this.set_use_autoclose(use_autoclose);
23853            this.set_use_auto_surround(use_auto_surround);
23854
23855            if let Some(new_selected_range) = new_selected_range_utf16 {
23856                let snapshot = this.buffer.read(cx).read(cx);
23857                let new_selected_ranges = marked_ranges
23858                    .into_iter()
23859                    .map(|marked_range| {
23860                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23861                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23862                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23863                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23864                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23865                    })
23866                    .collect::<Vec<_>>();
23867
23868                drop(snapshot);
23869                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23870                    selections.select_ranges(new_selected_ranges)
23871                });
23872            }
23873        });
23874
23875        self.ime_transaction = self.ime_transaction.or(transaction);
23876        if let Some(transaction) = self.ime_transaction {
23877            self.buffer.update(cx, |buffer, cx| {
23878                buffer.group_until_transaction(transaction, cx);
23879            });
23880        }
23881
23882        if self.text_highlights::<InputComposition>(cx).is_none() {
23883            self.ime_transaction.take();
23884        }
23885    }
23886
23887    fn bounds_for_range(
23888        &mut self,
23889        range_utf16: Range<usize>,
23890        element_bounds: gpui::Bounds<Pixels>,
23891        window: &mut Window,
23892        cx: &mut Context<Self>,
23893    ) -> Option<gpui::Bounds<Pixels>> {
23894        let text_layout_details = self.text_layout_details(window);
23895        let CharacterDimensions {
23896            em_width,
23897            em_advance,
23898            line_height,
23899        } = self.character_dimensions(window);
23900
23901        let snapshot = self.snapshot(window, cx);
23902        let scroll_position = snapshot.scroll_position();
23903        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
23904
23905        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23906        let x = Pixels::from(
23907            ScrollOffset::from(
23908                snapshot.x_for_display_point(start, &text_layout_details)
23909                    + self.gutter_dimensions.full_width(),
23910            ) - scroll_left,
23911        );
23912        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
23913
23914        Some(Bounds {
23915            origin: element_bounds.origin + point(x, y),
23916            size: size(em_width, line_height),
23917        })
23918    }
23919
23920    fn character_index_for_point(
23921        &mut self,
23922        point: gpui::Point<Pixels>,
23923        _window: &mut Window,
23924        _cx: &mut Context<Self>,
23925    ) -> Option<usize> {
23926        let position_map = self.last_position_map.as_ref()?;
23927        if !position_map.text_hitbox.contains(&point) {
23928            return None;
23929        }
23930        let display_point = position_map.point_for_position(point).previous_valid;
23931        let anchor = position_map
23932            .snapshot
23933            .display_point_to_anchor(display_point, Bias::Left);
23934        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23935        Some(utf16_offset.0)
23936    }
23937}
23938
23939trait SelectionExt {
23940    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23941    fn spanned_rows(
23942        &self,
23943        include_end_if_at_line_start: bool,
23944        map: &DisplaySnapshot,
23945    ) -> Range<MultiBufferRow>;
23946}
23947
23948impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23949    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23950        let start = self
23951            .start
23952            .to_point(&map.buffer_snapshot)
23953            .to_display_point(map);
23954        let end = self
23955            .end
23956            .to_point(&map.buffer_snapshot)
23957            .to_display_point(map);
23958        if self.reversed {
23959            end..start
23960        } else {
23961            start..end
23962        }
23963    }
23964
23965    fn spanned_rows(
23966        &self,
23967        include_end_if_at_line_start: bool,
23968        map: &DisplaySnapshot,
23969    ) -> Range<MultiBufferRow> {
23970        let start = self.start.to_point(&map.buffer_snapshot);
23971        let mut end = self.end.to_point(&map.buffer_snapshot);
23972        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23973            end.row -= 1;
23974        }
23975
23976        let buffer_start = map.prev_line_boundary(start).0;
23977        let buffer_end = map.next_line_boundary(end).0;
23978        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23979    }
23980}
23981
23982impl<T: InvalidationRegion> InvalidationStack<T> {
23983    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23984    where
23985        S: Clone + ToOffset,
23986    {
23987        while let Some(region) = self.last() {
23988            let all_selections_inside_invalidation_ranges =
23989                if selections.len() == region.ranges().len() {
23990                    selections
23991                        .iter()
23992                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23993                        .all(|(selection, invalidation_range)| {
23994                            let head = selection.head().to_offset(buffer);
23995                            invalidation_range.start <= head && invalidation_range.end >= head
23996                        })
23997                } else {
23998                    false
23999                };
24000
24001            if all_selections_inside_invalidation_ranges {
24002                break;
24003            } else {
24004                self.pop();
24005            }
24006        }
24007    }
24008}
24009
24010impl<T> Default for InvalidationStack<T> {
24011    fn default() -> Self {
24012        Self(Default::default())
24013    }
24014}
24015
24016impl<T> Deref for InvalidationStack<T> {
24017    type Target = Vec<T>;
24018
24019    fn deref(&self) -> &Self::Target {
24020        &self.0
24021    }
24022}
24023
24024impl<T> DerefMut for InvalidationStack<T> {
24025    fn deref_mut(&mut self) -> &mut Self::Target {
24026        &mut self.0
24027    }
24028}
24029
24030impl InvalidationRegion for SnippetState {
24031    fn ranges(&self) -> &[Range<Anchor>] {
24032        &self.ranges[self.active_index]
24033    }
24034}
24035
24036fn edit_prediction_edit_text(
24037    current_snapshot: &BufferSnapshot,
24038    edits: &[(Range<Anchor>, String)],
24039    edit_preview: &EditPreview,
24040    include_deletions: bool,
24041    cx: &App,
24042) -> HighlightedText {
24043    let edits = edits
24044        .iter()
24045        .map(|(anchor, text)| {
24046            (
24047                anchor.start.text_anchor..anchor.end.text_anchor,
24048                text.clone(),
24049            )
24050        })
24051        .collect::<Vec<_>>();
24052
24053    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24054}
24055
24056fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24057    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24058    // Just show the raw edit text with basic styling
24059    let mut text = String::new();
24060    let mut highlights = Vec::new();
24061
24062    let insertion_highlight_style = HighlightStyle {
24063        color: Some(cx.theme().colors().text),
24064        ..Default::default()
24065    };
24066
24067    for (_, edit_text) in edits {
24068        let start_offset = text.len();
24069        text.push_str(edit_text);
24070        let end_offset = text.len();
24071
24072        if start_offset < end_offset {
24073            highlights.push((start_offset..end_offset, insertion_highlight_style));
24074        }
24075    }
24076
24077    HighlightedText {
24078        text: text.into(),
24079        highlights,
24080    }
24081}
24082
24083pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24084    match severity {
24085        lsp::DiagnosticSeverity::ERROR => colors.error,
24086        lsp::DiagnosticSeverity::WARNING => colors.warning,
24087        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24088        lsp::DiagnosticSeverity::HINT => colors.info,
24089        _ => colors.ignored,
24090    }
24091}
24092
24093pub fn styled_runs_for_code_label<'a>(
24094    label: &'a CodeLabel,
24095    syntax_theme: &'a theme::SyntaxTheme,
24096) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24097    let fade_out = HighlightStyle {
24098        fade_out: Some(0.35),
24099        ..Default::default()
24100    };
24101
24102    let mut prev_end = label.filter_range.end;
24103    label
24104        .runs
24105        .iter()
24106        .enumerate()
24107        .flat_map(move |(ix, (range, highlight_id))| {
24108            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24109                style
24110            } else {
24111                return Default::default();
24112            };
24113            let muted_style = style.highlight(fade_out);
24114
24115            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24116            if range.start >= label.filter_range.end {
24117                if range.start > prev_end {
24118                    runs.push((prev_end..range.start, fade_out));
24119                }
24120                runs.push((range.clone(), muted_style));
24121            } else if range.end <= label.filter_range.end {
24122                runs.push((range.clone(), style));
24123            } else {
24124                runs.push((range.start..label.filter_range.end, style));
24125                runs.push((label.filter_range.end..range.end, muted_style));
24126            }
24127            prev_end = cmp::max(prev_end, range.end);
24128
24129            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24130                runs.push((prev_end..label.text.len(), fade_out));
24131            }
24132
24133            runs
24134        })
24135}
24136
24137pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24138    let mut prev_index = 0;
24139    let mut prev_codepoint: Option<char> = None;
24140    text.char_indices()
24141        .chain([(text.len(), '\0')])
24142        .filter_map(move |(index, codepoint)| {
24143            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24144            let is_boundary = index == text.len()
24145                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24146                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24147            if is_boundary {
24148                let chunk = &text[prev_index..index];
24149                prev_index = index;
24150                Some(chunk)
24151            } else {
24152                None
24153            }
24154        })
24155}
24156
24157pub trait RangeToAnchorExt: Sized {
24158    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24159
24160    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24161        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
24162        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24163    }
24164}
24165
24166impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24167    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24168        let start_offset = self.start.to_offset(snapshot);
24169        let end_offset = self.end.to_offset(snapshot);
24170        if start_offset == end_offset {
24171            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24172        } else {
24173            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24174        }
24175    }
24176}
24177
24178pub trait RowExt {
24179    fn as_f64(&self) -> f64;
24180
24181    fn next_row(&self) -> Self;
24182
24183    fn previous_row(&self) -> Self;
24184
24185    fn minus(&self, other: Self) -> u32;
24186}
24187
24188impl RowExt for DisplayRow {
24189    fn as_f64(&self) -> f64 {
24190        self.0 as _
24191    }
24192
24193    fn next_row(&self) -> Self {
24194        Self(self.0 + 1)
24195    }
24196
24197    fn previous_row(&self) -> Self {
24198        Self(self.0.saturating_sub(1))
24199    }
24200
24201    fn minus(&self, other: Self) -> u32 {
24202        self.0 - other.0
24203    }
24204}
24205
24206impl RowExt for MultiBufferRow {
24207    fn as_f64(&self) -> f64 {
24208        self.0 as _
24209    }
24210
24211    fn next_row(&self) -> Self {
24212        Self(self.0 + 1)
24213    }
24214
24215    fn previous_row(&self) -> Self {
24216        Self(self.0.saturating_sub(1))
24217    }
24218
24219    fn minus(&self, other: Self) -> u32 {
24220        self.0 - other.0
24221    }
24222}
24223
24224trait RowRangeExt {
24225    type Row;
24226
24227    fn len(&self) -> usize;
24228
24229    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24230}
24231
24232impl RowRangeExt for Range<MultiBufferRow> {
24233    type Row = MultiBufferRow;
24234
24235    fn len(&self) -> usize {
24236        (self.end.0 - self.start.0) as usize
24237    }
24238
24239    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24240        (self.start.0..self.end.0).map(MultiBufferRow)
24241    }
24242}
24243
24244impl RowRangeExt for Range<DisplayRow> {
24245    type Row = DisplayRow;
24246
24247    fn len(&self) -> usize {
24248        (self.end.0 - self.start.0) as usize
24249    }
24250
24251    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24252        (self.start.0..self.end.0).map(DisplayRow)
24253    }
24254}
24255
24256/// If select range has more than one line, we
24257/// just point the cursor to range.start.
24258fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24259    if range.start.row == range.end.row {
24260        range
24261    } else {
24262        range.start..range.start
24263    }
24264}
24265pub struct KillRing(ClipboardItem);
24266impl Global for KillRing {}
24267
24268const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24269
24270enum BreakpointPromptEditAction {
24271    Log,
24272    Condition,
24273    HitCondition,
24274}
24275
24276struct BreakpointPromptEditor {
24277    pub(crate) prompt: Entity<Editor>,
24278    editor: WeakEntity<Editor>,
24279    breakpoint_anchor: Anchor,
24280    breakpoint: Breakpoint,
24281    edit_action: BreakpointPromptEditAction,
24282    block_ids: HashSet<CustomBlockId>,
24283    editor_margins: Arc<Mutex<EditorMargins>>,
24284    _subscriptions: Vec<Subscription>,
24285}
24286
24287impl BreakpointPromptEditor {
24288    const MAX_LINES: u8 = 4;
24289
24290    fn new(
24291        editor: WeakEntity<Editor>,
24292        breakpoint_anchor: Anchor,
24293        breakpoint: Breakpoint,
24294        edit_action: BreakpointPromptEditAction,
24295        window: &mut Window,
24296        cx: &mut Context<Self>,
24297    ) -> Self {
24298        let base_text = match edit_action {
24299            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24300            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24301            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24302        }
24303        .map(|msg| msg.to_string())
24304        .unwrap_or_default();
24305
24306        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24307        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24308
24309        let prompt = cx.new(|cx| {
24310            let mut prompt = Editor::new(
24311                EditorMode::AutoHeight {
24312                    min_lines: 1,
24313                    max_lines: Some(Self::MAX_LINES as usize),
24314                },
24315                buffer,
24316                None,
24317                window,
24318                cx,
24319            );
24320            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24321            prompt.set_show_cursor_when_unfocused(false, cx);
24322            prompt.set_placeholder_text(
24323                match edit_action {
24324                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24325                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24326                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24327                },
24328                window,
24329                cx,
24330            );
24331
24332            prompt
24333        });
24334
24335        Self {
24336            prompt,
24337            editor,
24338            breakpoint_anchor,
24339            breakpoint,
24340            edit_action,
24341            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24342            block_ids: Default::default(),
24343            _subscriptions: vec![],
24344        }
24345    }
24346
24347    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24348        self.block_ids.extend(block_ids)
24349    }
24350
24351    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24352        if let Some(editor) = self.editor.upgrade() {
24353            let message = self
24354                .prompt
24355                .read(cx)
24356                .buffer
24357                .read(cx)
24358                .as_singleton()
24359                .expect("A multi buffer in breakpoint prompt isn't possible")
24360                .read(cx)
24361                .as_rope()
24362                .to_string();
24363
24364            editor.update(cx, |editor, cx| {
24365                editor.edit_breakpoint_at_anchor(
24366                    self.breakpoint_anchor,
24367                    self.breakpoint.clone(),
24368                    match self.edit_action {
24369                        BreakpointPromptEditAction::Log => {
24370                            BreakpointEditAction::EditLogMessage(message.into())
24371                        }
24372                        BreakpointPromptEditAction::Condition => {
24373                            BreakpointEditAction::EditCondition(message.into())
24374                        }
24375                        BreakpointPromptEditAction::HitCondition => {
24376                            BreakpointEditAction::EditHitCondition(message.into())
24377                        }
24378                    },
24379                    cx,
24380                );
24381
24382                editor.remove_blocks(self.block_ids.clone(), None, cx);
24383                cx.focus_self(window);
24384            });
24385        }
24386    }
24387
24388    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24389        self.editor
24390            .update(cx, |editor, cx| {
24391                editor.remove_blocks(self.block_ids.clone(), None, cx);
24392                window.focus(&editor.focus_handle);
24393            })
24394            .log_err();
24395    }
24396
24397    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24398        let settings = ThemeSettings::get_global(cx);
24399        let text_style = TextStyle {
24400            color: if self.prompt.read(cx).read_only(cx) {
24401                cx.theme().colors().text_disabled
24402            } else {
24403                cx.theme().colors().text
24404            },
24405            font_family: settings.buffer_font.family.clone(),
24406            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24407            font_size: settings.buffer_font_size(cx).into(),
24408            font_weight: settings.buffer_font.weight,
24409            line_height: relative(settings.buffer_line_height.value()),
24410            ..Default::default()
24411        };
24412        EditorElement::new(
24413            &self.prompt,
24414            EditorStyle {
24415                background: cx.theme().colors().editor_background,
24416                local_player: cx.theme().players().local(),
24417                text: text_style,
24418                ..Default::default()
24419            },
24420        )
24421    }
24422}
24423
24424impl Render for BreakpointPromptEditor {
24425    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24426        let editor_margins = *self.editor_margins.lock();
24427        let gutter_dimensions = editor_margins.gutter;
24428        h_flex()
24429            .key_context("Editor")
24430            .bg(cx.theme().colors().editor_background)
24431            .border_y_1()
24432            .border_color(cx.theme().status().info_border)
24433            .size_full()
24434            .py(window.line_height() / 2.5)
24435            .on_action(cx.listener(Self::confirm))
24436            .on_action(cx.listener(Self::cancel))
24437            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24438            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24439    }
24440}
24441
24442impl Focusable for BreakpointPromptEditor {
24443    fn focus_handle(&self, cx: &App) -> FocusHandle {
24444        self.prompt.focus_handle(cx)
24445    }
24446}
24447
24448fn all_edits_insertions_or_deletions(
24449    edits: &Vec<(Range<Anchor>, String)>,
24450    snapshot: &MultiBufferSnapshot,
24451) -> bool {
24452    let mut all_insertions = true;
24453    let mut all_deletions = true;
24454
24455    for (range, new_text) in edits.iter() {
24456        let range_is_empty = range.to_offset(snapshot).is_empty();
24457        let text_is_empty = new_text.is_empty();
24458
24459        if range_is_empty != text_is_empty {
24460            if range_is_empty {
24461                all_deletions = false;
24462            } else {
24463                all_insertions = false;
24464            }
24465        } else {
24466            return false;
24467        }
24468
24469        if !all_insertions && !all_deletions {
24470            return false;
24471        }
24472    }
24473    all_insertions || all_deletions
24474}
24475
24476struct MissingEditPredictionKeybindingTooltip;
24477
24478impl Render for MissingEditPredictionKeybindingTooltip {
24479    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24480        ui::tooltip_container(cx, |container, cx| {
24481            container
24482                .flex_shrink_0()
24483                .max_w_80()
24484                .min_h(rems_from_px(124.))
24485                .justify_between()
24486                .child(
24487                    v_flex()
24488                        .flex_1()
24489                        .text_ui_sm(cx)
24490                        .child(Label::new("Conflict with Accept Keybinding"))
24491                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24492                )
24493                .child(
24494                    h_flex()
24495                        .pb_1()
24496                        .gap_1()
24497                        .items_end()
24498                        .w_full()
24499                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24500                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24501                        }))
24502                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24503                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24504                        })),
24505                )
24506        })
24507    }
24508}
24509
24510#[derive(Debug, Clone, Copy, PartialEq)]
24511pub struct LineHighlight {
24512    pub background: Background,
24513    pub border: Option<gpui::Hsla>,
24514    pub include_gutter: bool,
24515    pub type_id: Option<TypeId>,
24516}
24517
24518struct LineManipulationResult {
24519    pub new_text: String,
24520    pub line_count_before: usize,
24521    pub line_count_after: usize,
24522}
24523
24524fn render_diff_hunk_controls(
24525    row: u32,
24526    status: &DiffHunkStatus,
24527    hunk_range: Range<Anchor>,
24528    is_created_file: bool,
24529    line_height: Pixels,
24530    editor: &Entity<Editor>,
24531    _window: &mut Window,
24532    cx: &mut App,
24533) -> AnyElement {
24534    h_flex()
24535        .h(line_height)
24536        .mr_1()
24537        .gap_1()
24538        .px_0p5()
24539        .pb_1()
24540        .border_x_1()
24541        .border_b_1()
24542        .border_color(cx.theme().colors().border_variant)
24543        .rounded_b_lg()
24544        .bg(cx.theme().colors().editor_background)
24545        .gap_1()
24546        .block_mouse_except_scroll()
24547        .shadow_md()
24548        .child(if status.has_secondary_hunk() {
24549            Button::new(("stage", row as u64), "Stage")
24550                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24551                .tooltip({
24552                    let focus_handle = editor.focus_handle(cx);
24553                    move |window, cx| {
24554                        Tooltip::for_action_in(
24555                            "Stage Hunk",
24556                            &::git::ToggleStaged,
24557                            &focus_handle,
24558                            window,
24559                            cx,
24560                        )
24561                    }
24562                })
24563                .on_click({
24564                    let editor = editor.clone();
24565                    move |_event, _window, cx| {
24566                        editor.update(cx, |editor, cx| {
24567                            editor.stage_or_unstage_diff_hunks(
24568                                true,
24569                                vec![hunk_range.start..hunk_range.start],
24570                                cx,
24571                            );
24572                        });
24573                    }
24574                })
24575        } else {
24576            Button::new(("unstage", row as u64), "Unstage")
24577                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24578                .tooltip({
24579                    let focus_handle = editor.focus_handle(cx);
24580                    move |window, cx| {
24581                        Tooltip::for_action_in(
24582                            "Unstage Hunk",
24583                            &::git::ToggleStaged,
24584                            &focus_handle,
24585                            window,
24586                            cx,
24587                        )
24588                    }
24589                })
24590                .on_click({
24591                    let editor = editor.clone();
24592                    move |_event, _window, cx| {
24593                        editor.update(cx, |editor, cx| {
24594                            editor.stage_or_unstage_diff_hunks(
24595                                false,
24596                                vec![hunk_range.start..hunk_range.start],
24597                                cx,
24598                            );
24599                        });
24600                    }
24601                })
24602        })
24603        .child(
24604            Button::new(("restore", row as u64), "Restore")
24605                .tooltip({
24606                    let focus_handle = editor.focus_handle(cx);
24607                    move |window, cx| {
24608                        Tooltip::for_action_in(
24609                            "Restore Hunk",
24610                            &::git::Restore,
24611                            &focus_handle,
24612                            window,
24613                            cx,
24614                        )
24615                    }
24616                })
24617                .on_click({
24618                    let editor = editor.clone();
24619                    move |_event, window, cx| {
24620                        editor.update(cx, |editor, cx| {
24621                            let snapshot = editor.snapshot(window, cx);
24622                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24623                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24624                        });
24625                    }
24626                })
24627                .disabled(is_created_file),
24628        )
24629        .when(
24630            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24631            |el| {
24632                el.child(
24633                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24634                        .shape(IconButtonShape::Square)
24635                        .icon_size(IconSize::Small)
24636                        // .disabled(!has_multiple_hunks)
24637                        .tooltip({
24638                            let focus_handle = editor.focus_handle(cx);
24639                            move |window, cx| {
24640                                Tooltip::for_action_in(
24641                                    "Next Hunk",
24642                                    &GoToHunk,
24643                                    &focus_handle,
24644                                    window,
24645                                    cx,
24646                                )
24647                            }
24648                        })
24649                        .on_click({
24650                            let editor = editor.clone();
24651                            move |_event, window, cx| {
24652                                editor.update(cx, |editor, cx| {
24653                                    let snapshot = editor.snapshot(window, cx);
24654                                    let position =
24655                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24656                                    editor.go_to_hunk_before_or_after_position(
24657                                        &snapshot,
24658                                        position,
24659                                        Direction::Next,
24660                                        window,
24661                                        cx,
24662                                    );
24663                                    editor.expand_selected_diff_hunks(cx);
24664                                });
24665                            }
24666                        }),
24667                )
24668                .child(
24669                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24670                        .shape(IconButtonShape::Square)
24671                        .icon_size(IconSize::Small)
24672                        // .disabled(!has_multiple_hunks)
24673                        .tooltip({
24674                            let focus_handle = editor.focus_handle(cx);
24675                            move |window, cx| {
24676                                Tooltip::for_action_in(
24677                                    "Previous Hunk",
24678                                    &GoToPreviousHunk,
24679                                    &focus_handle,
24680                                    window,
24681                                    cx,
24682                                )
24683                            }
24684                        })
24685                        .on_click({
24686                            let editor = editor.clone();
24687                            move |_event, window, cx| {
24688                                editor.update(cx, |editor, cx| {
24689                                    let snapshot = editor.snapshot(window, cx);
24690                                    let point =
24691                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24692                                    editor.go_to_hunk_before_or_after_position(
24693                                        &snapshot,
24694                                        point,
24695                                        Direction::Prev,
24696                                        window,
24697                                        cx,
24698                                    );
24699                                    editor.expand_selected_diff_hunks(cx);
24700                                });
24701                            }
24702                        }),
24703                )
24704            },
24705        )
24706        .into_any_element()
24707}
24708
24709pub fn multibuffer_context_lines(cx: &App) -> u32 {
24710    EditorSettings::try_get(cx)
24711        .map(|settings| settings.excerpt_context_lines)
24712        .unwrap_or(2)
24713        .min(32)
24714}