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 element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlay_hint_cache;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   69    RowInfo, ToOffset, ToPoint,
   70};
   71pub use proposed_changes_editor::{
   72    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   73};
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79};
   80use aho_corasick::AhoCorasick;
   81use anyhow::{Context as _, Result, anyhow};
   82use blink_manager::BlinkManager;
   83use buffer_diff::DiffHunkStatus;
   84use client::{Collaborator, ParticipantIndex, parse_zed_link};
   85use clock::{AGENT_REPLICA_ID, ReplicaId};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   91use convert_case::{Case, Casing};
   92use dap::TelemetrySpawnLocation;
   93use display_map::*;
   94use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   95use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   96use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   97use futures::{
   98    FutureExt, StreamExt as _,
   99    future::{self, Shared, join},
  100    stream::FuturesUnordered,
  101};
  102use fuzzy::{StringMatch, StringMatchCandidate};
  103use git::blame::{GitBlame, GlobalBlameRenderer};
  104use gpui::{
  105    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  106    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  107    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  108    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  109    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  110    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  111    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  112    div, point, prelude::*, pulsating_between, px, relative, size,
  113};
  114use highlight_matching_bracket::refresh_matching_bracket_highlights;
  115use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  125    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  128        all_language_settings, language_settings,
  129    },
  130    point_from_lsp, point_to_lsp, text_diff_with_options,
  131};
  132use linked_editing_ranges::refresh_linked_ranges;
  133use lsp::{
  134    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  135    LanguageServerId,
  136};
  137use lsp_colors::LspColorData;
  138use markdown::Markdown;
  139use mouse_context_menu::MouseContextMenu;
  140use movement::TextLayoutDetails;
  141use multi_buffer::{
  142    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  143    ToOffsetUtf16,
  144};
  145use parking_lot::Mutex;
  146use persistence::DB;
  147use project::{
  148    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  149    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  150    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  151    ProjectTransaction, TaskSourceKind,
  152    debugger::{
  153        breakpoint_store::{
  154            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  155            BreakpointStore, BreakpointStoreEvent,
  156        },
  157        session::{Session, SessionEvent},
  158    },
  159    git_store::{GitStoreEvent, RepositoryEvent},
  160    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  161    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  162};
  163use rand::seq::SliceRandom;
  164use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  165use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  166use selections_collection::{
  167    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  168};
  169use serde::{Deserialize, Serialize};
  170use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  171use smallvec::{SmallVec, smallvec};
  172use snippet::Snippet;
  173use std::{
  174    any::{Any, TypeId},
  175    borrow::Cow,
  176    cell::{OnceCell, RefCell},
  177    cmp::{self, Ordering, Reverse},
  178    iter::{self, Peekable},
  179    mem,
  180    num::NonZeroU32,
  181    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  182    path::{Path, PathBuf},
  183    rc::Rc,
  184    sync::Arc,
  185    time::{Duration, Instant},
  186};
  187use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  188use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::{
  208    code_context_menus::CompletionsMenuSource,
  209    editor_settings::MultiCursorModifier,
  210    hover_links::{find_url, find_url_from_range},
  211    scroll::{ScrollOffset, ScrollPixelOffset},
  212    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  213};
  214
  215pub const FILE_HEADER_HEIGHT: u32 = 2;
  216pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  217const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  218const MAX_LINE_LEN: usize = 1024;
  219const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  220const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  221pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  222#[doc(hidden)]
  223pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  224pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  225
  226pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  227pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  229
  230pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  231pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  232pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  233
  234pub type RenderDiffHunkControlsFn = Arc<
  235    dyn Fn(
  236        u32,
  237        &DiffHunkStatus,
  238        Range<Anchor>,
  239        bool,
  240        Pixels,
  241        &Entity<Editor>,
  242        &mut Window,
  243        &mut App,
  244    ) -> AnyElement,
  245>;
  246
  247enum ReportEditorEvent {
  248    Saved { auto_saved: bool },
  249    EditorOpened,
  250    Closed,
  251}
  252
  253impl ReportEditorEvent {
  254    pub fn event_type(&self) -> &'static str {
  255        match self {
  256            Self::Saved { .. } => "Editor Saved",
  257            Self::EditorOpened => "Editor Opened",
  258            Self::Closed => "Editor Closed",
  259        }
  260    }
  261}
  262
  263struct InlineValueCache {
  264    enabled: bool,
  265    inlays: Vec<InlayId>,
  266    refresh_task: Task<Option<()>>,
  267}
  268
  269impl InlineValueCache {
  270    fn new(enabled: bool) -> Self {
  271        Self {
  272            enabled,
  273            inlays: Vec::new(),
  274            refresh_task: Task::ready(None),
  275        }
  276    }
  277}
  278
  279#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  280pub enum InlayId {
  281    EditPrediction(u32),
  282    DebuggerValue(u32),
  283    // LSP
  284    Hint(u32),
  285    Color(u32),
  286}
  287
  288impl InlayId {
  289    fn id(&self) -> u32 {
  290        match self {
  291            Self::EditPrediction(id) => *id,
  292            Self::DebuggerValue(id) => *id,
  293            Self::Hint(id) => *id,
  294            Self::Color(id) => *id,
  295        }
  296    }
  297}
  298
  299pub enum ActiveDebugLine {}
  300pub enum DebugStackFrameLine {}
  301enum DocumentHighlightRead {}
  302enum DocumentHighlightWrite {}
  303enum InputComposition {}
  304pub enum PendingInput {}
  305enum SelectedTextHighlight {}
  306
  307pub enum ConflictsOuter {}
  308pub enum ConflictsOurs {}
  309pub enum ConflictsTheirs {}
  310pub enum ConflictsOursMarker {}
  311pub enum ConflictsTheirsMarker {}
  312
  313#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  314pub enum Navigated {
  315    Yes,
  316    No,
  317}
  318
  319impl Navigated {
  320    pub fn from_bool(yes: bool) -> Navigated {
  321        if yes { Navigated::Yes } else { Navigated::No }
  322    }
  323}
  324
  325#[derive(Debug, Clone, PartialEq, Eq)]
  326enum DisplayDiffHunk {
  327    Folded {
  328        display_row: DisplayRow,
  329    },
  330    Unfolded {
  331        is_created_file: bool,
  332        diff_base_byte_range: Range<usize>,
  333        display_row_range: Range<DisplayRow>,
  334        multi_buffer_range: Range<Anchor>,
  335        status: DiffHunkStatus,
  336    },
  337}
  338
  339pub enum HideMouseCursorOrigin {
  340    TypingAction,
  341    MovementAction,
  342}
  343
  344pub fn init_settings(cx: &mut App) {
  345    EditorSettings::register(cx);
  346}
  347
  348pub fn init(cx: &mut App) {
  349    init_settings(cx);
  350
  351    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  352
  353    workspace::register_project_item::<Editor>(cx);
  354    workspace::FollowableViewRegistry::register::<Editor>(cx);
  355    workspace::register_serializable_item::<Editor>(cx);
  356
  357    cx.observe_new(
  358        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  359            workspace.register_action(Editor::new_file);
  360            workspace.register_action(Editor::new_file_vertical);
  361            workspace.register_action(Editor::new_file_horizontal);
  362            workspace.register_action(Editor::cancel_language_server_work);
  363            workspace.register_action(Editor::toggle_focus);
  364        },
  365    )
  366    .detach();
  367
  368    cx.on_action(move |_: &workspace::NewFile, cx| {
  369        let app_state = workspace::AppState::global(cx);
  370        if let Some(app_state) = app_state.upgrade() {
  371            workspace::open_new(
  372                Default::default(),
  373                app_state,
  374                cx,
  375                |workspace, window, cx| {
  376                    Editor::new_file(workspace, &Default::default(), window, cx)
  377                },
  378            )
  379            .detach();
  380        }
  381    });
  382    cx.on_action(move |_: &workspace::NewWindow, cx| {
  383        let app_state = workspace::AppState::global(cx);
  384        if let Some(app_state) = app_state.upgrade() {
  385            workspace::open_new(
  386                Default::default(),
  387                app_state,
  388                cx,
  389                |workspace, window, cx| {
  390                    cx.activate(true);
  391                    Editor::new_file(workspace, &Default::default(), window, cx)
  392                },
  393            )
  394            .detach();
  395        }
  396    });
  397}
  398
  399pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  400    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  401}
  402
  403pub trait DiagnosticRenderer {
  404    fn render_group(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  407        buffer_id: BufferId,
  408        snapshot: EditorSnapshot,
  409        editor: WeakEntity<Editor>,
  410        cx: &mut App,
  411    ) -> Vec<BlockProperties<Anchor>>;
  412
  413    fn render_hover(
  414        &self,
  415        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  416        range: Range<Point>,
  417        buffer_id: BufferId,
  418        cx: &mut App,
  419    ) -> Option<Entity<markdown::Markdown>>;
  420
  421    fn open_link(
  422        &self,
  423        editor: &mut Editor,
  424        link: SharedString,
  425        window: &mut Window,
  426        cx: &mut Context<Editor>,
  427    );
  428}
  429
  430pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  431
  432impl GlobalDiagnosticRenderer {
  433    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  434        cx.try_global::<Self>().map(|g| g.0.clone())
  435    }
  436}
  437
  438impl gpui::Global for GlobalDiagnosticRenderer {}
  439pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  440    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  441}
  442
  443pub struct SearchWithinRange;
  444
  445trait InvalidationRegion {
  446    fn ranges(&self) -> &[Range<Anchor>];
  447}
  448
  449#[derive(Clone, Debug, PartialEq)]
  450pub enum SelectPhase {
  451    Begin {
  452        position: DisplayPoint,
  453        add: bool,
  454        click_count: usize,
  455    },
  456    BeginColumnar {
  457        position: DisplayPoint,
  458        reset: bool,
  459        mode: ColumnarMode,
  460        goal_column: u32,
  461    },
  462    Extend {
  463        position: DisplayPoint,
  464        click_count: usize,
  465    },
  466    Update {
  467        position: DisplayPoint,
  468        goal_column: u32,
  469        scroll_delta: gpui::Point<f32>,
  470    },
  471    End,
  472}
  473
  474#[derive(Clone, Debug, PartialEq)]
  475pub enum ColumnarMode {
  476    FromMouse,
  477    FromSelection,
  478}
  479
  480#[derive(Clone, Debug)]
  481pub enum SelectMode {
  482    Character,
  483    Word(Range<Anchor>),
  484    Line(Range<Anchor>),
  485    All,
  486}
  487
  488#[derive(Clone, PartialEq, Eq, Debug)]
  489pub enum EditorMode {
  490    SingleLine,
  491    AutoHeight {
  492        min_lines: usize,
  493        max_lines: Option<usize>,
  494    },
  495    Full {
  496        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  497        scale_ui_elements_with_buffer_font_size: bool,
  498        /// When set to `true`, the editor will render a background for the active line.
  499        show_active_line_background: bool,
  500        /// When set to `true`, the editor's height will be determined by its content.
  501        sized_by_content: bool,
  502    },
  503    Minimap {
  504        parent: WeakEntity<Editor>,
  505    },
  506}
  507
  508impl EditorMode {
  509    pub fn full() -> Self {
  510        Self::Full {
  511            scale_ui_elements_with_buffer_font_size: true,
  512            show_active_line_background: true,
  513            sized_by_content: false,
  514        }
  515    }
  516
  517    #[inline]
  518    pub fn is_full(&self) -> bool {
  519        matches!(self, Self::Full { .. })
  520    }
  521
  522    #[inline]
  523    pub fn is_single_line(&self) -> bool {
  524        matches!(self, Self::SingleLine { .. })
  525    }
  526
  527    #[inline]
  528    fn is_minimap(&self) -> bool {
  529        matches!(self, Self::Minimap { .. })
  530    }
  531}
  532
  533#[derive(Copy, Clone, Debug)]
  534pub enum SoftWrap {
  535    /// Prefer not to wrap at all.
  536    ///
  537    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  538    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  539    GitDiff,
  540    /// Prefer a single line generally, unless an overly long line is encountered.
  541    None,
  542    /// Soft wrap lines that exceed the editor width.
  543    EditorWidth,
  544    /// Soft wrap lines at the preferred line length.
  545    Column(u32),
  546    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  547    Bounded(u32),
  548}
  549
  550#[derive(Clone)]
  551pub struct EditorStyle {
  552    pub background: Hsla,
  553    pub border: Hsla,
  554    pub local_player: PlayerColor,
  555    pub text: TextStyle,
  556    pub scrollbar_width: Pixels,
  557    pub syntax: Arc<SyntaxTheme>,
  558    pub status: StatusColors,
  559    pub inlay_hints_style: HighlightStyle,
  560    pub edit_prediction_styles: EditPredictionStyles,
  561    pub unnecessary_code_fade: f32,
  562    pub show_underlines: bool,
  563}
  564
  565impl Default for EditorStyle {
  566    fn default() -> Self {
  567        Self {
  568            background: Hsla::default(),
  569            border: Hsla::default(),
  570            local_player: PlayerColor::default(),
  571            text: TextStyle::default(),
  572            scrollbar_width: Pixels::default(),
  573            syntax: Default::default(),
  574            // HACK: Status colors don't have a real default.
  575            // We should look into removing the status colors from the editor
  576            // style and retrieve them directly from the theme.
  577            status: StatusColors::dark(),
  578            inlay_hints_style: HighlightStyle::default(),
  579            edit_prediction_styles: EditPredictionStyles {
  580                insertion: HighlightStyle::default(),
  581                whitespace: HighlightStyle::default(),
  582            },
  583            unnecessary_code_fade: Default::default(),
  584            show_underlines: true,
  585        }
  586    }
  587}
  588
  589pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  590    let show_background = language_settings::language_settings(None, None, cx)
  591        .inlay_hints
  592        .show_background;
  593
  594    let mut style = cx.theme().syntax().get("hint");
  595
  596    if style.color.is_none() {
  597        style.color = Some(cx.theme().status().hint);
  598    }
  599
  600    if !show_background {
  601        style.background_color = None;
  602        return style;
  603    }
  604
  605    if style.background_color.is_none() {
  606        style.background_color = Some(cx.theme().status().hint_background);
  607    }
  608
  609    style
  610}
  611
  612pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  613    EditPredictionStyles {
  614        insertion: HighlightStyle {
  615            color: Some(cx.theme().status().predictive),
  616            ..HighlightStyle::default()
  617        },
  618        whitespace: HighlightStyle {
  619            background_color: Some(cx.theme().status().created_background),
  620            ..HighlightStyle::default()
  621        },
  622    }
  623}
  624
  625type CompletionId = usize;
  626
  627pub(crate) enum EditDisplayMode {
  628    TabAccept,
  629    DiffPopover,
  630    Inline,
  631}
  632
  633enum EditPrediction {
  634    Edit {
  635        edits: Vec<(Range<Anchor>, String)>,
  636        edit_preview: Option<EditPreview>,
  637        display_mode: EditDisplayMode,
  638        snapshot: BufferSnapshot,
  639    },
  640    /// Move to a specific location in the active editor
  641    MoveWithin {
  642        target: Anchor,
  643        snapshot: BufferSnapshot,
  644    },
  645    /// Move to a specific location in a different editor (not the active one)
  646    MoveOutside {
  647        target: language::Anchor,
  648        snapshot: BufferSnapshot,
  649    },
  650}
  651
  652struct EditPredictionState {
  653    inlay_ids: Vec<InlayId>,
  654    completion: EditPrediction,
  655    completion_id: Option<SharedString>,
  656    invalidation_range: Option<Range<Anchor>>,
  657}
  658
  659enum EditPredictionSettings {
  660    Disabled,
  661    Enabled {
  662        show_in_menu: bool,
  663        preview_requires_modifier: bool,
  664    },
  665}
  666
  667enum EditPredictionHighlight {}
  668
  669#[derive(Debug, Clone)]
  670struct InlineDiagnostic {
  671    message: SharedString,
  672    group_id: usize,
  673    is_primary: bool,
  674    start: Point,
  675    severity: lsp::DiagnosticSeverity,
  676}
  677
  678pub enum MenuEditPredictionsPolicy {
  679    Never,
  680    ByProvider,
  681}
  682
  683pub enum EditPredictionPreview {
  684    /// Modifier is not pressed
  685    Inactive { released_too_fast: bool },
  686    /// Modifier pressed
  687    Active {
  688        since: Instant,
  689        previous_scroll_position: Option<ScrollAnchor>,
  690    },
  691}
  692
  693impl EditPredictionPreview {
  694    pub fn released_too_fast(&self) -> bool {
  695        match self {
  696            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  697            EditPredictionPreview::Active { .. } => false,
  698        }
  699    }
  700
  701    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  702        if let EditPredictionPreview::Active {
  703            previous_scroll_position,
  704            ..
  705        } = self
  706        {
  707            *previous_scroll_position = scroll_position;
  708        }
  709    }
  710}
  711
  712pub struct ContextMenuOptions {
  713    pub min_entries_visible: usize,
  714    pub max_entries_visible: usize,
  715    pub placement: Option<ContextMenuPlacement>,
  716}
  717
  718#[derive(Debug, Clone, PartialEq, Eq)]
  719pub enum ContextMenuPlacement {
  720    Above,
  721    Below,
  722}
  723
  724#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  725struct EditorActionId(usize);
  726
  727impl EditorActionId {
  728    pub fn post_inc(&mut self) -> Self {
  729        let answer = self.0;
  730
  731        *self = Self(answer + 1);
  732
  733        Self(answer)
  734    }
  735}
  736
  737// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  738// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  739
  740type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  741type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  742
  743#[derive(Default)]
  744struct ScrollbarMarkerState {
  745    scrollbar_size: Size<Pixels>,
  746    dirty: bool,
  747    markers: Arc<[PaintQuad]>,
  748    pending_refresh: Option<Task<Result<()>>>,
  749}
  750
  751impl ScrollbarMarkerState {
  752    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  753        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  754    }
  755}
  756
  757#[derive(Clone, Copy, PartialEq, Eq)]
  758pub enum MinimapVisibility {
  759    Disabled,
  760    Enabled {
  761        /// The configuration currently present in the users settings.
  762        setting_configuration: bool,
  763        /// Whether to override the currently set visibility from the users setting.
  764        toggle_override: bool,
  765    },
  766}
  767
  768impl MinimapVisibility {
  769    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  770        if mode.is_full() {
  771            Self::Enabled {
  772                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  773                toggle_override: false,
  774            }
  775        } else {
  776            Self::Disabled
  777        }
  778    }
  779
  780    fn hidden(&self) -> Self {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => Self::Enabled {
  786                setting_configuration,
  787                toggle_override: setting_configuration,
  788            },
  789            Self::Disabled => Self::Disabled,
  790        }
  791    }
  792
  793    fn disabled(&self) -> bool {
  794        matches!(*self, Self::Disabled)
  795    }
  796
  797    fn settings_visibility(&self) -> bool {
  798        match *self {
  799            Self::Enabled {
  800                setting_configuration,
  801                ..
  802            } => setting_configuration,
  803            _ => false,
  804        }
  805    }
  806
  807    fn visible(&self) -> bool {
  808        match *self {
  809            Self::Enabled {
  810                setting_configuration,
  811                toggle_override,
  812            } => setting_configuration ^ toggle_override,
  813            _ => false,
  814        }
  815    }
  816
  817    fn toggle_visibility(&self) -> Self {
  818        match *self {
  819            Self::Enabled {
  820                toggle_override,
  821                setting_configuration,
  822            } => Self::Enabled {
  823                setting_configuration,
  824                toggle_override: !toggle_override,
  825            },
  826            Self::Disabled => Self::Disabled,
  827        }
  828    }
  829}
  830
  831#[derive(Clone, Debug)]
  832struct RunnableTasks {
  833    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  834    offset: multi_buffer::Anchor,
  835    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  836    column: u32,
  837    // Values of all named captures, including those starting with '_'
  838    extra_variables: HashMap<String, String>,
  839    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  840    context_range: Range<BufferOffset>,
  841}
  842
  843impl RunnableTasks {
  844    fn resolve<'a>(
  845        &'a self,
  846        cx: &'a task::TaskContext,
  847    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  848        self.templates.iter().filter_map(|(kind, template)| {
  849            template
  850                .resolve_task(&kind.to_id_base(), cx)
  851                .map(|task| (kind.clone(), task))
  852        })
  853    }
  854}
  855
  856#[derive(Clone)]
  857pub struct ResolvedTasks {
  858    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  859    position: Anchor,
  860}
  861
  862#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  863struct BufferOffset(usize);
  864
  865/// Addons allow storing per-editor state in other crates (e.g. Vim)
  866pub trait Addon: 'static {
  867    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  868
  869    fn render_buffer_header_controls(
  870        &self,
  871        _: &ExcerptInfo,
  872        _: &Window,
  873        _: &App,
  874    ) -> Option<AnyElement> {
  875        None
  876    }
  877
  878    fn to_any(&self) -> &dyn std::any::Any;
  879
  880    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  881        None
  882    }
  883}
  884
  885struct ChangeLocation {
  886    current: Option<Vec<Anchor>>,
  887    original: Vec<Anchor>,
  888}
  889impl ChangeLocation {
  890    fn locations(&self) -> &[Anchor] {
  891        self.current.as_ref().unwrap_or(&self.original)
  892    }
  893}
  894
  895/// A set of caret positions, registered when the editor was edited.
  896pub struct ChangeList {
  897    changes: Vec<ChangeLocation>,
  898    /// Currently "selected" change.
  899    position: Option<usize>,
  900}
  901
  902impl ChangeList {
  903    pub fn new() -> Self {
  904        Self {
  905            changes: Vec::new(),
  906            position: None,
  907        }
  908    }
  909
  910    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  911    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  912    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  913        if self.changes.is_empty() {
  914            return None;
  915        }
  916
  917        let prev = self.position.unwrap_or(self.changes.len());
  918        let next = if direction == Direction::Prev {
  919            prev.saturating_sub(count)
  920        } else {
  921            (prev + count).min(self.changes.len() - 1)
  922        };
  923        self.position = Some(next);
  924        self.changes.get(next).map(|change| change.locations())
  925    }
  926
  927    /// Adds a new change to the list, resetting the change list position.
  928    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  929        self.position.take();
  930        if let Some(last) = self.changes.last_mut()
  931            && group
  932        {
  933            last.current = Some(new_positions)
  934        } else {
  935            self.changes.push(ChangeLocation {
  936                original: new_positions,
  937                current: None,
  938            });
  939        }
  940    }
  941
  942    pub fn last(&self) -> Option<&[Anchor]> {
  943        self.changes.last().map(|change| change.locations())
  944    }
  945
  946    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  947        self.changes.last().map(|change| change.original.as_slice())
  948    }
  949
  950    pub fn invert_last_group(&mut self) {
  951        if let Some(last) = self.changes.last_mut()
  952            && let Some(current) = last.current.as_mut()
  953        {
  954            mem::swap(&mut last.original, current);
  955        }
  956    }
  957}
  958
  959#[derive(Clone)]
  960struct InlineBlamePopoverState {
  961    scroll_handle: ScrollHandle,
  962    commit_message: Option<ParsedCommitMessage>,
  963    markdown: Entity<Markdown>,
  964}
  965
  966struct InlineBlamePopover {
  967    position: gpui::Point<Pixels>,
  968    hide_task: Option<Task<()>>,
  969    popover_bounds: Option<Bounds<Pixels>>,
  970    popover_state: InlineBlamePopoverState,
  971    keyboard_grace: bool,
  972}
  973
  974enum SelectionDragState {
  975    /// State when no drag related activity is detected.
  976    None,
  977    /// State when the mouse is down on a selection that is about to be dragged.
  978    ReadyToDrag {
  979        selection: Selection<Anchor>,
  980        click_position: gpui::Point<Pixels>,
  981        mouse_down_time: Instant,
  982    },
  983    /// State when the mouse is dragging the selection in the editor.
  984    Dragging {
  985        selection: Selection<Anchor>,
  986        drop_cursor: Selection<Anchor>,
  987        hide_drop_cursor: bool,
  988    },
  989}
  990
  991enum ColumnarSelectionState {
  992    FromMouse {
  993        selection_tail: Anchor,
  994        display_point: Option<DisplayPoint>,
  995    },
  996    FromSelection {
  997        selection_tail: Anchor,
  998    },
  999}
 1000
 1001/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1002/// a breakpoint on them.
 1003#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1004struct PhantomBreakpointIndicator {
 1005    display_row: DisplayRow,
 1006    /// There's a small debounce between hovering over the line and showing the indicator.
 1007    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1008    is_active: bool,
 1009    collides_with_existing_breakpoint: bool,
 1010}
 1011
 1012/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1013///
 1014/// See the [module level documentation](self) for more information.
 1015pub struct Editor {
 1016    focus_handle: FocusHandle,
 1017    last_focused_descendant: Option<WeakFocusHandle>,
 1018    /// The text buffer being edited
 1019    buffer: Entity<MultiBuffer>,
 1020    /// Map of how text in the buffer should be displayed.
 1021    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1022    pub display_map: Entity<DisplayMap>,
 1023    placeholder_display_map: Option<Entity<DisplayMap>>,
 1024    pub selections: SelectionsCollection,
 1025    pub scroll_manager: ScrollManager,
 1026    /// When inline assist editors are linked, they all render cursors because
 1027    /// typing enters text into each of them, even the ones that aren't focused.
 1028    pub(crate) show_cursor_when_unfocused: bool,
 1029    columnar_selection_state: Option<ColumnarSelectionState>,
 1030    add_selections_state: Option<AddSelectionsState>,
 1031    select_next_state: Option<SelectNextState>,
 1032    select_prev_state: Option<SelectNextState>,
 1033    selection_history: SelectionHistory,
 1034    defer_selection_effects: bool,
 1035    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1036    autoclose_regions: Vec<AutocloseRegion>,
 1037    snippet_stack: InvalidationStack<SnippetState>,
 1038    select_syntax_node_history: SelectSyntaxNodeHistory,
 1039    ime_transaction: Option<TransactionId>,
 1040    pub diagnostics_max_severity: DiagnosticSeverity,
 1041    active_diagnostics: ActiveDiagnostic,
 1042    show_inline_diagnostics: bool,
 1043    inline_diagnostics_update: Task<()>,
 1044    inline_diagnostics_enabled: bool,
 1045    diagnostics_enabled: bool,
 1046    word_completions_enabled: bool,
 1047    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1048    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1049    hard_wrap: Option<usize>,
 1050    project: Option<Entity<Project>>,
 1051    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1052    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1053    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1054    blink_manager: Entity<BlinkManager>,
 1055    show_cursor_names: bool,
 1056    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1057    pub show_local_selections: bool,
 1058    mode: EditorMode,
 1059    show_breadcrumbs: bool,
 1060    show_gutter: bool,
 1061    show_scrollbars: ScrollbarAxes,
 1062    minimap_visibility: MinimapVisibility,
 1063    offset_content: bool,
 1064    disable_expand_excerpt_buttons: bool,
 1065    show_line_numbers: Option<bool>,
 1066    use_relative_line_numbers: Option<bool>,
 1067    show_git_diff_gutter: Option<bool>,
 1068    show_code_actions: Option<bool>,
 1069    show_runnables: Option<bool>,
 1070    show_breakpoints: Option<bool>,
 1071    show_wrap_guides: Option<bool>,
 1072    show_indent_guides: Option<bool>,
 1073    highlight_order: usize,
 1074    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1075    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1076    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1077    scrollbar_marker_state: ScrollbarMarkerState,
 1078    active_indent_guides_state: ActiveIndentGuidesState,
 1079    nav_history: Option<ItemNavHistory>,
 1080    context_menu: RefCell<Option<CodeContextMenu>>,
 1081    context_menu_options: Option<ContextMenuOptions>,
 1082    mouse_context_menu: Option<MouseContextMenu>,
 1083    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1084    inline_blame_popover: Option<InlineBlamePopover>,
 1085    inline_blame_popover_show_task: Option<Task<()>>,
 1086    signature_help_state: SignatureHelpState,
 1087    auto_signature_help: Option<bool>,
 1088    find_all_references_task_sources: Vec<Anchor>,
 1089    next_completion_id: CompletionId,
 1090    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1091    code_actions_task: Option<Task<Result<()>>>,
 1092    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1093    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    document_highlights_task: Option<Task<()>>,
 1095    linked_editing_range_task: Option<Task<Option<()>>>,
 1096    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1097    pending_rename: Option<RenameState>,
 1098    searchable: bool,
 1099    cursor_shape: CursorShape,
 1100    current_line_highlight: Option<CurrentLineHighlight>,
 1101    collapse_matches: bool,
 1102    autoindent_mode: Option<AutoindentMode>,
 1103    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1104    input_enabled: bool,
 1105    use_modal_editing: bool,
 1106    read_only: bool,
 1107    leader_id: Option<CollaboratorId>,
 1108    remote_id: Option<ViewId>,
 1109    pub hover_state: HoverState,
 1110    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1111    gutter_hovered: bool,
 1112    hovered_link_state: Option<HoveredLinkState>,
 1113    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1114    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1115    active_edit_prediction: Option<EditPredictionState>,
 1116    /// Used to prevent flickering as the user types while the menu is open
 1117    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1118    edit_prediction_settings: EditPredictionSettings,
 1119    edit_predictions_hidden_for_vim_mode: bool,
 1120    show_edit_predictions_override: Option<bool>,
 1121    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1122    edit_prediction_preview: EditPredictionPreview,
 1123    edit_prediction_indent_conflict: bool,
 1124    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1125    inlay_hint_cache: InlayHintCache,
 1126    next_inlay_id: u32,
 1127    next_color_inlay_id: u32,
 1128    _subscriptions: Vec<Subscription>,
 1129    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1130    gutter_dimensions: GutterDimensions,
 1131    style: Option<EditorStyle>,
 1132    text_style_refinement: Option<TextStyleRefinement>,
 1133    next_editor_action_id: EditorActionId,
 1134    editor_actions: Rc<
 1135        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1136    >,
 1137    use_autoclose: bool,
 1138    use_auto_surround: bool,
 1139    auto_replace_emoji_shortcode: bool,
 1140    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1141    show_git_blame_gutter: bool,
 1142    show_git_blame_inline: bool,
 1143    show_git_blame_inline_delay_task: Option<Task<()>>,
 1144    git_blame_inline_enabled: bool,
 1145    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1146    serialize_dirty_buffers: bool,
 1147    show_selection_menu: Option<bool>,
 1148    blame: Option<Entity<GitBlame>>,
 1149    blame_subscription: Option<Subscription>,
 1150    custom_context_menu: Option<
 1151        Box<
 1152            dyn 'static
 1153                + Fn(
 1154                    &mut Self,
 1155                    DisplayPoint,
 1156                    &mut Window,
 1157                    &mut Context<Self>,
 1158                ) -> Option<Entity<ui::ContextMenu>>,
 1159        >,
 1160    >,
 1161    last_bounds: Option<Bounds<Pixels>>,
 1162    last_position_map: Option<Rc<PositionMap>>,
 1163    expect_bounds_change: Option<Bounds<Pixels>>,
 1164    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1165    tasks_update_task: Option<Task<()>>,
 1166    breakpoint_store: Option<Entity<BreakpointStore>>,
 1167    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1168    hovered_diff_hunk_row: Option<DisplayRow>,
 1169    pull_diagnostics_task: Task<()>,
 1170    in_project_search: bool,
 1171    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1172    breadcrumb_header: Option<String>,
 1173    focused_block: Option<FocusedBlock>,
 1174    next_scroll_position: NextScrollCursorCenterTopBottom,
 1175    addons: HashMap<TypeId, Box<dyn Addon>>,
 1176    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1177    load_diff_task: Option<Shared<Task<()>>>,
 1178    /// Whether we are temporarily displaying a diff other than git's
 1179    temporary_diff_override: bool,
 1180    selection_mark_mode: bool,
 1181    toggle_fold_multiple_buffers: Task<()>,
 1182    _scroll_cursor_center_top_bottom_task: Task<()>,
 1183    serialize_selections: Task<()>,
 1184    serialize_folds: Task<()>,
 1185    mouse_cursor_hidden: bool,
 1186    minimap: Option<Entity<Self>>,
 1187    hide_mouse_mode: HideMouseMode,
 1188    pub change_list: ChangeList,
 1189    inline_value_cache: InlineValueCache,
 1190    selection_drag_state: SelectionDragState,
 1191    colors: Option<LspColorData>,
 1192    folding_newlines: Task<()>,
 1193    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1194}
 1195
 1196#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1197enum NextScrollCursorCenterTopBottom {
 1198    #[default]
 1199    Center,
 1200    Top,
 1201    Bottom,
 1202}
 1203
 1204impl NextScrollCursorCenterTopBottom {
 1205    fn next(&self) -> Self {
 1206        match self {
 1207            Self::Center => Self::Top,
 1208            Self::Top => Self::Bottom,
 1209            Self::Bottom => Self::Center,
 1210        }
 1211    }
 1212}
 1213
 1214#[derive(Clone)]
 1215pub struct EditorSnapshot {
 1216    pub mode: EditorMode,
 1217    show_gutter: bool,
 1218    show_line_numbers: Option<bool>,
 1219    show_git_diff_gutter: Option<bool>,
 1220    show_code_actions: Option<bool>,
 1221    show_runnables: Option<bool>,
 1222    show_breakpoints: Option<bool>,
 1223    git_blame_gutter_max_author_length: Option<usize>,
 1224    pub display_snapshot: DisplaySnapshot,
 1225    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1226    is_focused: bool,
 1227    scroll_anchor: ScrollAnchor,
 1228    ongoing_scroll: OngoingScroll,
 1229    current_line_highlight: CurrentLineHighlight,
 1230    gutter_hovered: bool,
 1231}
 1232
 1233#[derive(Default, Debug, Clone, Copy)]
 1234pub struct GutterDimensions {
 1235    pub left_padding: Pixels,
 1236    pub right_padding: Pixels,
 1237    pub width: Pixels,
 1238    pub margin: Pixels,
 1239    pub git_blame_entries_width: Option<Pixels>,
 1240}
 1241
 1242impl GutterDimensions {
 1243    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1244        Self {
 1245            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1246            ..Default::default()
 1247        }
 1248    }
 1249
 1250    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1251        -cx.text_system().descent(font_id, font_size)
 1252    }
 1253    /// The full width of the space taken up by the gutter.
 1254    pub fn full_width(&self) -> Pixels {
 1255        self.margin + self.width
 1256    }
 1257
 1258    /// The width of the space reserved for the fold indicators,
 1259    /// use alongside 'justify_end' and `gutter_width` to
 1260    /// right align content with the line numbers
 1261    pub fn fold_area_width(&self) -> Pixels {
 1262        self.margin + self.right_padding
 1263    }
 1264}
 1265
 1266struct CharacterDimensions {
 1267    em_width: Pixels,
 1268    em_advance: Pixels,
 1269    line_height: Pixels,
 1270}
 1271
 1272#[derive(Debug)]
 1273pub struct RemoteSelection {
 1274    pub replica_id: ReplicaId,
 1275    pub selection: Selection<Anchor>,
 1276    pub cursor_shape: CursorShape,
 1277    pub collaborator_id: CollaboratorId,
 1278    pub line_mode: bool,
 1279    pub user_name: Option<SharedString>,
 1280    pub color: PlayerColor,
 1281}
 1282
 1283#[derive(Clone, Debug)]
 1284struct SelectionHistoryEntry {
 1285    selections: Arc<[Selection<Anchor>]>,
 1286    select_next_state: Option<SelectNextState>,
 1287    select_prev_state: Option<SelectNextState>,
 1288    add_selections_state: Option<AddSelectionsState>,
 1289}
 1290
 1291#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1292enum SelectionHistoryMode {
 1293    Normal,
 1294    Undoing,
 1295    Redoing,
 1296    Skipping,
 1297}
 1298
 1299#[derive(Clone, PartialEq, Eq, Hash)]
 1300struct HoveredCursor {
 1301    replica_id: u16,
 1302    selection_id: usize,
 1303}
 1304
 1305impl Default for SelectionHistoryMode {
 1306    fn default() -> Self {
 1307        Self::Normal
 1308    }
 1309}
 1310
 1311#[derive(Debug)]
 1312/// SelectionEffects controls the side-effects of updating the selection.
 1313///
 1314/// The default behaviour does "what you mostly want":
 1315/// - it pushes to the nav history if the cursor moved by >10 lines
 1316/// - it re-triggers completion requests
 1317/// - it scrolls to fit
 1318///
 1319/// You might want to modify these behaviours. For example when doing a "jump"
 1320/// like go to definition, we always want to add to nav history; but when scrolling
 1321/// in vim mode we never do.
 1322///
 1323/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1324/// move.
 1325#[derive(Clone)]
 1326pub struct SelectionEffects {
 1327    nav_history: Option<bool>,
 1328    completions: bool,
 1329    scroll: Option<Autoscroll>,
 1330}
 1331
 1332impl Default for SelectionEffects {
 1333    fn default() -> Self {
 1334        Self {
 1335            nav_history: None,
 1336            completions: true,
 1337            scroll: Some(Autoscroll::fit()),
 1338        }
 1339    }
 1340}
 1341impl SelectionEffects {
 1342    pub fn scroll(scroll: Autoscroll) -> Self {
 1343        Self {
 1344            scroll: Some(scroll),
 1345            ..Default::default()
 1346        }
 1347    }
 1348
 1349    pub fn no_scroll() -> Self {
 1350        Self {
 1351            scroll: None,
 1352            ..Default::default()
 1353        }
 1354    }
 1355
 1356    pub fn completions(self, completions: bool) -> Self {
 1357        Self {
 1358            completions,
 1359            ..self
 1360        }
 1361    }
 1362
 1363    pub fn nav_history(self, nav_history: bool) -> Self {
 1364        Self {
 1365            nav_history: Some(nav_history),
 1366            ..self
 1367        }
 1368    }
 1369}
 1370
 1371struct DeferredSelectionEffectsState {
 1372    changed: bool,
 1373    effects: SelectionEffects,
 1374    old_cursor_position: Anchor,
 1375    history_entry: SelectionHistoryEntry,
 1376}
 1377
 1378#[derive(Default)]
 1379struct SelectionHistory {
 1380    #[allow(clippy::type_complexity)]
 1381    selections_by_transaction:
 1382        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1383    mode: SelectionHistoryMode,
 1384    undo_stack: VecDeque<SelectionHistoryEntry>,
 1385    redo_stack: VecDeque<SelectionHistoryEntry>,
 1386}
 1387
 1388impl SelectionHistory {
 1389    #[track_caller]
 1390    fn insert_transaction(
 1391        &mut self,
 1392        transaction_id: TransactionId,
 1393        selections: Arc<[Selection<Anchor>]>,
 1394    ) {
 1395        if selections.is_empty() {
 1396            log::error!(
 1397                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1398                std::panic::Location::caller()
 1399            );
 1400            return;
 1401        }
 1402        self.selections_by_transaction
 1403            .insert(transaction_id, (selections, None));
 1404    }
 1405
 1406    #[allow(clippy::type_complexity)]
 1407    fn transaction(
 1408        &self,
 1409        transaction_id: TransactionId,
 1410    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1411        self.selections_by_transaction.get(&transaction_id)
 1412    }
 1413
 1414    #[allow(clippy::type_complexity)]
 1415    fn transaction_mut(
 1416        &mut self,
 1417        transaction_id: TransactionId,
 1418    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1419        self.selections_by_transaction.get_mut(&transaction_id)
 1420    }
 1421
 1422    fn push(&mut self, entry: SelectionHistoryEntry) {
 1423        if !entry.selections.is_empty() {
 1424            match self.mode {
 1425                SelectionHistoryMode::Normal => {
 1426                    self.push_undo(entry);
 1427                    self.redo_stack.clear();
 1428                }
 1429                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1430                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1431                SelectionHistoryMode::Skipping => {}
 1432            }
 1433        }
 1434    }
 1435
 1436    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1437        if self
 1438            .undo_stack
 1439            .back()
 1440            .is_none_or(|e| e.selections != entry.selections)
 1441        {
 1442            self.undo_stack.push_back(entry);
 1443            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1444                self.undo_stack.pop_front();
 1445            }
 1446        }
 1447    }
 1448
 1449    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1450        if self
 1451            .redo_stack
 1452            .back()
 1453            .is_none_or(|e| e.selections != entry.selections)
 1454        {
 1455            self.redo_stack.push_back(entry);
 1456            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1457                self.redo_stack.pop_front();
 1458            }
 1459        }
 1460    }
 1461}
 1462
 1463#[derive(Clone, Copy)]
 1464pub struct RowHighlightOptions {
 1465    pub autoscroll: bool,
 1466    pub include_gutter: bool,
 1467}
 1468
 1469impl Default for RowHighlightOptions {
 1470    fn default() -> Self {
 1471        Self {
 1472            autoscroll: Default::default(),
 1473            include_gutter: true,
 1474        }
 1475    }
 1476}
 1477
 1478struct RowHighlight {
 1479    index: usize,
 1480    range: Range<Anchor>,
 1481    color: Hsla,
 1482    options: RowHighlightOptions,
 1483    type_id: TypeId,
 1484}
 1485
 1486#[derive(Clone, Debug)]
 1487struct AddSelectionsState {
 1488    groups: Vec<AddSelectionsGroup>,
 1489}
 1490
 1491#[derive(Clone, Debug)]
 1492struct AddSelectionsGroup {
 1493    above: bool,
 1494    stack: Vec<usize>,
 1495}
 1496
 1497#[derive(Clone)]
 1498struct SelectNextState {
 1499    query: AhoCorasick,
 1500    wordwise: bool,
 1501    done: bool,
 1502}
 1503
 1504impl std::fmt::Debug for SelectNextState {
 1505    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1506        f.debug_struct(std::any::type_name::<Self>())
 1507            .field("wordwise", &self.wordwise)
 1508            .field("done", &self.done)
 1509            .finish()
 1510    }
 1511}
 1512
 1513#[derive(Debug)]
 1514struct AutocloseRegion {
 1515    selection_id: usize,
 1516    range: Range<Anchor>,
 1517    pair: BracketPair,
 1518}
 1519
 1520#[derive(Debug)]
 1521struct SnippetState {
 1522    ranges: Vec<Vec<Range<Anchor>>>,
 1523    active_index: usize,
 1524    choices: Vec<Option<Vec<String>>>,
 1525}
 1526
 1527#[doc(hidden)]
 1528pub struct RenameState {
 1529    pub range: Range<Anchor>,
 1530    pub old_name: Arc<str>,
 1531    pub editor: Entity<Editor>,
 1532    block_id: CustomBlockId,
 1533}
 1534
 1535struct InvalidationStack<T>(Vec<T>);
 1536
 1537struct RegisteredEditPredictionProvider {
 1538    provider: Arc<dyn EditPredictionProviderHandle>,
 1539    _subscription: Subscription,
 1540}
 1541
 1542#[derive(Debug, PartialEq, Eq)]
 1543pub struct ActiveDiagnosticGroup {
 1544    pub active_range: Range<Anchor>,
 1545    pub active_message: String,
 1546    pub group_id: usize,
 1547    pub blocks: HashSet<CustomBlockId>,
 1548}
 1549
 1550#[derive(Debug, PartialEq, Eq)]
 1551
 1552pub(crate) enum ActiveDiagnostic {
 1553    None,
 1554    All,
 1555    Group(ActiveDiagnosticGroup),
 1556}
 1557
 1558#[derive(Serialize, Deserialize, Clone, Debug)]
 1559pub struct ClipboardSelection {
 1560    /// The number of bytes in this selection.
 1561    pub len: usize,
 1562    /// Whether this was a full-line selection.
 1563    pub is_entire_line: bool,
 1564    /// The indentation of the first line when this content was originally copied.
 1565    pub first_line_indent: u32,
 1566}
 1567
 1568// selections, scroll behavior, was newest selection reversed
 1569type SelectSyntaxNodeHistoryState = (
 1570    Box<[Selection<usize>]>,
 1571    SelectSyntaxNodeScrollBehavior,
 1572    bool,
 1573);
 1574
 1575#[derive(Default)]
 1576struct SelectSyntaxNodeHistory {
 1577    stack: Vec<SelectSyntaxNodeHistoryState>,
 1578    // disable temporarily to allow changing selections without losing the stack
 1579    pub disable_clearing: bool,
 1580}
 1581
 1582impl SelectSyntaxNodeHistory {
 1583    pub fn try_clear(&mut self) {
 1584        if !self.disable_clearing {
 1585            self.stack.clear();
 1586        }
 1587    }
 1588
 1589    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1590        self.stack.push(selection);
 1591    }
 1592
 1593    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1594        self.stack.pop()
 1595    }
 1596}
 1597
 1598enum SelectSyntaxNodeScrollBehavior {
 1599    CursorTop,
 1600    FitSelection,
 1601    CursorBottom,
 1602}
 1603
 1604#[derive(Debug)]
 1605pub(crate) struct NavigationData {
 1606    cursor_anchor: Anchor,
 1607    cursor_position: Point,
 1608    scroll_anchor: ScrollAnchor,
 1609    scroll_top_row: u32,
 1610}
 1611
 1612#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1613pub enum GotoDefinitionKind {
 1614    Symbol,
 1615    Declaration,
 1616    Type,
 1617    Implementation,
 1618}
 1619
 1620#[derive(Debug, Clone)]
 1621enum InlayHintRefreshReason {
 1622    ModifiersChanged(bool),
 1623    Toggle(bool),
 1624    SettingsChange(InlayHintSettings),
 1625    NewLinesShown,
 1626    BufferEdited(HashSet<Arc<Language>>),
 1627    RefreshRequested,
 1628    ExcerptsRemoved(Vec<ExcerptId>),
 1629}
 1630
 1631impl InlayHintRefreshReason {
 1632    fn description(&self) -> &'static str {
 1633        match self {
 1634            Self::ModifiersChanged(_) => "modifiers changed",
 1635            Self::Toggle(_) => "toggle",
 1636            Self::SettingsChange(_) => "settings change",
 1637            Self::NewLinesShown => "new lines shown",
 1638            Self::BufferEdited(_) => "buffer edited",
 1639            Self::RefreshRequested => "refresh requested",
 1640            Self::ExcerptsRemoved(_) => "excerpts removed",
 1641        }
 1642    }
 1643}
 1644
 1645pub enum FormatTarget {
 1646    Buffers(HashSet<Entity<Buffer>>),
 1647    Ranges(Vec<Range<MultiBufferPoint>>),
 1648}
 1649
 1650pub(crate) struct FocusedBlock {
 1651    id: BlockId,
 1652    focus_handle: WeakFocusHandle,
 1653}
 1654
 1655#[derive(Clone)]
 1656enum JumpData {
 1657    MultiBufferRow {
 1658        row: MultiBufferRow,
 1659        line_offset_from_top: u32,
 1660    },
 1661    MultiBufferPoint {
 1662        excerpt_id: ExcerptId,
 1663        position: Point,
 1664        anchor: text::Anchor,
 1665        line_offset_from_top: u32,
 1666    },
 1667}
 1668
 1669pub enum MultibufferSelectionMode {
 1670    First,
 1671    All,
 1672}
 1673
 1674#[derive(Clone, Copy, Debug, Default)]
 1675pub struct RewrapOptions {
 1676    pub override_language_settings: bool,
 1677    pub preserve_existing_whitespace: bool,
 1678}
 1679
 1680impl Editor {
 1681    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1682        let buffer = cx.new(|cx| Buffer::local("", cx));
 1683        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1684        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1685    }
 1686
 1687    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1688        let buffer = cx.new(|cx| Buffer::local("", cx));
 1689        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1690        Self::new(EditorMode::full(), buffer, None, window, cx)
 1691    }
 1692
 1693    pub fn auto_height(
 1694        min_lines: usize,
 1695        max_lines: usize,
 1696        window: &mut Window,
 1697        cx: &mut Context<Self>,
 1698    ) -> Self {
 1699        let buffer = cx.new(|cx| Buffer::local("", cx));
 1700        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1701        Self::new(
 1702            EditorMode::AutoHeight {
 1703                min_lines,
 1704                max_lines: Some(max_lines),
 1705            },
 1706            buffer,
 1707            None,
 1708            window,
 1709            cx,
 1710        )
 1711    }
 1712
 1713    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1714    /// The editor grows as tall as needed to fit its content.
 1715    pub fn auto_height_unbounded(
 1716        min_lines: usize,
 1717        window: &mut Window,
 1718        cx: &mut Context<Self>,
 1719    ) -> Self {
 1720        let buffer = cx.new(|cx| Buffer::local("", cx));
 1721        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1722        Self::new(
 1723            EditorMode::AutoHeight {
 1724                min_lines,
 1725                max_lines: None,
 1726            },
 1727            buffer,
 1728            None,
 1729            window,
 1730            cx,
 1731        )
 1732    }
 1733
 1734    pub fn for_buffer(
 1735        buffer: Entity<Buffer>,
 1736        project: Option<Entity<Project>>,
 1737        window: &mut Window,
 1738        cx: &mut Context<Self>,
 1739    ) -> Self {
 1740        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1741        Self::new(EditorMode::full(), buffer, project, window, cx)
 1742    }
 1743
 1744    pub fn for_multibuffer(
 1745        buffer: Entity<MultiBuffer>,
 1746        project: Option<Entity<Project>>,
 1747        window: &mut Window,
 1748        cx: &mut Context<Self>,
 1749    ) -> Self {
 1750        Self::new(EditorMode::full(), buffer, project, window, cx)
 1751    }
 1752
 1753    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1754        let mut clone = Self::new(
 1755            self.mode.clone(),
 1756            self.buffer.clone(),
 1757            self.project.clone(),
 1758            window,
 1759            cx,
 1760        );
 1761        self.display_map.update(cx, |display_map, cx| {
 1762            let snapshot = display_map.snapshot(cx);
 1763            clone.display_map.update(cx, |display_map, cx| {
 1764                display_map.set_state(&snapshot, cx);
 1765            });
 1766        });
 1767        clone.folds_did_change(cx);
 1768        clone.selections.clone_state(&self.selections);
 1769        clone.scroll_manager.clone_state(&self.scroll_manager);
 1770        clone.searchable = self.searchable;
 1771        clone.read_only = self.read_only;
 1772        clone
 1773    }
 1774
 1775    pub fn new(
 1776        mode: EditorMode,
 1777        buffer: Entity<MultiBuffer>,
 1778        project: Option<Entity<Project>>,
 1779        window: &mut Window,
 1780        cx: &mut Context<Self>,
 1781    ) -> Self {
 1782        Editor::new_internal(mode, buffer, project, None, window, cx)
 1783    }
 1784
 1785    fn new_internal(
 1786        mode: EditorMode,
 1787        buffer: Entity<MultiBuffer>,
 1788        project: Option<Entity<Project>>,
 1789        display_map: Option<Entity<DisplayMap>>,
 1790        window: &mut Window,
 1791        cx: &mut Context<Self>,
 1792    ) -> Self {
 1793        debug_assert!(
 1794            display_map.is_none() || mode.is_minimap(),
 1795            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1796        );
 1797
 1798        let full_mode = mode.is_full();
 1799        let is_minimap = mode.is_minimap();
 1800        let diagnostics_max_severity = if full_mode {
 1801            EditorSettings::get_global(cx)
 1802                .diagnostics_max_severity
 1803                .unwrap_or(DiagnosticSeverity::Hint)
 1804        } else {
 1805            DiagnosticSeverity::Off
 1806        };
 1807        let style = window.text_style();
 1808        let font_size = style.font_size.to_pixels(window.rem_size());
 1809        let editor = cx.entity().downgrade();
 1810        let fold_placeholder = FoldPlaceholder {
 1811            constrain_width: false,
 1812            render: Arc::new(move |fold_id, fold_range, cx| {
 1813                let editor = editor.clone();
 1814                div()
 1815                    .id(fold_id)
 1816                    .bg(cx.theme().colors().ghost_element_background)
 1817                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1818                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1819                    .rounded_xs()
 1820                    .size_full()
 1821                    .cursor_pointer()
 1822                    .child("")
 1823                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1824                    .on_click(move |_, _window, cx| {
 1825                        editor
 1826                            .update(cx, |editor, cx| {
 1827                                editor.unfold_ranges(
 1828                                    &[fold_range.start..fold_range.end],
 1829                                    true,
 1830                                    false,
 1831                                    cx,
 1832                                );
 1833                                cx.stop_propagation();
 1834                            })
 1835                            .ok();
 1836                    })
 1837                    .into_any()
 1838            }),
 1839            merge_adjacent: true,
 1840            ..FoldPlaceholder::default()
 1841        };
 1842        let display_map = display_map.unwrap_or_else(|| {
 1843            cx.new(|cx| {
 1844                DisplayMap::new(
 1845                    buffer.clone(),
 1846                    style.font(),
 1847                    font_size,
 1848                    None,
 1849                    FILE_HEADER_HEIGHT,
 1850                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1851                    fold_placeholder,
 1852                    diagnostics_max_severity,
 1853                    cx,
 1854                )
 1855            })
 1856        });
 1857
 1858        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1859
 1860        let blink_manager = cx.new(|cx| {
 1861            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1862            if is_minimap {
 1863                blink_manager.disable(cx);
 1864            }
 1865            blink_manager
 1866        });
 1867
 1868        let soft_wrap_mode_override =
 1869            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1870
 1871        let mut project_subscriptions = Vec::new();
 1872        if full_mode && let Some(project) = project.as_ref() {
 1873            project_subscriptions.push(cx.subscribe_in(
 1874                project,
 1875                window,
 1876                |editor, _, event, window, cx| match event {
 1877                    project::Event::RefreshCodeLens => {
 1878                        // we always query lens with actions, without storing them, always refreshing them
 1879                    }
 1880                    project::Event::RefreshInlayHints => {
 1881                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1882                    }
 1883                    project::Event::LanguageServerAdded(..)
 1884                    | project::Event::LanguageServerRemoved(..) => {
 1885                        if editor.tasks_update_task.is_none() {
 1886                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1887                        }
 1888                    }
 1889                    project::Event::SnippetEdit(id, snippet_edits) => {
 1890                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1891                            let focus_handle = editor.focus_handle(cx);
 1892                            if focus_handle.is_focused(window) {
 1893                                let snapshot = buffer.read(cx).snapshot();
 1894                                for (range, snippet) in snippet_edits {
 1895                                    let editor_range =
 1896                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1897                                    editor
 1898                                        .insert_snippet(
 1899                                            &[editor_range],
 1900                                            snippet.clone(),
 1901                                            window,
 1902                                            cx,
 1903                                        )
 1904                                        .ok();
 1905                                }
 1906                            }
 1907                        }
 1908                    }
 1909                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1910                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1911                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1912                        }
 1913                    }
 1914
 1915                    project::Event::EntryRenamed(transaction) => {
 1916                        let Some(workspace) = editor.workspace() else {
 1917                            return;
 1918                        };
 1919                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1920                        else {
 1921                            return;
 1922                        };
 1923                        if active_editor.entity_id() == cx.entity_id() {
 1924                            let edited_buffers_already_open = {
 1925                                let other_editors: Vec<Entity<Editor>> = workspace
 1926                                    .read(cx)
 1927                                    .panes()
 1928                                    .iter()
 1929                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1930                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1931                                    .collect();
 1932
 1933                                transaction.0.keys().all(|buffer| {
 1934                                    other_editors.iter().any(|editor| {
 1935                                        let multi_buffer = editor.read(cx).buffer();
 1936                                        multi_buffer.read(cx).is_singleton()
 1937                                            && multi_buffer.read(cx).as_singleton().map_or(
 1938                                                false,
 1939                                                |singleton| {
 1940                                                    singleton.entity_id() == buffer.entity_id()
 1941                                                },
 1942                                            )
 1943                                    })
 1944                                })
 1945                            };
 1946
 1947                            if !edited_buffers_already_open {
 1948                                let workspace = workspace.downgrade();
 1949                                let transaction = transaction.clone();
 1950                                cx.defer_in(window, move |_, window, cx| {
 1951                                    cx.spawn_in(window, async move |editor, cx| {
 1952                                        Self::open_project_transaction(
 1953                                            &editor,
 1954                                            workspace,
 1955                                            transaction,
 1956                                            "Rename".to_string(),
 1957                                            cx,
 1958                                        )
 1959                                        .await
 1960                                        .ok()
 1961                                    })
 1962                                    .detach();
 1963                                });
 1964                            }
 1965                        }
 1966                    }
 1967
 1968                    _ => {}
 1969                },
 1970            ));
 1971            if let Some(task_inventory) = project
 1972                .read(cx)
 1973                .task_store()
 1974                .read(cx)
 1975                .task_inventory()
 1976                .cloned()
 1977            {
 1978                project_subscriptions.push(cx.observe_in(
 1979                    &task_inventory,
 1980                    window,
 1981                    |editor, _, window, cx| {
 1982                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1983                    },
 1984                ));
 1985            };
 1986
 1987            project_subscriptions.push(cx.subscribe_in(
 1988                &project.read(cx).breakpoint_store(),
 1989                window,
 1990                |editor, _, event, window, cx| match event {
 1991                    BreakpointStoreEvent::ClearDebugLines => {
 1992                        editor.clear_row_highlights::<ActiveDebugLine>();
 1993                        editor.refresh_inline_values(cx);
 1994                    }
 1995                    BreakpointStoreEvent::SetDebugLine => {
 1996                        if editor.go_to_active_debug_line(window, cx) {
 1997                            cx.stop_propagation();
 1998                        }
 1999
 2000                        editor.refresh_inline_values(cx);
 2001                    }
 2002                    _ => {}
 2003                },
 2004            ));
 2005            let git_store = project.read(cx).git_store().clone();
 2006            let project = project.clone();
 2007            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2008                if let GitStoreEvent::RepositoryUpdated(
 2009                    _,
 2010                    RepositoryEvent::Updated {
 2011                        new_instance: true, ..
 2012                    },
 2013                    _,
 2014                ) = event
 2015                {
 2016                    this.load_diff_task = Some(
 2017                        update_uncommitted_diff_for_buffer(
 2018                            cx.entity(),
 2019                            &project,
 2020                            this.buffer.read(cx).all_buffers(),
 2021                            this.buffer.clone(),
 2022                            cx,
 2023                        )
 2024                        .shared(),
 2025                    );
 2026                }
 2027            }));
 2028        }
 2029
 2030        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2031
 2032        let inlay_hint_settings =
 2033            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2034        let focus_handle = cx.focus_handle();
 2035        if !is_minimap {
 2036            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2037                .detach();
 2038            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2039                .detach();
 2040            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2041                .detach();
 2042            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2043                .detach();
 2044            cx.observe_pending_input(window, Self::observe_pending_input)
 2045                .detach();
 2046        }
 2047
 2048        let show_indent_guides =
 2049            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2050                Some(false)
 2051            } else {
 2052                None
 2053            };
 2054
 2055        let breakpoint_store = match (&mode, project.as_ref()) {
 2056            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2057            _ => None,
 2058        };
 2059
 2060        let mut code_action_providers = Vec::new();
 2061        let mut load_uncommitted_diff = None;
 2062        if let Some(project) = project.clone() {
 2063            load_uncommitted_diff = Some(
 2064                update_uncommitted_diff_for_buffer(
 2065                    cx.entity(),
 2066                    &project,
 2067                    buffer.read(cx).all_buffers(),
 2068                    buffer.clone(),
 2069                    cx,
 2070                )
 2071                .shared(),
 2072            );
 2073            code_action_providers.push(Rc::new(project) as Rc<_>);
 2074        }
 2075
 2076        let mut editor = Self {
 2077            focus_handle,
 2078            show_cursor_when_unfocused: false,
 2079            last_focused_descendant: None,
 2080            buffer: buffer.clone(),
 2081            display_map: display_map.clone(),
 2082            placeholder_display_map: None,
 2083            selections,
 2084            scroll_manager: ScrollManager::new(cx),
 2085            columnar_selection_state: None,
 2086            add_selections_state: None,
 2087            select_next_state: None,
 2088            select_prev_state: None,
 2089            selection_history: SelectionHistory::default(),
 2090            defer_selection_effects: false,
 2091            deferred_selection_effects_state: None,
 2092            autoclose_regions: Vec::new(),
 2093            snippet_stack: InvalidationStack::default(),
 2094            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2095            ime_transaction: None,
 2096            active_diagnostics: ActiveDiagnostic::None,
 2097            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2098            inline_diagnostics_update: Task::ready(()),
 2099            inline_diagnostics: Vec::new(),
 2100            soft_wrap_mode_override,
 2101            diagnostics_max_severity,
 2102            hard_wrap: None,
 2103            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2104            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2105            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2106            project,
 2107            blink_manager: blink_manager.clone(),
 2108            show_local_selections: true,
 2109            show_scrollbars: ScrollbarAxes {
 2110                horizontal: full_mode,
 2111                vertical: full_mode,
 2112            },
 2113            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2114            offset_content: !matches!(mode, EditorMode::SingleLine),
 2115            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2116            show_gutter: full_mode,
 2117            show_line_numbers: (!full_mode).then_some(false),
 2118            use_relative_line_numbers: None,
 2119            disable_expand_excerpt_buttons: !full_mode,
 2120            show_git_diff_gutter: None,
 2121            show_code_actions: None,
 2122            show_runnables: None,
 2123            show_breakpoints: None,
 2124            show_wrap_guides: None,
 2125            show_indent_guides,
 2126            highlight_order: 0,
 2127            highlighted_rows: HashMap::default(),
 2128            background_highlights: HashMap::default(),
 2129            gutter_highlights: HashMap::default(),
 2130            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2131            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2132            nav_history: None,
 2133            context_menu: RefCell::new(None),
 2134            context_menu_options: None,
 2135            mouse_context_menu: None,
 2136            completion_tasks: Vec::new(),
 2137            inline_blame_popover: None,
 2138            inline_blame_popover_show_task: None,
 2139            signature_help_state: SignatureHelpState::default(),
 2140            auto_signature_help: None,
 2141            find_all_references_task_sources: Vec::new(),
 2142            next_completion_id: 0,
 2143            next_inlay_id: 0,
 2144            code_action_providers,
 2145            available_code_actions: None,
 2146            code_actions_task: None,
 2147            quick_selection_highlight_task: None,
 2148            debounced_selection_highlight_task: None,
 2149            document_highlights_task: None,
 2150            linked_editing_range_task: None,
 2151            pending_rename: None,
 2152            searchable: !is_minimap,
 2153            cursor_shape: EditorSettings::get_global(cx)
 2154                .cursor_shape
 2155                .unwrap_or_default(),
 2156            current_line_highlight: None,
 2157            autoindent_mode: Some(AutoindentMode::EachLine),
 2158            collapse_matches: false,
 2159            workspace: None,
 2160            input_enabled: !is_minimap,
 2161            use_modal_editing: full_mode,
 2162            read_only: is_minimap,
 2163            use_autoclose: true,
 2164            use_auto_surround: true,
 2165            auto_replace_emoji_shortcode: false,
 2166            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2167            leader_id: None,
 2168            remote_id: None,
 2169            hover_state: HoverState::default(),
 2170            pending_mouse_down: None,
 2171            hovered_link_state: None,
 2172            edit_prediction_provider: None,
 2173            active_edit_prediction: None,
 2174            stale_edit_prediction_in_menu: None,
 2175            edit_prediction_preview: EditPredictionPreview::Inactive {
 2176                released_too_fast: false,
 2177            },
 2178            inline_diagnostics_enabled: full_mode,
 2179            diagnostics_enabled: full_mode,
 2180            word_completions_enabled: full_mode,
 2181            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2182            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2183            gutter_hovered: false,
 2184            pixel_position_of_newest_cursor: None,
 2185            last_bounds: None,
 2186            last_position_map: None,
 2187            expect_bounds_change: None,
 2188            gutter_dimensions: GutterDimensions::default(),
 2189            style: None,
 2190            show_cursor_names: false,
 2191            hovered_cursors: HashMap::default(),
 2192            next_editor_action_id: EditorActionId::default(),
 2193            editor_actions: Rc::default(),
 2194            edit_predictions_hidden_for_vim_mode: false,
 2195            show_edit_predictions_override: None,
 2196            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2197            edit_prediction_settings: EditPredictionSettings::Disabled,
 2198            edit_prediction_indent_conflict: false,
 2199            edit_prediction_requires_modifier_in_indent_conflict: true,
 2200            custom_context_menu: None,
 2201            show_git_blame_gutter: false,
 2202            show_git_blame_inline: false,
 2203            show_selection_menu: None,
 2204            show_git_blame_inline_delay_task: None,
 2205            git_blame_inline_enabled: full_mode
 2206                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2207            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2208            serialize_dirty_buffers: !is_minimap
 2209                && ProjectSettings::get_global(cx)
 2210                    .session
 2211                    .restore_unsaved_buffers,
 2212            blame: None,
 2213            blame_subscription: None,
 2214            tasks: BTreeMap::default(),
 2215
 2216            breakpoint_store,
 2217            gutter_breakpoint_indicator: (None, None),
 2218            hovered_diff_hunk_row: None,
 2219            _subscriptions: (!is_minimap)
 2220                .then(|| {
 2221                    vec![
 2222                        cx.observe(&buffer, Self::on_buffer_changed),
 2223                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2224                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2225                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2226                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2227                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2228                        cx.observe_window_activation(window, |editor, window, cx| {
 2229                            let active = window.is_window_active();
 2230                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2231                                if active {
 2232                                    blink_manager.enable(cx);
 2233                                } else {
 2234                                    blink_manager.disable(cx);
 2235                                }
 2236                            });
 2237                            if active {
 2238                                editor.show_mouse_cursor(cx);
 2239                            }
 2240                        }),
 2241                    ]
 2242                })
 2243                .unwrap_or_default(),
 2244            tasks_update_task: None,
 2245            pull_diagnostics_task: Task::ready(()),
 2246            colors: None,
 2247            next_color_inlay_id: 0,
 2248            linked_edit_ranges: Default::default(),
 2249            in_project_search: false,
 2250            previous_search_ranges: None,
 2251            breadcrumb_header: None,
 2252            focused_block: None,
 2253            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2254            addons: HashMap::default(),
 2255            registered_buffers: HashMap::default(),
 2256            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2257            selection_mark_mode: false,
 2258            toggle_fold_multiple_buffers: Task::ready(()),
 2259            serialize_selections: Task::ready(()),
 2260            serialize_folds: Task::ready(()),
 2261            text_style_refinement: None,
 2262            load_diff_task: load_uncommitted_diff,
 2263            temporary_diff_override: false,
 2264            mouse_cursor_hidden: false,
 2265            minimap: None,
 2266            hide_mouse_mode: EditorSettings::get_global(cx)
 2267                .hide_mouse
 2268                .unwrap_or_default(),
 2269            change_list: ChangeList::new(),
 2270            mode,
 2271            selection_drag_state: SelectionDragState::None,
 2272            folding_newlines: Task::ready(()),
 2273            lookup_key: None,
 2274        };
 2275
 2276        if is_minimap {
 2277            return editor;
 2278        }
 2279
 2280        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2281            editor
 2282                ._subscriptions
 2283                .push(cx.observe(breakpoints, |_, _, cx| {
 2284                    cx.notify();
 2285                }));
 2286        }
 2287        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2288        editor._subscriptions.extend(project_subscriptions);
 2289
 2290        editor._subscriptions.push(cx.subscribe_in(
 2291            &cx.entity(),
 2292            window,
 2293            |editor, _, e: &EditorEvent, window, cx| match e {
 2294                EditorEvent::ScrollPositionChanged { local, .. } => {
 2295                    if *local {
 2296                        let new_anchor = editor.scroll_manager.anchor();
 2297                        let snapshot = editor.snapshot(window, cx);
 2298                        editor.update_restoration_data(cx, move |data| {
 2299                            data.scroll_position = (
 2300                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2301                                new_anchor.offset,
 2302                            );
 2303                        });
 2304                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2305                        editor.inline_blame_popover.take();
 2306                    }
 2307                }
 2308                EditorEvent::Edited { .. } => {
 2309                    if !vim_enabled(cx) {
 2310                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2311                        let pop_state = editor
 2312                            .change_list
 2313                            .last()
 2314                            .map(|previous| {
 2315                                previous.len() == selections.len()
 2316                                    && previous.iter().enumerate().all(|(ix, p)| {
 2317                                        p.to_display_point(&map).row()
 2318                                            == selections[ix].head().row()
 2319                                    })
 2320                            })
 2321                            .unwrap_or(false);
 2322                        let new_positions = selections
 2323                            .into_iter()
 2324                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2325                            .collect();
 2326                        editor
 2327                            .change_list
 2328                            .push_to_change_list(pop_state, new_positions);
 2329                    }
 2330                }
 2331                _ => (),
 2332            },
 2333        ));
 2334
 2335        if let Some(dap_store) = editor
 2336            .project
 2337            .as_ref()
 2338            .map(|project| project.read(cx).dap_store())
 2339        {
 2340            let weak_editor = cx.weak_entity();
 2341
 2342            editor
 2343                ._subscriptions
 2344                .push(
 2345                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2346                        let session_entity = cx.entity();
 2347                        weak_editor
 2348                            .update(cx, |editor, cx| {
 2349                                editor._subscriptions.push(
 2350                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2351                                );
 2352                            })
 2353                            .ok();
 2354                    }),
 2355                );
 2356
 2357            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2358                editor
 2359                    ._subscriptions
 2360                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2361            }
 2362        }
 2363
 2364        // skip adding the initial selection to selection history
 2365        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2366        editor.end_selection(window, cx);
 2367        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2368
 2369        editor.scroll_manager.show_scrollbars(window, cx);
 2370        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2371
 2372        if full_mode {
 2373            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2374            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2375
 2376            if editor.git_blame_inline_enabled {
 2377                editor.start_git_blame_inline(false, window, cx);
 2378            }
 2379
 2380            editor.go_to_active_debug_line(window, cx);
 2381
 2382            if let Some(buffer) = buffer.read(cx).as_singleton()
 2383                && let Some(project) = editor.project()
 2384            {
 2385                let handle = project.update(cx, |project, cx| {
 2386                    project.register_buffer_with_language_servers(&buffer, cx)
 2387                });
 2388                editor
 2389                    .registered_buffers
 2390                    .insert(buffer.read(cx).remote_id(), handle);
 2391            }
 2392
 2393            editor.minimap =
 2394                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2395            editor.colors = Some(LspColorData::new(cx));
 2396            editor.update_lsp_data(false, None, window, cx);
 2397        }
 2398
 2399        if editor.mode.is_full() {
 2400            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2401        }
 2402
 2403        editor
 2404    }
 2405
 2406    pub fn deploy_mouse_context_menu(
 2407        &mut self,
 2408        position: gpui::Point<Pixels>,
 2409        context_menu: Entity<ContextMenu>,
 2410        window: &mut Window,
 2411        cx: &mut Context<Self>,
 2412    ) {
 2413        self.mouse_context_menu = Some(MouseContextMenu::new(
 2414            self,
 2415            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2416            context_menu,
 2417            window,
 2418            cx,
 2419        ));
 2420    }
 2421
 2422    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2423        self.mouse_context_menu
 2424            .as_ref()
 2425            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2426    }
 2427
 2428    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2429        if self
 2430            .selections
 2431            .pending_anchor()
 2432            .is_some_and(|pending_selection| {
 2433                let snapshot = self.buffer().read(cx).snapshot(cx);
 2434                pending_selection.range().includes(range, &snapshot)
 2435            })
 2436        {
 2437            return true;
 2438        }
 2439
 2440        self.selections
 2441            .disjoint_in_range::<usize>(range.clone(), cx)
 2442            .into_iter()
 2443            .any(|selection| {
 2444                // This is needed to cover a corner case, if we just check for an existing
 2445                // selection in the fold range, having a cursor at the start of the fold
 2446                // marks it as selected. Non-empty selections don't cause this.
 2447                let length = selection.end - selection.start;
 2448                length > 0
 2449            })
 2450    }
 2451
 2452    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2453        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2454    }
 2455
 2456    fn key_context_internal(
 2457        &self,
 2458        has_active_edit_prediction: bool,
 2459        window: &Window,
 2460        cx: &App,
 2461    ) -> KeyContext {
 2462        let mut key_context = KeyContext::new_with_defaults();
 2463        key_context.add("Editor");
 2464        let mode = match self.mode {
 2465            EditorMode::SingleLine => "single_line",
 2466            EditorMode::AutoHeight { .. } => "auto_height",
 2467            EditorMode::Minimap { .. } => "minimap",
 2468            EditorMode::Full { .. } => "full",
 2469        };
 2470
 2471        if EditorSettings::jupyter_enabled(cx) {
 2472            key_context.add("jupyter");
 2473        }
 2474
 2475        key_context.set("mode", mode);
 2476        if self.pending_rename.is_some() {
 2477            key_context.add("renaming");
 2478        }
 2479
 2480        match self.context_menu.borrow().as_ref() {
 2481            Some(CodeContextMenu::Completions(menu)) => {
 2482                if menu.visible() {
 2483                    key_context.add("menu");
 2484                    key_context.add("showing_completions");
 2485                }
 2486            }
 2487            Some(CodeContextMenu::CodeActions(menu)) => {
 2488                if menu.visible() {
 2489                    key_context.add("menu");
 2490                    key_context.add("showing_code_actions")
 2491                }
 2492            }
 2493            None => {}
 2494        }
 2495
 2496        if self.signature_help_state.has_multiple_signatures() {
 2497            key_context.add("showing_signature_help");
 2498        }
 2499
 2500        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2501        if !self.focus_handle(cx).contains_focused(window, cx)
 2502            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2503        {
 2504            for addon in self.addons.values() {
 2505                addon.extend_key_context(&mut key_context, cx)
 2506            }
 2507        }
 2508
 2509        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2510            if let Some(extension) = singleton_buffer
 2511                .read(cx)
 2512                .file()
 2513                .and_then(|file| file.path().extension())
 2514            {
 2515                key_context.set("extension", extension.to_string());
 2516            }
 2517        } else {
 2518            key_context.add("multibuffer");
 2519        }
 2520
 2521        if has_active_edit_prediction {
 2522            if self.edit_prediction_in_conflict() {
 2523                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2524            } else {
 2525                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2526                key_context.add("copilot_suggestion");
 2527            }
 2528        }
 2529
 2530        if self.selection_mark_mode {
 2531            key_context.add("selection_mode");
 2532        }
 2533
 2534        key_context
 2535    }
 2536
 2537    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2538        self.last_bounds.as_ref()
 2539    }
 2540
 2541    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2542        if self.mouse_cursor_hidden {
 2543            self.mouse_cursor_hidden = false;
 2544            cx.notify();
 2545        }
 2546    }
 2547
 2548    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2549        let hide_mouse_cursor = match origin {
 2550            HideMouseCursorOrigin::TypingAction => {
 2551                matches!(
 2552                    self.hide_mouse_mode,
 2553                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2554                )
 2555            }
 2556            HideMouseCursorOrigin::MovementAction => {
 2557                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2558            }
 2559        };
 2560        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2561            self.mouse_cursor_hidden = hide_mouse_cursor;
 2562            cx.notify();
 2563        }
 2564    }
 2565
 2566    pub fn edit_prediction_in_conflict(&self) -> bool {
 2567        if !self.show_edit_predictions_in_menu() {
 2568            return false;
 2569        }
 2570
 2571        let showing_completions = self
 2572            .context_menu
 2573            .borrow()
 2574            .as_ref()
 2575            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2576
 2577        showing_completions
 2578            || self.edit_prediction_requires_modifier()
 2579            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2580            // bindings to insert tab characters.
 2581            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2582    }
 2583
 2584    pub fn accept_edit_prediction_keybind(
 2585        &self,
 2586        accept_partial: bool,
 2587        window: &Window,
 2588        cx: &App,
 2589    ) -> AcceptEditPredictionBinding {
 2590        let key_context = self.key_context_internal(true, window, cx);
 2591        let in_conflict = self.edit_prediction_in_conflict();
 2592
 2593        let bindings = if accept_partial {
 2594            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2595        } else {
 2596            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2597        };
 2598
 2599        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2600        // just the first one.
 2601        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2602            !in_conflict
 2603                || binding
 2604                    .keystrokes()
 2605                    .first()
 2606                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2607        }))
 2608    }
 2609
 2610    pub fn new_file(
 2611        workspace: &mut Workspace,
 2612        _: &workspace::NewFile,
 2613        window: &mut Window,
 2614        cx: &mut Context<Workspace>,
 2615    ) {
 2616        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2617            "Failed to create buffer",
 2618            window,
 2619            cx,
 2620            |e, _, _| match e.error_code() {
 2621                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2622                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2623                e.error_tag("required").unwrap_or("the latest version")
 2624            )),
 2625                _ => None,
 2626            },
 2627        );
 2628    }
 2629
 2630    pub fn new_in_workspace(
 2631        workspace: &mut Workspace,
 2632        window: &mut Window,
 2633        cx: &mut Context<Workspace>,
 2634    ) -> Task<Result<Entity<Editor>>> {
 2635        let project = workspace.project().clone();
 2636        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2637
 2638        cx.spawn_in(window, async move |workspace, cx| {
 2639            let buffer = create.await?;
 2640            workspace.update_in(cx, |workspace, window, cx| {
 2641                let editor =
 2642                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2643                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2644                editor
 2645            })
 2646        })
 2647    }
 2648
 2649    fn new_file_vertical(
 2650        workspace: &mut Workspace,
 2651        _: &workspace::NewFileSplitVertical,
 2652        window: &mut Window,
 2653        cx: &mut Context<Workspace>,
 2654    ) {
 2655        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2656    }
 2657
 2658    fn new_file_horizontal(
 2659        workspace: &mut Workspace,
 2660        _: &workspace::NewFileSplitHorizontal,
 2661        window: &mut Window,
 2662        cx: &mut Context<Workspace>,
 2663    ) {
 2664        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2665    }
 2666
 2667    fn new_file_in_direction(
 2668        workspace: &mut Workspace,
 2669        direction: SplitDirection,
 2670        window: &mut Window,
 2671        cx: &mut Context<Workspace>,
 2672    ) {
 2673        let project = workspace.project().clone();
 2674        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2675
 2676        cx.spawn_in(window, async move |workspace, cx| {
 2677            let buffer = create.await?;
 2678            workspace.update_in(cx, move |workspace, window, cx| {
 2679                workspace.split_item(
 2680                    direction,
 2681                    Box::new(
 2682                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2683                    ),
 2684                    window,
 2685                    cx,
 2686                )
 2687            })?;
 2688            anyhow::Ok(())
 2689        })
 2690        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2691            match e.error_code() {
 2692                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2693                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2694                e.error_tag("required").unwrap_or("the latest version")
 2695            )),
 2696                _ => None,
 2697            }
 2698        });
 2699    }
 2700
 2701    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2702        self.leader_id
 2703    }
 2704
 2705    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2706        &self.buffer
 2707    }
 2708
 2709    pub fn project(&self) -> Option<&Entity<Project>> {
 2710        self.project.as_ref()
 2711    }
 2712
 2713    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2714        self.workspace.as_ref()?.0.upgrade()
 2715    }
 2716
 2717    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2718        self.buffer().read(cx).title(cx)
 2719    }
 2720
 2721    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2722        let git_blame_gutter_max_author_length = self
 2723            .render_git_blame_gutter(cx)
 2724            .then(|| {
 2725                if let Some(blame) = self.blame.as_ref() {
 2726                    let max_author_length =
 2727                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2728                    Some(max_author_length)
 2729                } else {
 2730                    None
 2731                }
 2732            })
 2733            .flatten();
 2734
 2735        EditorSnapshot {
 2736            mode: self.mode.clone(),
 2737            show_gutter: self.show_gutter,
 2738            show_line_numbers: self.show_line_numbers,
 2739            show_git_diff_gutter: self.show_git_diff_gutter,
 2740            show_code_actions: self.show_code_actions,
 2741            show_runnables: self.show_runnables,
 2742            show_breakpoints: self.show_breakpoints,
 2743            git_blame_gutter_max_author_length,
 2744            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2745            placeholder_display_snapshot: self
 2746                .placeholder_display_map
 2747                .as_ref()
 2748                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2749            scroll_anchor: self.scroll_manager.anchor(),
 2750            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2751            is_focused: self.focus_handle.is_focused(window),
 2752            current_line_highlight: self
 2753                .current_line_highlight
 2754                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2755            gutter_hovered: self.gutter_hovered,
 2756        }
 2757    }
 2758
 2759    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2760        self.buffer.read(cx).language_at(point, cx)
 2761    }
 2762
 2763    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2764        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2765    }
 2766
 2767    pub fn active_excerpt(
 2768        &self,
 2769        cx: &App,
 2770    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2771        self.buffer
 2772            .read(cx)
 2773            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2774    }
 2775
 2776    pub fn mode(&self) -> &EditorMode {
 2777        &self.mode
 2778    }
 2779
 2780    pub fn set_mode(&mut self, mode: EditorMode) {
 2781        self.mode = mode;
 2782    }
 2783
 2784    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2785        self.collaboration_hub.as_deref()
 2786    }
 2787
 2788    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2789        self.collaboration_hub = Some(hub);
 2790    }
 2791
 2792    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2793        self.in_project_search = in_project_search;
 2794    }
 2795
 2796    pub fn set_custom_context_menu(
 2797        &mut self,
 2798        f: impl 'static
 2799        + Fn(
 2800            &mut Self,
 2801            DisplayPoint,
 2802            &mut Window,
 2803            &mut Context<Self>,
 2804        ) -> Option<Entity<ui::ContextMenu>>,
 2805    ) {
 2806        self.custom_context_menu = Some(Box::new(f))
 2807    }
 2808
 2809    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2810        self.completion_provider = provider;
 2811    }
 2812
 2813    #[cfg(any(test, feature = "test-support"))]
 2814    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2815        self.completion_provider.clone()
 2816    }
 2817
 2818    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2819        self.semantics_provider.clone()
 2820    }
 2821
 2822    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2823        self.semantics_provider = provider;
 2824    }
 2825
 2826    pub fn set_edit_prediction_provider<T>(
 2827        &mut self,
 2828        provider: Option<Entity<T>>,
 2829        window: &mut Window,
 2830        cx: &mut Context<Self>,
 2831    ) where
 2832        T: EditPredictionProvider,
 2833    {
 2834        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2835            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2836                if this.focus_handle.is_focused(window) {
 2837                    this.update_visible_edit_prediction(window, cx);
 2838                }
 2839            }),
 2840            provider: Arc::new(provider),
 2841        });
 2842        self.update_edit_prediction_settings(cx);
 2843        self.refresh_edit_prediction(false, false, window, cx);
 2844    }
 2845
 2846    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2847        self.placeholder_display_map
 2848            .as_ref()
 2849            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2850    }
 2851
 2852    pub fn set_placeholder_text(
 2853        &mut self,
 2854        placeholder_text: &str,
 2855        window: &mut Window,
 2856        cx: &mut Context<Self>,
 2857    ) {
 2858        let multibuffer = cx
 2859            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2860
 2861        let style = window.text_style();
 2862
 2863        self.placeholder_display_map = Some(cx.new(|cx| {
 2864            DisplayMap::new(
 2865                multibuffer,
 2866                style.font(),
 2867                style.font_size.to_pixels(window.rem_size()),
 2868                None,
 2869                FILE_HEADER_HEIGHT,
 2870                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2871                Default::default(),
 2872                DiagnosticSeverity::Off,
 2873                cx,
 2874            )
 2875        }));
 2876        cx.notify();
 2877    }
 2878
 2879    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2880        self.cursor_shape = cursor_shape;
 2881
 2882        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2883        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2884
 2885        cx.notify();
 2886    }
 2887
 2888    pub fn set_current_line_highlight(
 2889        &mut self,
 2890        current_line_highlight: Option<CurrentLineHighlight>,
 2891    ) {
 2892        self.current_line_highlight = current_line_highlight;
 2893    }
 2894
 2895    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2896        self.collapse_matches = collapse_matches;
 2897    }
 2898
 2899    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2900        let buffers = self.buffer.read(cx).all_buffers();
 2901        let Some(project) = self.project.as_ref() else {
 2902            return;
 2903        };
 2904        project.update(cx, |project, cx| {
 2905            for buffer in buffers {
 2906                self.registered_buffers
 2907                    .entry(buffer.read(cx).remote_id())
 2908                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2909            }
 2910        })
 2911    }
 2912
 2913    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2914        if self.collapse_matches {
 2915            return range.start..range.start;
 2916        }
 2917        range.clone()
 2918    }
 2919
 2920    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2921        if self.display_map.read(cx).clip_at_line_ends != clip {
 2922            self.display_map
 2923                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2924        }
 2925    }
 2926
 2927    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2928        self.input_enabled = input_enabled;
 2929    }
 2930
 2931    pub fn set_edit_predictions_hidden_for_vim_mode(
 2932        &mut self,
 2933        hidden: bool,
 2934        window: &mut Window,
 2935        cx: &mut Context<Self>,
 2936    ) {
 2937        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2938            self.edit_predictions_hidden_for_vim_mode = hidden;
 2939            if hidden {
 2940                self.update_visible_edit_prediction(window, cx);
 2941            } else {
 2942                self.refresh_edit_prediction(true, false, window, cx);
 2943            }
 2944        }
 2945    }
 2946
 2947    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2948        self.menu_edit_predictions_policy = value;
 2949    }
 2950
 2951    pub fn set_autoindent(&mut self, autoindent: bool) {
 2952        if autoindent {
 2953            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2954        } else {
 2955            self.autoindent_mode = None;
 2956        }
 2957    }
 2958
 2959    pub fn read_only(&self, cx: &App) -> bool {
 2960        self.read_only || self.buffer.read(cx).read_only()
 2961    }
 2962
 2963    pub fn set_read_only(&mut self, read_only: bool) {
 2964        self.read_only = read_only;
 2965    }
 2966
 2967    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2968        self.use_autoclose = autoclose;
 2969    }
 2970
 2971    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2972        self.use_auto_surround = auto_surround;
 2973    }
 2974
 2975    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2976        self.auto_replace_emoji_shortcode = auto_replace;
 2977    }
 2978
 2979    pub fn toggle_edit_predictions(
 2980        &mut self,
 2981        _: &ToggleEditPrediction,
 2982        window: &mut Window,
 2983        cx: &mut Context<Self>,
 2984    ) {
 2985        if self.show_edit_predictions_override.is_some() {
 2986            self.set_show_edit_predictions(None, window, cx);
 2987        } else {
 2988            let show_edit_predictions = !self.edit_predictions_enabled();
 2989            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2990        }
 2991    }
 2992
 2993    pub fn set_show_edit_predictions(
 2994        &mut self,
 2995        show_edit_predictions: Option<bool>,
 2996        window: &mut Window,
 2997        cx: &mut Context<Self>,
 2998    ) {
 2999        self.show_edit_predictions_override = show_edit_predictions;
 3000        self.update_edit_prediction_settings(cx);
 3001
 3002        if let Some(false) = show_edit_predictions {
 3003            self.discard_edit_prediction(false, cx);
 3004        } else {
 3005            self.refresh_edit_prediction(false, true, window, cx);
 3006        }
 3007    }
 3008
 3009    fn edit_predictions_disabled_in_scope(
 3010        &self,
 3011        buffer: &Entity<Buffer>,
 3012        buffer_position: language::Anchor,
 3013        cx: &App,
 3014    ) -> bool {
 3015        let snapshot = buffer.read(cx).snapshot();
 3016        let settings = snapshot.settings_at(buffer_position, cx);
 3017
 3018        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3019            return false;
 3020        };
 3021
 3022        scope.override_name().is_some_and(|scope_name| {
 3023            settings
 3024                .edit_predictions_disabled_in
 3025                .iter()
 3026                .any(|s| s == scope_name)
 3027        })
 3028    }
 3029
 3030    pub fn set_use_modal_editing(&mut self, to: bool) {
 3031        self.use_modal_editing = to;
 3032    }
 3033
 3034    pub fn use_modal_editing(&self) -> bool {
 3035        self.use_modal_editing
 3036    }
 3037
 3038    fn selections_did_change(
 3039        &mut self,
 3040        local: bool,
 3041        old_cursor_position: &Anchor,
 3042        effects: SelectionEffects,
 3043        window: &mut Window,
 3044        cx: &mut Context<Self>,
 3045    ) {
 3046        window.invalidate_character_coordinates();
 3047
 3048        // Copy selections to primary selection buffer
 3049        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3050        if local {
 3051            let selections = self.selections.all::<usize>(cx);
 3052            let buffer_handle = self.buffer.read(cx).read(cx);
 3053
 3054            let mut text = String::new();
 3055            for (index, selection) in selections.iter().enumerate() {
 3056                let text_for_selection = buffer_handle
 3057                    .text_for_range(selection.start..selection.end)
 3058                    .collect::<String>();
 3059
 3060                text.push_str(&text_for_selection);
 3061                if index != selections.len() - 1 {
 3062                    text.push('\n');
 3063                }
 3064            }
 3065
 3066            if !text.is_empty() {
 3067                cx.write_to_primary(ClipboardItem::new_string(text));
 3068            }
 3069        }
 3070
 3071        let selection_anchors = self.selections.disjoint_anchors_arc();
 3072
 3073        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3074            self.buffer.update(cx, |buffer, cx| {
 3075                buffer.set_active_selections(
 3076                    &selection_anchors,
 3077                    self.selections.line_mode(),
 3078                    self.cursor_shape,
 3079                    cx,
 3080                )
 3081            });
 3082        }
 3083        let display_map = self
 3084            .display_map
 3085            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3086        let buffer = display_map.buffer_snapshot();
 3087        if self.selections.count() == 1 {
 3088            self.add_selections_state = None;
 3089        }
 3090        self.select_next_state = None;
 3091        self.select_prev_state = None;
 3092        self.select_syntax_node_history.try_clear();
 3093        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3094        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3095        self.take_rename(false, window, cx);
 3096
 3097        let newest_selection = self.selections.newest_anchor();
 3098        let new_cursor_position = newest_selection.head();
 3099        let selection_start = newest_selection.start;
 3100
 3101        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3102            self.push_to_nav_history(
 3103                *old_cursor_position,
 3104                Some(new_cursor_position.to_point(buffer)),
 3105                false,
 3106                effects.nav_history == Some(true),
 3107                cx,
 3108            );
 3109        }
 3110
 3111        if local {
 3112            if let Some(buffer_id) = new_cursor_position.buffer_id
 3113                && !self.registered_buffers.contains_key(&buffer_id)
 3114                && let Some(project) = self.project.as_ref()
 3115            {
 3116                project.update(cx, |project, cx| {
 3117                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3118                        return;
 3119                    };
 3120                    self.registered_buffers.insert(
 3121                        buffer_id,
 3122                        project.register_buffer_with_language_servers(&buffer, cx),
 3123                    );
 3124                })
 3125            }
 3126
 3127            let mut context_menu = self.context_menu.borrow_mut();
 3128            let completion_menu = match context_menu.as_ref() {
 3129                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3130                Some(CodeContextMenu::CodeActions(_)) => {
 3131                    *context_menu = None;
 3132                    None
 3133                }
 3134                None => None,
 3135            };
 3136            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3137            drop(context_menu);
 3138
 3139            if effects.completions
 3140                && let Some(completion_position) = completion_position
 3141            {
 3142                let start_offset = selection_start.to_offset(buffer);
 3143                let position_matches = start_offset == completion_position.to_offset(buffer);
 3144                let continue_showing = if position_matches {
 3145                    if self.snippet_stack.is_empty() {
 3146                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3147                            == Some(CharKind::Word)
 3148                    } else {
 3149                        // Snippet choices can be shown even when the cursor is in whitespace.
 3150                        // Dismissing the menu with actions like backspace is handled by
 3151                        // invalidation regions.
 3152                        true
 3153                    }
 3154                } else {
 3155                    false
 3156                };
 3157
 3158                if continue_showing {
 3159                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3160                } else {
 3161                    self.hide_context_menu(window, cx);
 3162                }
 3163            }
 3164
 3165            hide_hover(self, cx);
 3166
 3167            if old_cursor_position.to_display_point(&display_map).row()
 3168                != new_cursor_position.to_display_point(&display_map).row()
 3169            {
 3170                self.available_code_actions.take();
 3171            }
 3172            self.refresh_code_actions(window, cx);
 3173            self.refresh_document_highlights(cx);
 3174            self.refresh_selected_text_highlights(false, window, cx);
 3175            refresh_matching_bracket_highlights(self, window, cx);
 3176            self.update_visible_edit_prediction(window, cx);
 3177            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3178            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3179            self.inline_blame_popover.take();
 3180            if self.git_blame_inline_enabled {
 3181                self.start_inline_blame_timer(window, cx);
 3182            }
 3183        }
 3184
 3185        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3186        cx.emit(EditorEvent::SelectionsChanged { local });
 3187
 3188        let selections = &self.selections.disjoint_anchors_arc();
 3189        if selections.len() == 1 {
 3190            cx.emit(SearchEvent::ActiveMatchChanged)
 3191        }
 3192        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3193            let inmemory_selections = selections
 3194                .iter()
 3195                .map(|s| {
 3196                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3197                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3198                })
 3199                .collect();
 3200            self.update_restoration_data(cx, |data| {
 3201                data.selections = inmemory_selections;
 3202            });
 3203
 3204            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3205                && let Some(workspace_id) =
 3206                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3207            {
 3208                let snapshot = self.buffer().read(cx).snapshot(cx);
 3209                let selections = selections.clone();
 3210                let background_executor = cx.background_executor().clone();
 3211                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3212                self.serialize_selections = cx.background_spawn(async move {
 3213                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3214                    let db_selections = selections
 3215                        .iter()
 3216                        .map(|selection| {
 3217                            (
 3218                                selection.start.to_offset(&snapshot),
 3219                                selection.end.to_offset(&snapshot),
 3220                            )
 3221                        })
 3222                        .collect();
 3223
 3224                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3225                        .await
 3226                        .with_context(|| {
 3227                            format!(
 3228                                "persisting editor selections for editor {editor_id}, \
 3229                                workspace {workspace_id:?}"
 3230                            )
 3231                        })
 3232                        .log_err();
 3233                });
 3234            }
 3235        }
 3236
 3237        cx.notify();
 3238    }
 3239
 3240    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3241        use text::ToOffset as _;
 3242        use text::ToPoint as _;
 3243
 3244        if self.mode.is_minimap()
 3245            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3246        {
 3247            return;
 3248        }
 3249
 3250        if !self.buffer().read(cx).is_singleton() {
 3251            return;
 3252        }
 3253
 3254        let display_snapshot = self
 3255            .display_map
 3256            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3257        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3258            return;
 3259        };
 3260        let inmemory_folds = 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        self.update_restoration_data(cx, |data| {
 3268            data.folds = inmemory_folds;
 3269        });
 3270
 3271        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3272            return;
 3273        };
 3274        let background_executor = cx.background_executor().clone();
 3275        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3276        let db_folds = display_snapshot
 3277            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3278            .map(|fold| {
 3279                (
 3280                    fold.range.start.text_anchor.to_offset(&snapshot),
 3281                    fold.range.end.text_anchor.to_offset(&snapshot),
 3282                )
 3283            })
 3284            .collect();
 3285        self.serialize_folds = cx.background_spawn(async move {
 3286            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3287            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3288                .await
 3289                .with_context(|| {
 3290                    format!(
 3291                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3292                    )
 3293                })
 3294                .log_err();
 3295        });
 3296    }
 3297
 3298    pub fn sync_selections(
 3299        &mut self,
 3300        other: Entity<Editor>,
 3301        cx: &mut Context<Self>,
 3302    ) -> gpui::Subscription {
 3303        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3304        if !other_selections.is_empty() {
 3305            self.selections.change_with(cx, |selections| {
 3306                selections.select_anchors(other_selections);
 3307            });
 3308        }
 3309
 3310        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3311            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3312                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3313                if other_selections.is_empty() {
 3314                    return;
 3315                }
 3316                this.selections.change_with(cx, |selections| {
 3317                    selections.select_anchors(other_selections);
 3318                });
 3319            }
 3320        });
 3321
 3322        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3323            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3324                let these_selections = this.selections.disjoint_anchors().to_vec();
 3325                if these_selections.is_empty() {
 3326                    return;
 3327                }
 3328                other.update(cx, |other_editor, cx| {
 3329                    other_editor.selections.change_with(cx, |selections| {
 3330                        selections.select_anchors(these_selections);
 3331                    })
 3332                });
 3333            }
 3334        });
 3335
 3336        Subscription::join(other_subscription, this_subscription)
 3337    }
 3338
 3339    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3340    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3341    /// effects of selection change occur at the end of the transaction.
 3342    pub fn change_selections<R>(
 3343        &mut self,
 3344        effects: SelectionEffects,
 3345        window: &mut Window,
 3346        cx: &mut Context<Self>,
 3347        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3348    ) -> R {
 3349        if let Some(state) = &mut self.deferred_selection_effects_state {
 3350            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3351            state.effects.completions = effects.completions;
 3352            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3353            let (changed, result) = self.selections.change_with(cx, change);
 3354            state.changed |= changed;
 3355            return result;
 3356        }
 3357        let mut state = DeferredSelectionEffectsState {
 3358            changed: false,
 3359            effects,
 3360            old_cursor_position: self.selections.newest_anchor().head(),
 3361            history_entry: SelectionHistoryEntry {
 3362                selections: self.selections.disjoint_anchors_arc(),
 3363                select_next_state: self.select_next_state.clone(),
 3364                select_prev_state: self.select_prev_state.clone(),
 3365                add_selections_state: self.add_selections_state.clone(),
 3366            },
 3367        };
 3368        let (changed, result) = self.selections.change_with(cx, change);
 3369        state.changed = state.changed || changed;
 3370        if self.defer_selection_effects {
 3371            self.deferred_selection_effects_state = Some(state);
 3372        } else {
 3373            self.apply_selection_effects(state, window, cx);
 3374        }
 3375        result
 3376    }
 3377
 3378    /// Defers the effects of selection change, so that the effects of multiple calls to
 3379    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3380    /// to selection history and the state of popovers based on selection position aren't
 3381    /// erroneously updated.
 3382    pub fn with_selection_effects_deferred<R>(
 3383        &mut self,
 3384        window: &mut Window,
 3385        cx: &mut Context<Self>,
 3386        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3387    ) -> R {
 3388        let already_deferred = self.defer_selection_effects;
 3389        self.defer_selection_effects = true;
 3390        let result = update(self, window, cx);
 3391        if !already_deferred {
 3392            self.defer_selection_effects = false;
 3393            if let Some(state) = self.deferred_selection_effects_state.take() {
 3394                self.apply_selection_effects(state, window, cx);
 3395            }
 3396        }
 3397        result
 3398    }
 3399
 3400    fn apply_selection_effects(
 3401        &mut self,
 3402        state: DeferredSelectionEffectsState,
 3403        window: &mut Window,
 3404        cx: &mut Context<Self>,
 3405    ) {
 3406        if state.changed {
 3407            self.selection_history.push(state.history_entry);
 3408
 3409            if let Some(autoscroll) = state.effects.scroll {
 3410                self.request_autoscroll(autoscroll, cx);
 3411            }
 3412
 3413            let old_cursor_position = &state.old_cursor_position;
 3414
 3415            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3416
 3417            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3418                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3419            }
 3420        }
 3421    }
 3422
 3423    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3424    where
 3425        I: IntoIterator<Item = (Range<S>, T)>,
 3426        S: ToOffset,
 3427        T: Into<Arc<str>>,
 3428    {
 3429        if self.read_only(cx) {
 3430            return;
 3431        }
 3432
 3433        self.buffer
 3434            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3435    }
 3436
 3437    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3438    where
 3439        I: IntoIterator<Item = (Range<S>, T)>,
 3440        S: ToOffset,
 3441        T: Into<Arc<str>>,
 3442    {
 3443        if self.read_only(cx) {
 3444            return;
 3445        }
 3446
 3447        self.buffer.update(cx, |buffer, cx| {
 3448            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3449        });
 3450    }
 3451
 3452    pub fn edit_with_block_indent<I, S, T>(
 3453        &mut self,
 3454        edits: I,
 3455        original_indent_columns: Vec<Option<u32>>,
 3456        cx: &mut Context<Self>,
 3457    ) where
 3458        I: IntoIterator<Item = (Range<S>, T)>,
 3459        S: ToOffset,
 3460        T: Into<Arc<str>>,
 3461    {
 3462        if self.read_only(cx) {
 3463            return;
 3464        }
 3465
 3466        self.buffer.update(cx, |buffer, cx| {
 3467            buffer.edit(
 3468                edits,
 3469                Some(AutoindentMode::Block {
 3470                    original_indent_columns,
 3471                }),
 3472                cx,
 3473            )
 3474        });
 3475    }
 3476
 3477    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3478        self.hide_context_menu(window, cx);
 3479
 3480        match phase {
 3481            SelectPhase::Begin {
 3482                position,
 3483                add,
 3484                click_count,
 3485            } => self.begin_selection(position, add, click_count, window, cx),
 3486            SelectPhase::BeginColumnar {
 3487                position,
 3488                goal_column,
 3489                reset,
 3490                mode,
 3491            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3492            SelectPhase::Extend {
 3493                position,
 3494                click_count,
 3495            } => self.extend_selection(position, click_count, window, cx),
 3496            SelectPhase::Update {
 3497                position,
 3498                goal_column,
 3499                scroll_delta,
 3500            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3501            SelectPhase::End => self.end_selection(window, cx),
 3502        }
 3503    }
 3504
 3505    fn extend_selection(
 3506        &mut self,
 3507        position: DisplayPoint,
 3508        click_count: usize,
 3509        window: &mut Window,
 3510        cx: &mut Context<Self>,
 3511    ) {
 3512        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3513        let tail = self.selections.newest::<usize>(cx).tail();
 3514        self.begin_selection(position, false, click_count, window, cx);
 3515
 3516        let position = position.to_offset(&display_map, Bias::Left);
 3517        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3518
 3519        let mut pending_selection = self
 3520            .selections
 3521            .pending_anchor()
 3522            .cloned()
 3523            .expect("extend_selection not called with pending selection");
 3524        if position >= tail {
 3525            pending_selection.start = tail_anchor;
 3526        } else {
 3527            pending_selection.end = tail_anchor;
 3528            pending_selection.reversed = true;
 3529        }
 3530
 3531        let mut pending_mode = self.selections.pending_mode().unwrap();
 3532        match &mut pending_mode {
 3533            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3534            _ => {}
 3535        }
 3536
 3537        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3538            SelectionEffects::scroll(Autoscroll::fit())
 3539        } else {
 3540            SelectionEffects::no_scroll()
 3541        };
 3542
 3543        self.change_selections(effects, window, cx, |s| {
 3544            s.set_pending(pending_selection.clone(), pending_mode)
 3545        });
 3546    }
 3547
 3548    fn begin_selection(
 3549        &mut self,
 3550        position: DisplayPoint,
 3551        add: bool,
 3552        click_count: usize,
 3553        window: &mut Window,
 3554        cx: &mut Context<Self>,
 3555    ) {
 3556        if !self.focus_handle.is_focused(window) {
 3557            self.last_focused_descendant = None;
 3558            window.focus(&self.focus_handle);
 3559        }
 3560
 3561        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3562        let buffer = display_map.buffer_snapshot();
 3563        let position = display_map.clip_point(position, Bias::Left);
 3564
 3565        let start;
 3566        let end;
 3567        let mode;
 3568        let mut auto_scroll;
 3569        match click_count {
 3570            1 => {
 3571                start = buffer.anchor_before(position.to_point(&display_map));
 3572                end = start;
 3573                mode = SelectMode::Character;
 3574                auto_scroll = true;
 3575            }
 3576            2 => {
 3577                let position = display_map
 3578                    .clip_point(position, Bias::Left)
 3579                    .to_offset(&display_map, Bias::Left);
 3580                let (range, _) = buffer.surrounding_word(position, None);
 3581                start = buffer.anchor_before(range.start);
 3582                end = buffer.anchor_before(range.end);
 3583                mode = SelectMode::Word(start..end);
 3584                auto_scroll = true;
 3585            }
 3586            3 => {
 3587                let position = display_map
 3588                    .clip_point(position, Bias::Left)
 3589                    .to_point(&display_map);
 3590                let line_start = display_map.prev_line_boundary(position).0;
 3591                let next_line_start = buffer.clip_point(
 3592                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3593                    Bias::Left,
 3594                );
 3595                start = buffer.anchor_before(line_start);
 3596                end = buffer.anchor_before(next_line_start);
 3597                mode = SelectMode::Line(start..end);
 3598                auto_scroll = true;
 3599            }
 3600            _ => {
 3601                start = buffer.anchor_before(0);
 3602                end = buffer.anchor_before(buffer.len());
 3603                mode = SelectMode::All;
 3604                auto_scroll = false;
 3605            }
 3606        }
 3607        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3608
 3609        let point_to_delete: Option<usize> = {
 3610            let selected_points: Vec<Selection<Point>> =
 3611                self.selections.disjoint_in_range(start..end, cx);
 3612
 3613            if !add || click_count > 1 {
 3614                None
 3615            } else if !selected_points.is_empty() {
 3616                Some(selected_points[0].id)
 3617            } else {
 3618                let clicked_point_already_selected =
 3619                    self.selections.disjoint_anchors().iter().find(|selection| {
 3620                        selection.start.to_point(buffer) == start.to_point(buffer)
 3621                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3622                    });
 3623
 3624                clicked_point_already_selected.map(|selection| selection.id)
 3625            }
 3626        };
 3627
 3628        let selections_count = self.selections.count();
 3629        let effects = if auto_scroll {
 3630            SelectionEffects::default()
 3631        } else {
 3632            SelectionEffects::no_scroll()
 3633        };
 3634
 3635        self.change_selections(effects, window, cx, |s| {
 3636            if let Some(point_to_delete) = point_to_delete {
 3637                s.delete(point_to_delete);
 3638
 3639                if selections_count == 1 {
 3640                    s.set_pending_anchor_range(start..end, mode);
 3641                }
 3642            } else {
 3643                if !add {
 3644                    s.clear_disjoint();
 3645                }
 3646
 3647                s.set_pending_anchor_range(start..end, mode);
 3648            }
 3649        });
 3650    }
 3651
 3652    fn begin_columnar_selection(
 3653        &mut self,
 3654        position: DisplayPoint,
 3655        goal_column: u32,
 3656        reset: bool,
 3657        mode: ColumnarMode,
 3658        window: &mut Window,
 3659        cx: &mut Context<Self>,
 3660    ) {
 3661        if !self.focus_handle.is_focused(window) {
 3662            self.last_focused_descendant = None;
 3663            window.focus(&self.focus_handle);
 3664        }
 3665
 3666        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3667
 3668        if reset {
 3669            let pointer_position = display_map
 3670                .buffer_snapshot()
 3671                .anchor_before(position.to_point(&display_map));
 3672
 3673            self.change_selections(
 3674                SelectionEffects::scroll(Autoscroll::newest()),
 3675                window,
 3676                cx,
 3677                |s| {
 3678                    s.clear_disjoint();
 3679                    s.set_pending_anchor_range(
 3680                        pointer_position..pointer_position,
 3681                        SelectMode::Character,
 3682                    );
 3683                },
 3684            );
 3685        };
 3686
 3687        let tail = self.selections.newest::<Point>(cx).tail();
 3688        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3689        self.columnar_selection_state = match mode {
 3690            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3691                selection_tail: selection_anchor,
 3692                display_point: if reset {
 3693                    if position.column() != goal_column {
 3694                        Some(DisplayPoint::new(position.row(), goal_column))
 3695                    } else {
 3696                        None
 3697                    }
 3698                } else {
 3699                    None
 3700                },
 3701            }),
 3702            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3703                selection_tail: selection_anchor,
 3704            }),
 3705        };
 3706
 3707        if !reset {
 3708            self.select_columns(position, goal_column, &display_map, window, cx);
 3709        }
 3710    }
 3711
 3712    fn update_selection(
 3713        &mut self,
 3714        position: DisplayPoint,
 3715        goal_column: u32,
 3716        scroll_delta: gpui::Point<f32>,
 3717        window: &mut Window,
 3718        cx: &mut Context<Self>,
 3719    ) {
 3720        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3721
 3722        if self.columnar_selection_state.is_some() {
 3723            self.select_columns(position, goal_column, &display_map, window, cx);
 3724        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3725            let buffer = display_map.buffer_snapshot();
 3726            let head;
 3727            let tail;
 3728            let mode = self.selections.pending_mode().unwrap();
 3729            match &mode {
 3730                SelectMode::Character => {
 3731                    head = position.to_point(&display_map);
 3732                    tail = pending.tail().to_point(buffer);
 3733                }
 3734                SelectMode::Word(original_range) => {
 3735                    let offset = display_map
 3736                        .clip_point(position, Bias::Left)
 3737                        .to_offset(&display_map, Bias::Left);
 3738                    let original_range = original_range.to_offset(buffer);
 3739
 3740                    let head_offset = if buffer.is_inside_word(offset, None)
 3741                        || original_range.contains(&offset)
 3742                    {
 3743                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3744                        if word_range.start < original_range.start {
 3745                            word_range.start
 3746                        } else {
 3747                            word_range.end
 3748                        }
 3749                    } else {
 3750                        offset
 3751                    };
 3752
 3753                    head = head_offset.to_point(buffer);
 3754                    if head_offset <= original_range.start {
 3755                        tail = original_range.end.to_point(buffer);
 3756                    } else {
 3757                        tail = original_range.start.to_point(buffer);
 3758                    }
 3759                }
 3760                SelectMode::Line(original_range) => {
 3761                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3762
 3763                    let position = display_map
 3764                        .clip_point(position, Bias::Left)
 3765                        .to_point(&display_map);
 3766                    let line_start = display_map.prev_line_boundary(position).0;
 3767                    let next_line_start = buffer.clip_point(
 3768                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3769                        Bias::Left,
 3770                    );
 3771
 3772                    if line_start < original_range.start {
 3773                        head = line_start
 3774                    } else {
 3775                        head = next_line_start
 3776                    }
 3777
 3778                    if head <= original_range.start {
 3779                        tail = original_range.end;
 3780                    } else {
 3781                        tail = original_range.start;
 3782                    }
 3783                }
 3784                SelectMode::All => {
 3785                    return;
 3786                }
 3787            };
 3788
 3789            if head < tail {
 3790                pending.start = buffer.anchor_before(head);
 3791                pending.end = buffer.anchor_before(tail);
 3792                pending.reversed = true;
 3793            } else {
 3794                pending.start = buffer.anchor_before(tail);
 3795                pending.end = buffer.anchor_before(head);
 3796                pending.reversed = false;
 3797            }
 3798
 3799            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3800                s.set_pending(pending.clone(), mode);
 3801            });
 3802        } else {
 3803            log::error!("update_selection dispatched with no pending selection");
 3804            return;
 3805        }
 3806
 3807        self.apply_scroll_delta(scroll_delta, window, cx);
 3808        cx.notify();
 3809    }
 3810
 3811    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3812        self.columnar_selection_state.take();
 3813        if self.selections.pending_anchor().is_some() {
 3814            let selections = self.selections.all::<usize>(cx);
 3815            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3816                s.select(selections);
 3817                s.clear_pending();
 3818            });
 3819        }
 3820    }
 3821
 3822    fn select_columns(
 3823        &mut self,
 3824        head: DisplayPoint,
 3825        goal_column: u32,
 3826        display_map: &DisplaySnapshot,
 3827        window: &mut Window,
 3828        cx: &mut Context<Self>,
 3829    ) {
 3830        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3831            return;
 3832        };
 3833
 3834        let tail = match columnar_state {
 3835            ColumnarSelectionState::FromMouse {
 3836                selection_tail,
 3837                display_point,
 3838            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3839            ColumnarSelectionState::FromSelection { selection_tail } => {
 3840                selection_tail.to_display_point(display_map)
 3841            }
 3842        };
 3843
 3844        let start_row = cmp::min(tail.row(), head.row());
 3845        let end_row = cmp::max(tail.row(), head.row());
 3846        let start_column = cmp::min(tail.column(), goal_column);
 3847        let end_column = cmp::max(tail.column(), goal_column);
 3848        let reversed = start_column < tail.column();
 3849
 3850        let selection_ranges = (start_row.0..=end_row.0)
 3851            .map(DisplayRow)
 3852            .filter_map(|row| {
 3853                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3854                    || start_column <= display_map.line_len(row))
 3855                    && !display_map.is_block_line(row)
 3856                {
 3857                    let start = display_map
 3858                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3859                        .to_point(display_map);
 3860                    let end = display_map
 3861                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3862                        .to_point(display_map);
 3863                    if reversed {
 3864                        Some(end..start)
 3865                    } else {
 3866                        Some(start..end)
 3867                    }
 3868                } else {
 3869                    None
 3870                }
 3871            })
 3872            .collect::<Vec<_>>();
 3873
 3874        let ranges = match columnar_state {
 3875            ColumnarSelectionState::FromMouse { .. } => {
 3876                let mut non_empty_ranges = selection_ranges
 3877                    .iter()
 3878                    .filter(|selection_range| selection_range.start != selection_range.end)
 3879                    .peekable();
 3880                if non_empty_ranges.peek().is_some() {
 3881                    non_empty_ranges.cloned().collect()
 3882                } else {
 3883                    selection_ranges
 3884                }
 3885            }
 3886            _ => selection_ranges,
 3887        };
 3888
 3889        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3890            s.select_ranges(ranges);
 3891        });
 3892        cx.notify();
 3893    }
 3894
 3895    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3896        self.selections
 3897            .all_adjusted(cx)
 3898            .iter()
 3899            .any(|selection| !selection.is_empty())
 3900    }
 3901
 3902    pub fn has_pending_nonempty_selection(&self) -> bool {
 3903        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3904            Some(Selection { start, end, .. }) => start != end,
 3905            None => false,
 3906        };
 3907
 3908        pending_nonempty_selection
 3909            || (self.columnar_selection_state.is_some()
 3910                && self.selections.disjoint_anchors().len() > 1)
 3911    }
 3912
 3913    pub fn has_pending_selection(&self) -> bool {
 3914        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3915    }
 3916
 3917    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3918        self.selection_mark_mode = false;
 3919        self.selection_drag_state = SelectionDragState::None;
 3920
 3921        if self.clear_expanded_diff_hunks(cx) {
 3922            cx.notify();
 3923            return;
 3924        }
 3925        if self.dismiss_menus_and_popups(true, window, cx) {
 3926            return;
 3927        }
 3928
 3929        if self.mode.is_full()
 3930            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3931        {
 3932            return;
 3933        }
 3934
 3935        cx.propagate();
 3936    }
 3937
 3938    pub fn dismiss_menus_and_popups(
 3939        &mut self,
 3940        is_user_requested: bool,
 3941        window: &mut Window,
 3942        cx: &mut Context<Self>,
 3943    ) -> bool {
 3944        if self.take_rename(false, window, cx).is_some() {
 3945            return true;
 3946        }
 3947
 3948        if hide_hover(self, cx) {
 3949            return true;
 3950        }
 3951
 3952        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3953            return true;
 3954        }
 3955
 3956        if self.hide_context_menu(window, cx).is_some() {
 3957            return true;
 3958        }
 3959
 3960        if self.mouse_context_menu.take().is_some() {
 3961            return true;
 3962        }
 3963
 3964        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3965            return true;
 3966        }
 3967
 3968        if self.snippet_stack.pop().is_some() {
 3969            return true;
 3970        }
 3971
 3972        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3973            self.dismiss_diagnostics(cx);
 3974            return true;
 3975        }
 3976
 3977        false
 3978    }
 3979
 3980    fn linked_editing_ranges_for(
 3981        &self,
 3982        selection: Range<text::Anchor>,
 3983        cx: &App,
 3984    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3985        if self.linked_edit_ranges.is_empty() {
 3986            return None;
 3987        }
 3988        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3989            selection.end.buffer_id.and_then(|end_buffer_id| {
 3990                if selection.start.buffer_id != Some(end_buffer_id) {
 3991                    return None;
 3992                }
 3993                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3994                let snapshot = buffer.read(cx).snapshot();
 3995                self.linked_edit_ranges
 3996                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3997                    .map(|ranges| (ranges, snapshot, buffer))
 3998            })?;
 3999        use text::ToOffset as TO;
 4000        // find offset from the start of current range to current cursor position
 4001        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4002
 4003        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4004        let start_difference = start_offset - start_byte_offset;
 4005        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4006        let end_difference = end_offset - start_byte_offset;
 4007        // Current range has associated linked ranges.
 4008        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4009        for range in linked_ranges.iter() {
 4010            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4011            let end_offset = start_offset + end_difference;
 4012            let start_offset = start_offset + start_difference;
 4013            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4014                continue;
 4015            }
 4016            if self.selections.disjoint_anchor_ranges().any(|s| {
 4017                if s.start.buffer_id != selection.start.buffer_id
 4018                    || s.end.buffer_id != selection.end.buffer_id
 4019                {
 4020                    return false;
 4021                }
 4022                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4023                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4024            }) {
 4025                continue;
 4026            }
 4027            let start = buffer_snapshot.anchor_after(start_offset);
 4028            let end = buffer_snapshot.anchor_after(end_offset);
 4029            linked_edits
 4030                .entry(buffer.clone())
 4031                .or_default()
 4032                .push(start..end);
 4033        }
 4034        Some(linked_edits)
 4035    }
 4036
 4037    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4038        let text: Arc<str> = text.into();
 4039
 4040        if self.read_only(cx) {
 4041            return;
 4042        }
 4043
 4044        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4045
 4046        let selections = self.selections.all_adjusted(cx);
 4047        let mut bracket_inserted = false;
 4048        let mut edits = Vec::new();
 4049        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4050        let mut new_selections = Vec::with_capacity(selections.len());
 4051        let mut new_autoclose_regions = Vec::new();
 4052        let snapshot = self.buffer.read(cx).read(cx);
 4053        let mut clear_linked_edit_ranges = false;
 4054
 4055        for (selection, autoclose_region) in
 4056            self.selections_with_autoclose_regions(selections, &snapshot)
 4057        {
 4058            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4059                // Determine if the inserted text matches the opening or closing
 4060                // bracket of any of this language's bracket pairs.
 4061                let mut bracket_pair = None;
 4062                let mut is_bracket_pair_start = false;
 4063                let mut is_bracket_pair_end = false;
 4064                if !text.is_empty() {
 4065                    let mut bracket_pair_matching_end = None;
 4066                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4067                    //  and they are removing the character that triggered IME popup.
 4068                    for (pair, enabled) in scope.brackets() {
 4069                        if !pair.close && !pair.surround {
 4070                            continue;
 4071                        }
 4072
 4073                        if enabled && pair.start.ends_with(text.as_ref()) {
 4074                            let prefix_len = pair.start.len() - text.len();
 4075                            let preceding_text_matches_prefix = prefix_len == 0
 4076                                || (selection.start.column >= (prefix_len as u32)
 4077                                    && snapshot.contains_str_at(
 4078                                        Point::new(
 4079                                            selection.start.row,
 4080                                            selection.start.column - (prefix_len as u32),
 4081                                        ),
 4082                                        &pair.start[..prefix_len],
 4083                                    ));
 4084                            if preceding_text_matches_prefix {
 4085                                bracket_pair = Some(pair.clone());
 4086                                is_bracket_pair_start = true;
 4087                                break;
 4088                            }
 4089                        }
 4090                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4091                        {
 4092                            // take first bracket pair matching end, but don't break in case a later bracket
 4093                            // pair matches start
 4094                            bracket_pair_matching_end = Some(pair.clone());
 4095                        }
 4096                    }
 4097                    if let Some(end) = bracket_pair_matching_end
 4098                        && bracket_pair.is_none()
 4099                    {
 4100                        bracket_pair = Some(end);
 4101                        is_bracket_pair_end = true;
 4102                    }
 4103                }
 4104
 4105                if let Some(bracket_pair) = bracket_pair {
 4106                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4107                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4108                    let auto_surround =
 4109                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4110                    if selection.is_empty() {
 4111                        if is_bracket_pair_start {
 4112                            // If the inserted text is a suffix of an opening bracket and the
 4113                            // selection is preceded by the rest of the opening bracket, then
 4114                            // insert the closing bracket.
 4115                            let following_text_allows_autoclose = snapshot
 4116                                .chars_at(selection.start)
 4117                                .next()
 4118                                .is_none_or(|c| scope.should_autoclose_before(c));
 4119
 4120                            let preceding_text_allows_autoclose = selection.start.column == 0
 4121                                || snapshot
 4122                                    .reversed_chars_at(selection.start)
 4123                                    .next()
 4124                                    .is_none_or(|c| {
 4125                                        bracket_pair.start != bracket_pair.end
 4126                                            || !snapshot
 4127                                                .char_classifier_at(selection.start)
 4128                                                .is_word(c)
 4129                                    });
 4130
 4131                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4132                                && bracket_pair.start.len() == 1
 4133                            {
 4134                                let target = bracket_pair.start.chars().next().unwrap();
 4135                                let current_line_count = snapshot
 4136                                    .reversed_chars_at(selection.start)
 4137                                    .take_while(|&c| c != '\n')
 4138                                    .filter(|&c| c == target)
 4139                                    .count();
 4140                                current_line_count % 2 == 1
 4141                            } else {
 4142                                false
 4143                            };
 4144
 4145                            if autoclose
 4146                                && bracket_pair.close
 4147                                && following_text_allows_autoclose
 4148                                && preceding_text_allows_autoclose
 4149                                && !is_closing_quote
 4150                            {
 4151                                let anchor = snapshot.anchor_before(selection.end);
 4152                                new_selections.push((selection.map(|_| anchor), text.len()));
 4153                                new_autoclose_regions.push((
 4154                                    anchor,
 4155                                    text.len(),
 4156                                    selection.id,
 4157                                    bracket_pair.clone(),
 4158                                ));
 4159                                edits.push((
 4160                                    selection.range(),
 4161                                    format!("{}{}", text, bracket_pair.end).into(),
 4162                                ));
 4163                                bracket_inserted = true;
 4164                                continue;
 4165                            }
 4166                        }
 4167
 4168                        if let Some(region) = autoclose_region {
 4169                            // If the selection is followed by an auto-inserted closing bracket,
 4170                            // then don't insert that closing bracket again; just move the selection
 4171                            // past the closing bracket.
 4172                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4173                                && text.as_ref() == region.pair.end.as_str()
 4174                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4175                            if should_skip {
 4176                                let anchor = snapshot.anchor_after(selection.end);
 4177                                new_selections
 4178                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4179                                continue;
 4180                            }
 4181                        }
 4182
 4183                        let always_treat_brackets_as_autoclosed = snapshot
 4184                            .language_settings_at(selection.start, cx)
 4185                            .always_treat_brackets_as_autoclosed;
 4186                        if always_treat_brackets_as_autoclosed
 4187                            && is_bracket_pair_end
 4188                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4189                        {
 4190                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4191                            // and the inserted text is a closing bracket and the selection is followed
 4192                            // by the closing bracket then move the selection past the closing bracket.
 4193                            let anchor = snapshot.anchor_after(selection.end);
 4194                            new_selections.push((selection.map(|_| anchor), text.len()));
 4195                            continue;
 4196                        }
 4197                    }
 4198                    // If an opening bracket is 1 character long and is typed while
 4199                    // text is selected, then surround that text with the bracket pair.
 4200                    else if auto_surround
 4201                        && bracket_pair.surround
 4202                        && is_bracket_pair_start
 4203                        && bracket_pair.start.chars().count() == 1
 4204                    {
 4205                        edits.push((selection.start..selection.start, text.clone()));
 4206                        edits.push((
 4207                            selection.end..selection.end,
 4208                            bracket_pair.end.as_str().into(),
 4209                        ));
 4210                        bracket_inserted = true;
 4211                        new_selections.push((
 4212                            Selection {
 4213                                id: selection.id,
 4214                                start: snapshot.anchor_after(selection.start),
 4215                                end: snapshot.anchor_before(selection.end),
 4216                                reversed: selection.reversed,
 4217                                goal: selection.goal,
 4218                            },
 4219                            0,
 4220                        ));
 4221                        continue;
 4222                    }
 4223                }
 4224            }
 4225
 4226            if self.auto_replace_emoji_shortcode
 4227                && selection.is_empty()
 4228                && text.as_ref().ends_with(':')
 4229                && let Some(possible_emoji_short_code) =
 4230                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4231                && !possible_emoji_short_code.is_empty()
 4232                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4233            {
 4234                let emoji_shortcode_start = Point::new(
 4235                    selection.start.row,
 4236                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4237                );
 4238
 4239                // Remove shortcode from buffer
 4240                edits.push((
 4241                    emoji_shortcode_start..selection.start,
 4242                    "".to_string().into(),
 4243                ));
 4244                new_selections.push((
 4245                    Selection {
 4246                        id: selection.id,
 4247                        start: snapshot.anchor_after(emoji_shortcode_start),
 4248                        end: snapshot.anchor_before(selection.start),
 4249                        reversed: selection.reversed,
 4250                        goal: selection.goal,
 4251                    },
 4252                    0,
 4253                ));
 4254
 4255                // Insert emoji
 4256                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4257                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4258                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4259
 4260                continue;
 4261            }
 4262
 4263            // If not handling any auto-close operation, then just replace the selected
 4264            // text with the given input and move the selection to the end of the
 4265            // newly inserted text.
 4266            let anchor = snapshot.anchor_after(selection.end);
 4267            if !self.linked_edit_ranges.is_empty() {
 4268                let start_anchor = snapshot.anchor_before(selection.start);
 4269
 4270                let is_word_char = text.chars().next().is_none_or(|char| {
 4271                    let classifier = snapshot
 4272                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4273                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4274                    classifier.is_word(char)
 4275                });
 4276
 4277                if is_word_char {
 4278                    if let Some(ranges) = self
 4279                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4280                    {
 4281                        for (buffer, edits) in ranges {
 4282                            linked_edits
 4283                                .entry(buffer.clone())
 4284                                .or_default()
 4285                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4286                        }
 4287                    }
 4288                } else {
 4289                    clear_linked_edit_ranges = true;
 4290                }
 4291            }
 4292
 4293            new_selections.push((selection.map(|_| anchor), 0));
 4294            edits.push((selection.start..selection.end, text.clone()));
 4295        }
 4296
 4297        drop(snapshot);
 4298
 4299        self.transact(window, cx, |this, window, cx| {
 4300            if clear_linked_edit_ranges {
 4301                this.linked_edit_ranges.clear();
 4302            }
 4303            let initial_buffer_versions =
 4304                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4305
 4306            this.buffer.update(cx, |buffer, cx| {
 4307                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4308            });
 4309            for (buffer, edits) in linked_edits {
 4310                buffer.update(cx, |buffer, cx| {
 4311                    let snapshot = buffer.snapshot();
 4312                    let edits = edits
 4313                        .into_iter()
 4314                        .map(|(range, text)| {
 4315                            use text::ToPoint as TP;
 4316                            let end_point = TP::to_point(&range.end, &snapshot);
 4317                            let start_point = TP::to_point(&range.start, &snapshot);
 4318                            (start_point..end_point, text)
 4319                        })
 4320                        .sorted_by_key(|(range, _)| range.start);
 4321                    buffer.edit(edits, None, cx);
 4322                })
 4323            }
 4324            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4325            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4326            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4327            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4328                .zip(new_selection_deltas)
 4329                .map(|(selection, delta)| Selection {
 4330                    id: selection.id,
 4331                    start: selection.start + delta,
 4332                    end: selection.end + delta,
 4333                    reversed: selection.reversed,
 4334                    goal: SelectionGoal::None,
 4335                })
 4336                .collect::<Vec<_>>();
 4337
 4338            let mut i = 0;
 4339            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4340                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4341                let start = map.buffer_snapshot().anchor_before(position);
 4342                let end = map.buffer_snapshot().anchor_after(position);
 4343                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4344                    match existing_state
 4345                        .range
 4346                        .start
 4347                        .cmp(&start, map.buffer_snapshot())
 4348                    {
 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()?)?;
 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.buffer_kind(cx) == ItemBufferKind::Singleton
 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
10450            // Accumulate contiguous regions of rows that we want to delete.
10451            while let Some(next_selection) = selections.peek() {
10452                let next_rows = next_selection.spanned_rows(false, &display_map);
10453                if next_rows.start <= rows.end {
10454                    rows.end = next_rows.end;
10455                    selections.next().unwrap();
10456                } else {
10457                    break;
10458                }
10459            }
10460
10461            let buffer = display_map.buffer_snapshot();
10462            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10463            let edit_end = if buffer.max_point().row >= rows.end.0 {
10464                // If there's a line after the range, delete the \n from the end of the row range
10465                ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer)
10466            } else {
10467                // If there isn't a line after the range, delete the \n from the line before the
10468                // start of the row range
10469                edit_start = edit_start.saturating_sub(1);
10470                buffer.len()
10471            };
10472
10473            let (cursor, goal) = movement::down_by_rows(
10474                &display_map,
10475                selection.head().to_display_point(&display_map),
10476                rows.len() as u32,
10477                selection.goal,
10478                false,
10479                &self.text_layout_details(window),
10480            );
10481
10482            new_cursors.push((
10483                selection.id,
10484                buffer.anchor_after(cursor.to_point(&display_map)),
10485                goal,
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, goal)| {
10505                    let cursor = cursor.to_point(&buffer);
10506                    Selection {
10507                        id,
10508                        start: cursor,
10509                        end: cursor,
10510                        reversed: false,
10511                        goal,
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
11691                let mut text = buffer.text_for_range(start..end).collect::<String>();
11692
11693                let insert_location = if upwards {
11694                    // When duplicating upward, we need to insert before the current line.
11695                    // If we're on the last line and it doesn't end with a newline,
11696                    // we need to add a newline before the duplicated content.
11697                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11698                        && buffer.max_point().column > 0
11699                        && !text.ends_with('\n');
11700
11701                    if needs_leading_newline {
11702                        text.insert(0, '\n');
11703                        end
11704                    } else {
11705                        text.push('\n');
11706                        Point::new(rows.end.0, 0)
11707                    }
11708                } else {
11709                    text.push('\n');
11710                    start
11711                };
11712                edits.push((insert_location..insert_location, text));
11713            } else {
11714                // duplicate character-wise
11715                let start = selection.start;
11716                let end = selection.end;
11717                let text = buffer.text_for_range(start..end).collect::<String>();
11718                edits.push((selection.end..selection.end, text));
11719            }
11720        }
11721
11722        self.transact(window, cx, |this, _, cx| {
11723            this.buffer.update(cx, |buffer, cx| {
11724                buffer.edit(edits, None, cx);
11725            });
11726
11727            this.request_autoscroll(Autoscroll::fit(), cx);
11728        });
11729    }
11730
11731    pub fn duplicate_line_up(
11732        &mut self,
11733        _: &DuplicateLineUp,
11734        window: &mut Window,
11735        cx: &mut Context<Self>,
11736    ) {
11737        self.duplicate(true, true, window, cx);
11738    }
11739
11740    pub fn duplicate_line_down(
11741        &mut self,
11742        _: &DuplicateLineDown,
11743        window: &mut Window,
11744        cx: &mut Context<Self>,
11745    ) {
11746        self.duplicate(false, true, window, cx);
11747    }
11748
11749    pub fn duplicate_selection(
11750        &mut self,
11751        _: &DuplicateSelection,
11752        window: &mut Window,
11753        cx: &mut Context<Self>,
11754    ) {
11755        self.duplicate(false, false, window, cx);
11756    }
11757
11758    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11760        if self.mode.is_single_line() {
11761            cx.propagate();
11762            return;
11763        }
11764
11765        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11766        let buffer = self.buffer.read(cx).snapshot(cx);
11767
11768        let mut edits = Vec::new();
11769        let mut unfold_ranges = Vec::new();
11770        let mut refold_creases = Vec::new();
11771
11772        let selections = self.selections.all::<Point>(cx);
11773        let mut selections = selections.iter().peekable();
11774        let mut contiguous_row_selections = Vec::new();
11775        let mut new_selections = Vec::new();
11776
11777        while let Some(selection) = selections.next() {
11778            // Find all the selections that span a contiguous row range
11779            let (start_row, end_row) = consume_contiguous_rows(
11780                &mut contiguous_row_selections,
11781                selection,
11782                &display_map,
11783                &mut selections,
11784            );
11785
11786            // Move the text spanned by the row range to be before the line preceding the row range
11787            if start_row.0 > 0 {
11788                let range_to_move = Point::new(
11789                    start_row.previous_row().0,
11790                    buffer.line_len(start_row.previous_row()),
11791                )
11792                    ..Point::new(
11793                        end_row.previous_row().0,
11794                        buffer.line_len(end_row.previous_row()),
11795                    );
11796                let insertion_point = display_map
11797                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11798                    .0;
11799
11800                // Don't move lines across excerpts
11801                if buffer
11802                    .excerpt_containing(insertion_point..range_to_move.end)
11803                    .is_some()
11804                {
11805                    let text = buffer
11806                        .text_for_range(range_to_move.clone())
11807                        .flat_map(|s| s.chars())
11808                        .skip(1)
11809                        .chain(['\n'])
11810                        .collect::<String>();
11811
11812                    edits.push((
11813                        buffer.anchor_after(range_to_move.start)
11814                            ..buffer.anchor_before(range_to_move.end),
11815                        String::new(),
11816                    ));
11817                    let insertion_anchor = buffer.anchor_after(insertion_point);
11818                    edits.push((insertion_anchor..insertion_anchor, text));
11819
11820                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11821
11822                    // Move selections up
11823                    new_selections.extend(contiguous_row_selections.drain(..).map(
11824                        |mut selection| {
11825                            selection.start.row -= row_delta;
11826                            selection.end.row -= row_delta;
11827                            selection
11828                        },
11829                    ));
11830
11831                    // Move folds up
11832                    unfold_ranges.push(range_to_move.clone());
11833                    for fold in display_map.folds_in_range(
11834                        buffer.anchor_before(range_to_move.start)
11835                            ..buffer.anchor_after(range_to_move.end),
11836                    ) {
11837                        let mut start = fold.range.start.to_point(&buffer);
11838                        let mut end = fold.range.end.to_point(&buffer);
11839                        start.row -= row_delta;
11840                        end.row -= row_delta;
11841                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11842                    }
11843                }
11844            }
11845
11846            // If we didn't move line(s), preserve the existing selections
11847            new_selections.append(&mut contiguous_row_selections);
11848        }
11849
11850        self.transact(window, cx, |this, window, cx| {
11851            this.unfold_ranges(&unfold_ranges, true, true, cx);
11852            this.buffer.update(cx, |buffer, cx| {
11853                for (range, text) in edits {
11854                    buffer.edit([(range, text)], None, cx);
11855                }
11856            });
11857            this.fold_creases(refold_creases, true, window, cx);
11858            this.change_selections(Default::default(), window, cx, |s| {
11859                s.select(new_selections);
11860            })
11861        });
11862    }
11863
11864    pub fn move_line_down(
11865        &mut self,
11866        _: &MoveLineDown,
11867        window: &mut Window,
11868        cx: &mut Context<Self>,
11869    ) {
11870        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11871        if self.mode.is_single_line() {
11872            cx.propagate();
11873            return;
11874        }
11875
11876        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11877        let buffer = self.buffer.read(cx).snapshot(cx);
11878
11879        let mut edits = Vec::new();
11880        let mut unfold_ranges = Vec::new();
11881        let mut refold_creases = Vec::new();
11882
11883        let selections = self.selections.all::<Point>(cx);
11884        let mut selections = selections.iter().peekable();
11885        let mut contiguous_row_selections = Vec::new();
11886        let mut new_selections = Vec::new();
11887
11888        while let Some(selection) = selections.next() {
11889            // Find all the selections that span a contiguous row range
11890            let (start_row, end_row) = consume_contiguous_rows(
11891                &mut contiguous_row_selections,
11892                selection,
11893                &display_map,
11894                &mut selections,
11895            );
11896
11897            // Move the text spanned by the row range to be after the last line of the row range
11898            if end_row.0 <= buffer.max_point().row {
11899                let range_to_move =
11900                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11901                let insertion_point = display_map
11902                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11903                    .0;
11904
11905                // Don't move lines across excerpt boundaries
11906                if buffer
11907                    .excerpt_containing(range_to_move.start..insertion_point)
11908                    .is_some()
11909                {
11910                    let mut text = String::from("\n");
11911                    text.extend(buffer.text_for_range(range_to_move.clone()));
11912                    text.pop(); // Drop trailing newline
11913                    edits.push((
11914                        buffer.anchor_after(range_to_move.start)
11915                            ..buffer.anchor_before(range_to_move.end),
11916                        String::new(),
11917                    ));
11918                    let insertion_anchor = buffer.anchor_after(insertion_point);
11919                    edits.push((insertion_anchor..insertion_anchor, text));
11920
11921                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11922
11923                    // Move selections down
11924                    new_selections.extend(contiguous_row_selections.drain(..).map(
11925                        |mut selection| {
11926                            selection.start.row += row_delta;
11927                            selection.end.row += row_delta;
11928                            selection
11929                        },
11930                    ));
11931
11932                    // Move folds down
11933                    unfold_ranges.push(range_to_move.clone());
11934                    for fold in display_map.folds_in_range(
11935                        buffer.anchor_before(range_to_move.start)
11936                            ..buffer.anchor_after(range_to_move.end),
11937                    ) {
11938                        let mut start = fold.range.start.to_point(&buffer);
11939                        let mut end = fold.range.end.to_point(&buffer);
11940                        start.row += row_delta;
11941                        end.row += row_delta;
11942                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11943                    }
11944                }
11945            }
11946
11947            // If we didn't move line(s), preserve the existing selections
11948            new_selections.append(&mut contiguous_row_selections);
11949        }
11950
11951        self.transact(window, cx, |this, window, cx| {
11952            this.unfold_ranges(&unfold_ranges, true, true, cx);
11953            this.buffer.update(cx, |buffer, cx| {
11954                for (range, text) in edits {
11955                    buffer.edit([(range, text)], None, cx);
11956                }
11957            });
11958            this.fold_creases(refold_creases, true, window, cx);
11959            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11960        });
11961    }
11962
11963    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11964        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11965        let text_layout_details = &self.text_layout_details(window);
11966        self.transact(window, cx, |this, window, cx| {
11967            let edits = this.change_selections(Default::default(), window, cx, |s| {
11968                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11969                s.move_with(|display_map, selection| {
11970                    if !selection.is_empty() {
11971                        return;
11972                    }
11973
11974                    let mut head = selection.head();
11975                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11976                    if head.column() == display_map.line_len(head.row()) {
11977                        transpose_offset = display_map
11978                            .buffer_snapshot()
11979                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11980                    }
11981
11982                    if transpose_offset == 0 {
11983                        return;
11984                    }
11985
11986                    *head.column_mut() += 1;
11987                    head = display_map.clip_point(head, Bias::Right);
11988                    let goal = SelectionGoal::HorizontalPosition(
11989                        display_map
11990                            .x_for_display_point(head, text_layout_details)
11991                            .into(),
11992                    );
11993                    selection.collapse_to(head, goal);
11994
11995                    let transpose_start = display_map
11996                        .buffer_snapshot()
11997                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11998                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11999                        let transpose_end = display_map
12000                            .buffer_snapshot()
12001                            .clip_offset(transpose_offset + 1, Bias::Right);
12002                        if let Some(ch) = display_map
12003                            .buffer_snapshot()
12004                            .chars_at(transpose_start)
12005                            .next()
12006                        {
12007                            edits.push((transpose_start..transpose_offset, String::new()));
12008                            edits.push((transpose_end..transpose_end, ch.to_string()));
12009                        }
12010                    }
12011                });
12012                edits
12013            });
12014            this.buffer
12015                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12016            let selections = this.selections.all::<usize>(cx);
12017            this.change_selections(Default::default(), window, cx, |s| {
12018                s.select(selections);
12019            });
12020        });
12021    }
12022
12023    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12024        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12025        if self.mode.is_single_line() {
12026            cx.propagate();
12027            return;
12028        }
12029
12030        self.rewrap_impl(RewrapOptions::default(), cx)
12031    }
12032
12033    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12034        let buffer = self.buffer.read(cx).snapshot(cx);
12035        let selections = self.selections.all::<Point>(cx);
12036
12037        #[derive(Clone, Debug, PartialEq)]
12038        enum CommentFormat {
12039            /// single line comment, with prefix for line
12040            Line(String),
12041            /// single line within a block comment, with prefix for line
12042            BlockLine(String),
12043            /// a single line of a block comment that includes the initial delimiter
12044            BlockCommentWithStart(BlockCommentConfig),
12045            /// a single line of a block comment that includes the ending delimiter
12046            BlockCommentWithEnd(BlockCommentConfig),
12047        }
12048
12049        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12050        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12051            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12052                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12053                .peekable();
12054
12055            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12056                row
12057            } else {
12058                return Vec::new();
12059            };
12060
12061            let language_settings = buffer.language_settings_at(selection.head(), cx);
12062            let language_scope = buffer.language_scope_at(selection.head());
12063
12064            let indent_and_prefix_for_row =
12065                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12066                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12067                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12068                        &language_scope
12069                    {
12070                        let indent_end = Point::new(row, indent.len);
12071                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12072                        let line_text_after_indent = buffer
12073                            .text_for_range(indent_end..line_end)
12074                            .collect::<String>();
12075
12076                        let is_within_comment_override = buffer
12077                            .language_scope_at(indent_end)
12078                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12079                        let comment_delimiters = if is_within_comment_override {
12080                            // we are within a comment syntax node, but we don't
12081                            // yet know what kind of comment: block, doc or line
12082                            match (
12083                                language_scope.documentation_comment(),
12084                                language_scope.block_comment(),
12085                            ) {
12086                                (Some(config), _) | (_, Some(config))
12087                                    if buffer.contains_str_at(indent_end, &config.start) =>
12088                                {
12089                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12090                                }
12091                                (Some(config), _) | (_, Some(config))
12092                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12093                                {
12094                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12095                                }
12096                                (Some(config), _) | (_, Some(config))
12097                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12098                                {
12099                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12100                                }
12101                                (_, _) => language_scope
12102                                    .line_comment_prefixes()
12103                                    .iter()
12104                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12105                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12106                            }
12107                        } else {
12108                            // we not in an overridden comment node, but we may
12109                            // be within a non-overridden line comment node
12110                            language_scope
12111                                .line_comment_prefixes()
12112                                .iter()
12113                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12114                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12115                        };
12116
12117                        let rewrap_prefix = language_scope
12118                            .rewrap_prefixes()
12119                            .iter()
12120                            .find_map(|prefix_regex| {
12121                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12122                                    if mat.start() == 0 {
12123                                        Some(mat.as_str().to_string())
12124                                    } else {
12125                                        None
12126                                    }
12127                                })
12128                            })
12129                            .flatten();
12130                        (comment_delimiters, rewrap_prefix)
12131                    } else {
12132                        (None, None)
12133                    };
12134                    (indent, comment_prefix, rewrap_prefix)
12135                };
12136
12137            let mut ranges = Vec::new();
12138            let from_empty_selection = selection.is_empty();
12139
12140            let mut current_range_start = first_row;
12141            let mut prev_row = first_row;
12142            let (
12143                mut current_range_indent,
12144                mut current_range_comment_delimiters,
12145                mut current_range_rewrap_prefix,
12146            ) = indent_and_prefix_for_row(first_row);
12147
12148            for row in non_blank_rows_iter.skip(1) {
12149                let has_paragraph_break = row > prev_row + 1;
12150
12151                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12152                    indent_and_prefix_for_row(row);
12153
12154                let has_indent_change = row_indent != current_range_indent;
12155                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12156
12157                let has_boundary_change = has_comment_change
12158                    || row_rewrap_prefix.is_some()
12159                    || (has_indent_change && current_range_comment_delimiters.is_some());
12160
12161                if has_paragraph_break || has_boundary_change {
12162                    ranges.push((
12163                        language_settings.clone(),
12164                        Point::new(current_range_start, 0)
12165                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12166                        current_range_indent,
12167                        current_range_comment_delimiters.clone(),
12168                        current_range_rewrap_prefix.clone(),
12169                        from_empty_selection,
12170                    ));
12171                    current_range_start = row;
12172                    current_range_indent = row_indent;
12173                    current_range_comment_delimiters = row_comment_delimiters;
12174                    current_range_rewrap_prefix = row_rewrap_prefix;
12175                }
12176                prev_row = row;
12177            }
12178
12179            ranges.push((
12180                language_settings.clone(),
12181                Point::new(current_range_start, 0)
12182                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12183                current_range_indent,
12184                current_range_comment_delimiters,
12185                current_range_rewrap_prefix,
12186                from_empty_selection,
12187            ));
12188
12189            ranges
12190        });
12191
12192        let mut edits = Vec::new();
12193        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12194
12195        for (
12196            language_settings,
12197            wrap_range,
12198            mut indent_size,
12199            comment_prefix,
12200            rewrap_prefix,
12201            from_empty_selection,
12202        ) in wrap_ranges
12203        {
12204            let mut start_row = wrap_range.start.row;
12205            let mut end_row = wrap_range.end.row;
12206
12207            // Skip selections that overlap with a range that has already been rewrapped.
12208            let selection_range = start_row..end_row;
12209            if rewrapped_row_ranges
12210                .iter()
12211                .any(|range| range.overlaps(&selection_range))
12212            {
12213                continue;
12214            }
12215
12216            let tab_size = language_settings.tab_size;
12217
12218            let (line_prefix, inside_comment) = match &comment_prefix {
12219                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12220                    (Some(prefix.as_str()), true)
12221                }
12222                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12223                    (Some(prefix.as_ref()), true)
12224                }
12225                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12226                    start: _,
12227                    end: _,
12228                    prefix,
12229                    tab_size,
12230                })) => {
12231                    indent_size.len += tab_size;
12232                    (Some(prefix.as_ref()), true)
12233                }
12234                None => (None, false),
12235            };
12236            let indent_prefix = indent_size.chars().collect::<String>();
12237            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12238
12239            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12240                RewrapBehavior::InComments => inside_comment,
12241                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12242                RewrapBehavior::Anywhere => true,
12243            };
12244
12245            let should_rewrap = options.override_language_settings
12246                || allow_rewrap_based_on_language
12247                || self.hard_wrap.is_some();
12248            if !should_rewrap {
12249                continue;
12250            }
12251
12252            if from_empty_selection {
12253                'expand_upwards: while start_row > 0 {
12254                    let prev_row = start_row - 1;
12255                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12256                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12257                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12258                    {
12259                        start_row = prev_row;
12260                    } else {
12261                        break 'expand_upwards;
12262                    }
12263                }
12264
12265                'expand_downwards: while end_row < buffer.max_point().row {
12266                    let next_row = end_row + 1;
12267                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12268                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12269                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12270                    {
12271                        end_row = next_row;
12272                    } else {
12273                        break 'expand_downwards;
12274                    }
12275                }
12276            }
12277
12278            let start = Point::new(start_row, 0);
12279            let start_offset = ToOffset::to_offset(&start, &buffer);
12280            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12281            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12282            let mut first_line_delimiter = None;
12283            let mut last_line_delimiter = None;
12284            let Some(lines_without_prefixes) = selection_text
12285                .lines()
12286                .enumerate()
12287                .map(|(ix, line)| {
12288                    let line_trimmed = line.trim_start();
12289                    if rewrap_prefix.is_some() && ix > 0 {
12290                        Ok(line_trimmed)
12291                    } else if let Some(
12292                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12293                            start,
12294                            prefix,
12295                            end,
12296                            tab_size,
12297                        })
12298                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12299                            start,
12300                            prefix,
12301                            end,
12302                            tab_size,
12303                        }),
12304                    ) = &comment_prefix
12305                    {
12306                        let line_trimmed = line_trimmed
12307                            .strip_prefix(start.as_ref())
12308                            .map(|s| {
12309                                let mut indent_size = indent_size;
12310                                indent_size.len -= tab_size;
12311                                let indent_prefix: String = indent_size.chars().collect();
12312                                first_line_delimiter = Some((indent_prefix, start));
12313                                s.trim_start()
12314                            })
12315                            .unwrap_or(line_trimmed);
12316                        let line_trimmed = line_trimmed
12317                            .strip_suffix(end.as_ref())
12318                            .map(|s| {
12319                                last_line_delimiter = Some(end);
12320                                s.trim_end()
12321                            })
12322                            .unwrap_or(line_trimmed);
12323                        let line_trimmed = line_trimmed
12324                            .strip_prefix(prefix.as_ref())
12325                            .unwrap_or(line_trimmed);
12326                        Ok(line_trimmed)
12327                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12328                        line_trimmed.strip_prefix(prefix).with_context(|| {
12329                            format!("line did not start with prefix {prefix:?}: {line:?}")
12330                        })
12331                    } else {
12332                        line_trimmed
12333                            .strip_prefix(&line_prefix.trim_start())
12334                            .with_context(|| {
12335                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12336                            })
12337                    }
12338                })
12339                .collect::<Result<Vec<_>, _>>()
12340                .log_err()
12341            else {
12342                continue;
12343            };
12344
12345            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12346                buffer
12347                    .language_settings_at(Point::new(start_row, 0), cx)
12348                    .preferred_line_length as usize
12349            });
12350
12351            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12352                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12353            } else {
12354                line_prefix.clone()
12355            };
12356
12357            let wrapped_text = {
12358                let mut wrapped_text = wrap_with_prefix(
12359                    line_prefix,
12360                    subsequent_lines_prefix,
12361                    lines_without_prefixes.join("\n"),
12362                    wrap_column,
12363                    tab_size,
12364                    options.preserve_existing_whitespace,
12365                );
12366
12367                if let Some((indent, delimiter)) = first_line_delimiter {
12368                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12369                }
12370                if let Some(last_line) = last_line_delimiter {
12371                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12372                }
12373
12374                wrapped_text
12375            };
12376
12377            // TODO: should always use char-based diff while still supporting cursor behavior that
12378            // matches vim.
12379            let mut diff_options = DiffOptions::default();
12380            if options.override_language_settings {
12381                diff_options.max_word_diff_len = 0;
12382                diff_options.max_word_diff_line_count = 0;
12383            } else {
12384                diff_options.max_word_diff_len = usize::MAX;
12385                diff_options.max_word_diff_line_count = usize::MAX;
12386            }
12387
12388            for (old_range, new_text) in
12389                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12390            {
12391                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12392                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12393                edits.push((edit_start..edit_end, new_text));
12394            }
12395
12396            rewrapped_row_ranges.push(start_row..=end_row);
12397        }
12398
12399        self.buffer
12400            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12401    }
12402
12403    pub fn cut_common(
12404        &mut self,
12405        cut_no_selection_line: bool,
12406        window: &mut Window,
12407        cx: &mut Context<Self>,
12408    ) -> ClipboardItem {
12409        let mut text = String::new();
12410        let buffer = self.buffer.read(cx).snapshot(cx);
12411        let mut selections = self.selections.all::<Point>(cx);
12412        let mut clipboard_selections = Vec::with_capacity(selections.len());
12413        {
12414            let max_point = buffer.max_point();
12415            let mut is_first = true;
12416            for selection in &mut selections {
12417                let is_entire_line =
12418                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12419                if is_entire_line {
12420                    selection.start = Point::new(selection.start.row, 0);
12421                    if !selection.is_empty() && selection.end.column == 0 {
12422                        selection.end = cmp::min(max_point, selection.end);
12423                    } else {
12424                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12425                    }
12426                    selection.goal = SelectionGoal::None;
12427                }
12428                if is_first {
12429                    is_first = false;
12430                } else {
12431                    text += "\n";
12432                }
12433                let mut len = 0;
12434                for chunk in buffer.text_for_range(selection.start..selection.end) {
12435                    text.push_str(chunk);
12436                    len += chunk.len();
12437                }
12438                clipboard_selections.push(ClipboardSelection {
12439                    len,
12440                    is_entire_line,
12441                    first_line_indent: buffer
12442                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12443                        .len,
12444                });
12445            }
12446        }
12447
12448        self.transact(window, cx, |this, window, cx| {
12449            this.change_selections(Default::default(), window, cx, |s| {
12450                s.select(selections);
12451            });
12452            this.insert("", window, cx);
12453        });
12454        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12455    }
12456
12457    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12459        let item = self.cut_common(true, window, cx);
12460        cx.write_to_clipboard(item);
12461    }
12462
12463    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12464        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12465        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12466            s.move_with(|snapshot, sel| {
12467                if sel.is_empty() {
12468                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12469                }
12470                if sel.is_empty() {
12471                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12472                }
12473            });
12474        });
12475        let item = self.cut_common(false, window, cx);
12476        cx.set_global(KillRing(item))
12477    }
12478
12479    pub fn kill_ring_yank(
12480        &mut self,
12481        _: &KillRingYank,
12482        window: &mut Window,
12483        cx: &mut Context<Self>,
12484    ) {
12485        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12486        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12487            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12488                (kill_ring.text().to_string(), kill_ring.metadata_json())
12489            } else {
12490                return;
12491            }
12492        } else {
12493            return;
12494        };
12495        self.do_paste(&text, metadata, false, window, cx);
12496    }
12497
12498    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12499        self.do_copy(true, cx);
12500    }
12501
12502    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12503        self.do_copy(false, cx);
12504    }
12505
12506    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12507        let selections = self.selections.all::<Point>(cx);
12508        let buffer = self.buffer.read(cx).read(cx);
12509        let mut text = String::new();
12510
12511        let mut clipboard_selections = Vec::with_capacity(selections.len());
12512        {
12513            let max_point = buffer.max_point();
12514            let mut is_first = true;
12515            for selection in &selections {
12516                let mut start = selection.start;
12517                let mut end = selection.end;
12518                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12519                let mut add_trailing_newline = false;
12520                if is_entire_line {
12521                    start = Point::new(start.row, 0);
12522                    let next_line_start = Point::new(end.row + 1, 0);
12523                    if next_line_start <= max_point {
12524                        end = next_line_start;
12525                    } else {
12526                        // We're on the last line without a trailing newline.
12527                        // Copy to the end of the line and add a newline afterwards.
12528                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12529                        add_trailing_newline = true;
12530                    }
12531                }
12532
12533                let mut trimmed_selections = Vec::new();
12534                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12535                    let row = MultiBufferRow(start.row);
12536                    let first_indent = buffer.indent_size_for_line(row);
12537                    if first_indent.len == 0 || start.column > first_indent.len {
12538                        trimmed_selections.push(start..end);
12539                    } else {
12540                        trimmed_selections.push(
12541                            Point::new(row.0, first_indent.len)
12542                                ..Point::new(row.0, buffer.line_len(row)),
12543                        );
12544                        for row in start.row + 1..=end.row {
12545                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12546                            if row == end.row {
12547                                line_len = end.column;
12548                            }
12549                            if line_len == 0 {
12550                                trimmed_selections
12551                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12552                                continue;
12553                            }
12554                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12555                            if row_indent_size.len >= first_indent.len {
12556                                trimmed_selections.push(
12557                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12558                                );
12559                            } else {
12560                                trimmed_selections.clear();
12561                                trimmed_selections.push(start..end);
12562                                break;
12563                            }
12564                        }
12565                    }
12566                } else {
12567                    trimmed_selections.push(start..end);
12568                }
12569
12570                for trimmed_range in trimmed_selections {
12571                    if is_first {
12572                        is_first = false;
12573                    } else {
12574                        text += "\n";
12575                    }
12576                    let mut len = 0;
12577                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12578                        text.push_str(chunk);
12579                        len += chunk.len();
12580                    }
12581                    if add_trailing_newline {
12582                        text.push('\n');
12583                        len += 1;
12584                    }
12585                    clipboard_selections.push(ClipboardSelection {
12586                        len,
12587                        is_entire_line,
12588                        first_line_indent: buffer
12589                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12590                            .len,
12591                    });
12592                }
12593            }
12594        }
12595
12596        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12597            text,
12598            clipboard_selections,
12599        ));
12600    }
12601
12602    pub fn do_paste(
12603        &mut self,
12604        text: &String,
12605        clipboard_selections: Option<Vec<ClipboardSelection>>,
12606        handle_entire_lines: bool,
12607        window: &mut Window,
12608        cx: &mut Context<Self>,
12609    ) {
12610        if self.read_only(cx) {
12611            return;
12612        }
12613
12614        let clipboard_text = Cow::Borrowed(text.as_str());
12615
12616        self.transact(window, cx, |this, window, cx| {
12617            let had_active_edit_prediction = this.has_active_edit_prediction();
12618            let old_selections = this.selections.all::<usize>(cx);
12619            let cursor_offset = this.selections.last::<usize>(cx).head();
12620
12621            if let Some(mut clipboard_selections) = clipboard_selections {
12622                let all_selections_were_entire_line =
12623                    clipboard_selections.iter().all(|s| s.is_entire_line);
12624                let first_selection_indent_column =
12625                    clipboard_selections.first().map(|s| s.first_line_indent);
12626                if clipboard_selections.len() != old_selections.len() {
12627                    clipboard_selections.drain(..);
12628                }
12629                let mut auto_indent_on_paste = true;
12630
12631                this.buffer.update(cx, |buffer, cx| {
12632                    let snapshot = buffer.read(cx);
12633                    auto_indent_on_paste = snapshot
12634                        .language_settings_at(cursor_offset, cx)
12635                        .auto_indent_on_paste;
12636
12637                    let mut start_offset = 0;
12638                    let mut edits = Vec::new();
12639                    let mut original_indent_columns = Vec::new();
12640                    for (ix, selection) in old_selections.iter().enumerate() {
12641                        let to_insert;
12642                        let entire_line;
12643                        let original_indent_column;
12644                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12645                            let end_offset = start_offset + clipboard_selection.len;
12646                            to_insert = &clipboard_text[start_offset..end_offset];
12647                            entire_line = clipboard_selection.is_entire_line;
12648                            start_offset = end_offset + 1;
12649                            original_indent_column = Some(clipboard_selection.first_line_indent);
12650                        } else {
12651                            to_insert = &*clipboard_text;
12652                            entire_line = all_selections_were_entire_line;
12653                            original_indent_column = first_selection_indent_column
12654                        }
12655
12656                        let (range, to_insert) =
12657                            if selection.is_empty() && handle_entire_lines && entire_line {
12658                                // If the corresponding selection was empty when this slice of the
12659                                // clipboard text was written, then the entire line containing the
12660                                // selection was copied. If this selection is also currently empty,
12661                                // then paste the line before the current line of the buffer.
12662                                let column = selection.start.to_point(&snapshot).column as usize;
12663                                let line_start = selection.start - column;
12664                                (line_start..line_start, Cow::Borrowed(to_insert))
12665                            } else {
12666                                let language = snapshot.language_at(selection.head());
12667                                let range = selection.range();
12668                                if let Some(language) = language
12669                                    && language.name() == "Markdown".into()
12670                                {
12671                                    edit_for_markdown_paste(
12672                                        &snapshot,
12673                                        range,
12674                                        to_insert,
12675                                        url::Url::parse(to_insert).ok(),
12676                                    )
12677                                } else {
12678                                    (range, Cow::Borrowed(to_insert))
12679                                }
12680                            };
12681
12682                        edits.push((range, to_insert));
12683                        original_indent_columns.push(original_indent_column);
12684                    }
12685                    drop(snapshot);
12686
12687                    buffer.edit(
12688                        edits,
12689                        if auto_indent_on_paste {
12690                            Some(AutoindentMode::Block {
12691                                original_indent_columns,
12692                            })
12693                        } else {
12694                            None
12695                        },
12696                        cx,
12697                    );
12698                });
12699
12700                let selections = this.selections.all::<usize>(cx);
12701                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12702            } else {
12703                let url = url::Url::parse(&clipboard_text).ok();
12704
12705                let auto_indent_mode = if !clipboard_text.is_empty() {
12706                    Some(AutoindentMode::Block {
12707                        original_indent_columns: Vec::new(),
12708                    })
12709                } else {
12710                    None
12711                };
12712
12713                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12714                    let snapshot = buffer.snapshot(cx);
12715
12716                    let anchors = old_selections
12717                        .iter()
12718                        .map(|s| {
12719                            let anchor = snapshot.anchor_after(s.head());
12720                            s.map(|_| anchor)
12721                        })
12722                        .collect::<Vec<_>>();
12723
12724                    let mut edits = Vec::new();
12725
12726                    for selection in old_selections.iter() {
12727                        let language = snapshot.language_at(selection.head());
12728                        let range = selection.range();
12729
12730                        let (edit_range, edit_text) = if let Some(language) = language
12731                            && language.name() == "Markdown".into()
12732                        {
12733                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12734                        } else {
12735                            (range, clipboard_text.clone())
12736                        };
12737
12738                        edits.push((edit_range, edit_text));
12739                    }
12740
12741                    drop(snapshot);
12742                    buffer.edit(edits, auto_indent_mode, cx);
12743
12744                    anchors
12745                });
12746
12747                this.change_selections(Default::default(), window, cx, |s| {
12748                    s.select_anchors(selection_anchors);
12749                });
12750            }
12751
12752            let trigger_in_words =
12753                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12754
12755            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12756        });
12757    }
12758
12759    pub fn diff_clipboard_with_selection(
12760        &mut self,
12761        _: &DiffClipboardWithSelection,
12762        window: &mut Window,
12763        cx: &mut Context<Self>,
12764    ) {
12765        let selections = self.selections.all::<usize>(cx);
12766
12767        if selections.is_empty() {
12768            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12769            return;
12770        };
12771
12772        let clipboard_text = match cx.read_from_clipboard() {
12773            Some(item) => match item.entries().first() {
12774                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12775                _ => None,
12776            },
12777            None => None,
12778        };
12779
12780        let Some(clipboard_text) = clipboard_text else {
12781            log::warn!("Clipboard doesn't contain text.");
12782            return;
12783        };
12784
12785        window.dispatch_action(
12786            Box::new(DiffClipboardWithSelectionData {
12787                clipboard_text,
12788                editor: cx.entity(),
12789            }),
12790            cx,
12791        );
12792    }
12793
12794    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12795        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12796        if let Some(item) = cx.read_from_clipboard() {
12797            let entries = item.entries();
12798
12799            match entries.first() {
12800                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12801                // of all the pasted entries.
12802                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12803                    .do_paste(
12804                        clipboard_string.text(),
12805                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12806                        true,
12807                        window,
12808                        cx,
12809                    ),
12810                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12811            }
12812        }
12813    }
12814
12815    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12816        if self.read_only(cx) {
12817            return;
12818        }
12819
12820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12821
12822        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12823            if let Some((selections, _)) =
12824                self.selection_history.transaction(transaction_id).cloned()
12825            {
12826                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12827                    s.select_anchors(selections.to_vec());
12828                });
12829            } else {
12830                log::error!(
12831                    "No entry in selection_history found for undo. \
12832                     This may correspond to a bug where undo does not update the selection. \
12833                     If this is occurring, please add details to \
12834                     https://github.com/zed-industries/zed/issues/22692"
12835                );
12836            }
12837            self.request_autoscroll(Autoscroll::fit(), cx);
12838            self.unmark_text(window, cx);
12839            self.refresh_edit_prediction(true, false, window, cx);
12840            cx.emit(EditorEvent::Edited { transaction_id });
12841            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12842        }
12843    }
12844
12845    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12846        if self.read_only(cx) {
12847            return;
12848        }
12849
12850        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12851
12852        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12853            if let Some((_, Some(selections))) =
12854                self.selection_history.transaction(transaction_id).cloned()
12855            {
12856                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12857                    s.select_anchors(selections.to_vec());
12858                });
12859            } else {
12860                log::error!(
12861                    "No entry in selection_history found for redo. \
12862                     This may correspond to a bug where undo does not update the selection. \
12863                     If this is occurring, please add details to \
12864                     https://github.com/zed-industries/zed/issues/22692"
12865                );
12866            }
12867            self.request_autoscroll(Autoscroll::fit(), cx);
12868            self.unmark_text(window, cx);
12869            self.refresh_edit_prediction(true, false, window, cx);
12870            cx.emit(EditorEvent::Edited { transaction_id });
12871        }
12872    }
12873
12874    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12875        self.buffer
12876            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12877    }
12878
12879    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12880        self.buffer
12881            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12882    }
12883
12884    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12886        self.change_selections(Default::default(), window, cx, |s| {
12887            s.move_with(|map, selection| {
12888                let cursor = if selection.is_empty() {
12889                    movement::left(map, selection.start)
12890                } else {
12891                    selection.start
12892                };
12893                selection.collapse_to(cursor, SelectionGoal::None);
12894            });
12895        })
12896    }
12897
12898    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12899        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12900        self.change_selections(Default::default(), window, cx, |s| {
12901            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12902        })
12903    }
12904
12905    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12906        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12907        self.change_selections(Default::default(), window, cx, |s| {
12908            s.move_with(|map, selection| {
12909                let cursor = if selection.is_empty() {
12910                    movement::right(map, selection.end)
12911                } else {
12912                    selection.end
12913                };
12914                selection.collapse_to(cursor, SelectionGoal::None)
12915            });
12916        })
12917    }
12918
12919    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12920        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12921        self.change_selections(Default::default(), window, cx, |s| {
12922            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12923        });
12924    }
12925
12926    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12927        if self.take_rename(true, window, cx).is_some() {
12928            return;
12929        }
12930
12931        if self.mode.is_single_line() {
12932            cx.propagate();
12933            return;
12934        }
12935
12936        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12937
12938        let text_layout_details = &self.text_layout_details(window);
12939        let selection_count = self.selections.count();
12940        let first_selection = self.selections.first_anchor();
12941
12942        self.change_selections(Default::default(), window, cx, |s| {
12943            s.move_with(|map, selection| {
12944                if !selection.is_empty() {
12945                    selection.goal = SelectionGoal::None;
12946                }
12947                let (cursor, goal) = movement::up(
12948                    map,
12949                    selection.start,
12950                    selection.goal,
12951                    false,
12952                    text_layout_details,
12953                );
12954                selection.collapse_to(cursor, goal);
12955            });
12956        });
12957
12958        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12959        {
12960            cx.propagate();
12961        }
12962    }
12963
12964    pub fn move_up_by_lines(
12965        &mut self,
12966        action: &MoveUpByLines,
12967        window: &mut Window,
12968        cx: &mut Context<Self>,
12969    ) {
12970        if self.take_rename(true, window, cx).is_some() {
12971            return;
12972        }
12973
12974        if self.mode.is_single_line() {
12975            cx.propagate();
12976            return;
12977        }
12978
12979        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12980
12981        let text_layout_details = &self.text_layout_details(window);
12982
12983        self.change_selections(Default::default(), window, cx, |s| {
12984            s.move_with(|map, selection| {
12985                if !selection.is_empty() {
12986                    selection.goal = SelectionGoal::None;
12987                }
12988                let (cursor, goal) = movement::up_by_rows(
12989                    map,
12990                    selection.start,
12991                    action.lines,
12992                    selection.goal,
12993                    false,
12994                    text_layout_details,
12995                );
12996                selection.collapse_to(cursor, goal);
12997            });
12998        })
12999    }
13000
13001    pub fn move_down_by_lines(
13002        &mut self,
13003        action: &MoveDownByLines,
13004        window: &mut Window,
13005        cx: &mut Context<Self>,
13006    ) {
13007        if self.take_rename(true, window, cx).is_some() {
13008            return;
13009        }
13010
13011        if self.mode.is_single_line() {
13012            cx.propagate();
13013            return;
13014        }
13015
13016        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13017
13018        let text_layout_details = &self.text_layout_details(window);
13019
13020        self.change_selections(Default::default(), window, cx, |s| {
13021            s.move_with(|map, selection| {
13022                if !selection.is_empty() {
13023                    selection.goal = SelectionGoal::None;
13024                }
13025                let (cursor, goal) = movement::down_by_rows(
13026                    map,
13027                    selection.start,
13028                    action.lines,
13029                    selection.goal,
13030                    false,
13031                    text_layout_details,
13032                );
13033                selection.collapse_to(cursor, goal);
13034            });
13035        })
13036    }
13037
13038    pub fn select_down_by_lines(
13039        &mut self,
13040        action: &SelectDownByLines,
13041        window: &mut Window,
13042        cx: &mut Context<Self>,
13043    ) {
13044        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13045        let text_layout_details = &self.text_layout_details(window);
13046        self.change_selections(Default::default(), window, cx, |s| {
13047            s.move_heads_with(|map, head, goal| {
13048                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13049            })
13050        })
13051    }
13052
13053    pub fn select_up_by_lines(
13054        &mut self,
13055        action: &SelectUpByLines,
13056        window: &mut Window,
13057        cx: &mut Context<Self>,
13058    ) {
13059        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13060        let text_layout_details = &self.text_layout_details(window);
13061        self.change_selections(Default::default(), window, cx, |s| {
13062            s.move_heads_with(|map, head, goal| {
13063                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13064            })
13065        })
13066    }
13067
13068    pub fn select_page_up(
13069        &mut self,
13070        _: &SelectPageUp,
13071        window: &mut Window,
13072        cx: &mut Context<Self>,
13073    ) {
13074        let Some(row_count) = self.visible_row_count() else {
13075            return;
13076        };
13077
13078        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13079
13080        let text_layout_details = &self.text_layout_details(window);
13081
13082        self.change_selections(Default::default(), window, cx, |s| {
13083            s.move_heads_with(|map, head, goal| {
13084                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13085            })
13086        })
13087    }
13088
13089    pub fn move_page_up(
13090        &mut self,
13091        action: &MovePageUp,
13092        window: &mut Window,
13093        cx: &mut Context<Self>,
13094    ) {
13095        if self.take_rename(true, window, cx).is_some() {
13096            return;
13097        }
13098
13099        if self
13100            .context_menu
13101            .borrow_mut()
13102            .as_mut()
13103            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13104            .unwrap_or(false)
13105        {
13106            return;
13107        }
13108
13109        if matches!(self.mode, EditorMode::SingleLine) {
13110            cx.propagate();
13111            return;
13112        }
13113
13114        let Some(row_count) = self.visible_row_count() else {
13115            return;
13116        };
13117
13118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13119
13120        let effects = if action.center_cursor {
13121            SelectionEffects::scroll(Autoscroll::center())
13122        } else {
13123            SelectionEffects::default()
13124        };
13125
13126        let text_layout_details = &self.text_layout_details(window);
13127
13128        self.change_selections(effects, window, cx, |s| {
13129            s.move_with(|map, selection| {
13130                if !selection.is_empty() {
13131                    selection.goal = SelectionGoal::None;
13132                }
13133                let (cursor, goal) = movement::up_by_rows(
13134                    map,
13135                    selection.end,
13136                    row_count,
13137                    selection.goal,
13138                    false,
13139                    text_layout_details,
13140                );
13141                selection.collapse_to(cursor, goal);
13142            });
13143        });
13144    }
13145
13146    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13148        let text_layout_details = &self.text_layout_details(window);
13149        self.change_selections(Default::default(), window, cx, |s| {
13150            s.move_heads_with(|map, head, goal| {
13151                movement::up(map, head, goal, false, text_layout_details)
13152            })
13153        })
13154    }
13155
13156    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13157        self.take_rename(true, window, cx);
13158
13159        if self.mode.is_single_line() {
13160            cx.propagate();
13161            return;
13162        }
13163
13164        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13165
13166        let text_layout_details = &self.text_layout_details(window);
13167        let selection_count = self.selections.count();
13168        let first_selection = self.selections.first_anchor();
13169
13170        self.change_selections(Default::default(), window, cx, |s| {
13171            s.move_with(|map, selection| {
13172                if !selection.is_empty() {
13173                    selection.goal = SelectionGoal::None;
13174                }
13175                let (cursor, goal) = movement::down(
13176                    map,
13177                    selection.end,
13178                    selection.goal,
13179                    false,
13180                    text_layout_details,
13181                );
13182                selection.collapse_to(cursor, goal);
13183            });
13184        });
13185
13186        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13187        {
13188            cx.propagate();
13189        }
13190    }
13191
13192    pub fn select_page_down(
13193        &mut self,
13194        _: &SelectPageDown,
13195        window: &mut Window,
13196        cx: &mut Context<Self>,
13197    ) {
13198        let Some(row_count) = self.visible_row_count() else {
13199            return;
13200        };
13201
13202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13203
13204        let text_layout_details = &self.text_layout_details(window);
13205
13206        self.change_selections(Default::default(), window, cx, |s| {
13207            s.move_heads_with(|map, head, goal| {
13208                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13209            })
13210        })
13211    }
13212
13213    pub fn move_page_down(
13214        &mut self,
13215        action: &MovePageDown,
13216        window: &mut Window,
13217        cx: &mut Context<Self>,
13218    ) {
13219        if self.take_rename(true, window, cx).is_some() {
13220            return;
13221        }
13222
13223        if self
13224            .context_menu
13225            .borrow_mut()
13226            .as_mut()
13227            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13228            .unwrap_or(false)
13229        {
13230            return;
13231        }
13232
13233        if matches!(self.mode, EditorMode::SingleLine) {
13234            cx.propagate();
13235            return;
13236        }
13237
13238        let Some(row_count) = self.visible_row_count() else {
13239            return;
13240        };
13241
13242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13243
13244        let effects = if action.center_cursor {
13245            SelectionEffects::scroll(Autoscroll::center())
13246        } else {
13247            SelectionEffects::default()
13248        };
13249
13250        let text_layout_details = &self.text_layout_details(window);
13251        self.change_selections(effects, window, cx, |s| {
13252            s.move_with(|map, selection| {
13253                if !selection.is_empty() {
13254                    selection.goal = SelectionGoal::None;
13255                }
13256                let (cursor, goal) = movement::down_by_rows(
13257                    map,
13258                    selection.end,
13259                    row_count,
13260                    selection.goal,
13261                    false,
13262                    text_layout_details,
13263                );
13264                selection.collapse_to(cursor, goal);
13265            });
13266        });
13267    }
13268
13269    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13270        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13271        let text_layout_details = &self.text_layout_details(window);
13272        self.change_selections(Default::default(), window, cx, |s| {
13273            s.move_heads_with(|map, head, goal| {
13274                movement::down(map, head, goal, false, text_layout_details)
13275            })
13276        });
13277    }
13278
13279    pub fn context_menu_first(
13280        &mut self,
13281        _: &ContextMenuFirst,
13282        window: &mut Window,
13283        cx: &mut Context<Self>,
13284    ) {
13285        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13286            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13287        }
13288    }
13289
13290    pub fn context_menu_prev(
13291        &mut self,
13292        _: &ContextMenuPrevious,
13293        window: &mut Window,
13294        cx: &mut Context<Self>,
13295    ) {
13296        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13297            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13298        }
13299    }
13300
13301    pub fn context_menu_next(
13302        &mut self,
13303        _: &ContextMenuNext,
13304        window: &mut Window,
13305        cx: &mut Context<Self>,
13306    ) {
13307        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13308            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13309        }
13310    }
13311
13312    pub fn context_menu_last(
13313        &mut self,
13314        _: &ContextMenuLast,
13315        window: &mut Window,
13316        cx: &mut Context<Self>,
13317    ) {
13318        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13319            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13320        }
13321    }
13322
13323    pub fn signature_help_prev(
13324        &mut self,
13325        _: &SignatureHelpPrevious,
13326        _: &mut Window,
13327        cx: &mut Context<Self>,
13328    ) {
13329        if let Some(popover) = self.signature_help_state.popover_mut() {
13330            if popover.current_signature == 0 {
13331                popover.current_signature = popover.signatures.len() - 1;
13332            } else {
13333                popover.current_signature -= 1;
13334            }
13335            cx.notify();
13336        }
13337    }
13338
13339    pub fn signature_help_next(
13340        &mut self,
13341        _: &SignatureHelpNext,
13342        _: &mut Window,
13343        cx: &mut Context<Self>,
13344    ) {
13345        if let Some(popover) = self.signature_help_state.popover_mut() {
13346            if popover.current_signature + 1 == popover.signatures.len() {
13347                popover.current_signature = 0;
13348            } else {
13349                popover.current_signature += 1;
13350            }
13351            cx.notify();
13352        }
13353    }
13354
13355    pub fn move_to_previous_word_start(
13356        &mut self,
13357        _: &MoveToPreviousWordStart,
13358        window: &mut Window,
13359        cx: &mut Context<Self>,
13360    ) {
13361        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13362        self.change_selections(Default::default(), window, cx, |s| {
13363            s.move_cursors_with(|map, head, _| {
13364                (
13365                    movement::previous_word_start(map, head),
13366                    SelectionGoal::None,
13367                )
13368            });
13369        })
13370    }
13371
13372    pub fn move_to_previous_subword_start(
13373        &mut self,
13374        _: &MoveToPreviousSubwordStart,
13375        window: &mut Window,
13376        cx: &mut Context<Self>,
13377    ) {
13378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13379        self.change_selections(Default::default(), window, cx, |s| {
13380            s.move_cursors_with(|map, head, _| {
13381                (
13382                    movement::previous_subword_start(map, head),
13383                    SelectionGoal::None,
13384                )
13385            });
13386        })
13387    }
13388
13389    pub fn select_to_previous_word_start(
13390        &mut self,
13391        _: &SelectToPreviousWordStart,
13392        window: &mut Window,
13393        cx: &mut Context<Self>,
13394    ) {
13395        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13396        self.change_selections(Default::default(), window, cx, |s| {
13397            s.move_heads_with(|map, head, _| {
13398                (
13399                    movement::previous_word_start(map, head),
13400                    SelectionGoal::None,
13401                )
13402            });
13403        })
13404    }
13405
13406    pub fn select_to_previous_subword_start(
13407        &mut self,
13408        _: &SelectToPreviousSubwordStart,
13409        window: &mut Window,
13410        cx: &mut Context<Self>,
13411    ) {
13412        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13413        self.change_selections(Default::default(), window, cx, |s| {
13414            s.move_heads_with(|map, head, _| {
13415                (
13416                    movement::previous_subword_start(map, head),
13417                    SelectionGoal::None,
13418                )
13419            });
13420        })
13421    }
13422
13423    pub fn delete_to_previous_word_start(
13424        &mut self,
13425        action: &DeleteToPreviousWordStart,
13426        window: &mut Window,
13427        cx: &mut Context<Self>,
13428    ) {
13429        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13430        self.transact(window, cx, |this, window, cx| {
13431            this.select_autoclose_pair(window, cx);
13432            this.change_selections(Default::default(), window, cx, |s| {
13433                s.move_with(|map, selection| {
13434                    if selection.is_empty() {
13435                        let mut cursor = if action.ignore_newlines {
13436                            movement::previous_word_start(map, selection.head())
13437                        } else {
13438                            movement::previous_word_start_or_newline(map, selection.head())
13439                        };
13440                        cursor = movement::adjust_greedy_deletion(
13441                            map,
13442                            selection.head(),
13443                            cursor,
13444                            action.ignore_brackets,
13445                        );
13446                        selection.set_head(cursor, SelectionGoal::None);
13447                    }
13448                });
13449            });
13450            this.insert("", window, cx);
13451        });
13452    }
13453
13454    pub fn delete_to_previous_subword_start(
13455        &mut self,
13456        _: &DeleteToPreviousSubwordStart,
13457        window: &mut Window,
13458        cx: &mut Context<Self>,
13459    ) {
13460        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13461        self.transact(window, cx, |this, window, cx| {
13462            this.select_autoclose_pair(window, cx);
13463            this.change_selections(Default::default(), window, cx, |s| {
13464                s.move_with(|map, selection| {
13465                    if selection.is_empty() {
13466                        let mut cursor = movement::previous_subword_start(map, selection.head());
13467                        cursor =
13468                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13469                        selection.set_head(cursor, SelectionGoal::None);
13470                    }
13471                });
13472            });
13473            this.insert("", window, cx);
13474        });
13475    }
13476
13477    pub fn move_to_next_word_end(
13478        &mut self,
13479        _: &MoveToNextWordEnd,
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_cursors_with(|map, head, _| {
13486                (movement::next_word_end(map, head), SelectionGoal::None)
13487            });
13488        })
13489    }
13490
13491    pub fn move_to_next_subword_end(
13492        &mut self,
13493        _: &MoveToNextSubwordEnd,
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_cursors_with(|map, head, _| {
13500                (movement::next_subword_end(map, head), SelectionGoal::None)
13501            });
13502        })
13503    }
13504
13505    pub fn select_to_next_word_end(
13506        &mut self,
13507        _: &SelectToNextWordEnd,
13508        window: &mut Window,
13509        cx: &mut Context<Self>,
13510    ) {
13511        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13512        self.change_selections(Default::default(), window, cx, |s| {
13513            s.move_heads_with(|map, head, _| {
13514                (movement::next_word_end(map, head), SelectionGoal::None)
13515            });
13516        })
13517    }
13518
13519    pub fn select_to_next_subword_end(
13520        &mut self,
13521        _: &SelectToNextSubwordEnd,
13522        window: &mut Window,
13523        cx: &mut Context<Self>,
13524    ) {
13525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13526        self.change_selections(Default::default(), window, cx, |s| {
13527            s.move_heads_with(|map, head, _| {
13528                (movement::next_subword_end(map, head), SelectionGoal::None)
13529            });
13530        })
13531    }
13532
13533    pub fn delete_to_next_word_end(
13534        &mut self,
13535        action: &DeleteToNextWordEnd,
13536        window: &mut Window,
13537        cx: &mut Context<Self>,
13538    ) {
13539        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13540        self.transact(window, cx, |this, window, cx| {
13541            this.change_selections(Default::default(), window, cx, |s| {
13542                s.move_with(|map, selection| {
13543                    if selection.is_empty() {
13544                        let mut cursor = if action.ignore_newlines {
13545                            movement::next_word_end(map, selection.head())
13546                        } else {
13547                            movement::next_word_end_or_newline(map, selection.head())
13548                        };
13549                        cursor = movement::adjust_greedy_deletion(
13550                            map,
13551                            selection.head(),
13552                            cursor,
13553                            action.ignore_brackets,
13554                        );
13555                        selection.set_head(cursor, SelectionGoal::None);
13556                    }
13557                });
13558            });
13559            this.insert("", window, cx);
13560        });
13561    }
13562
13563    pub fn delete_to_next_subword_end(
13564        &mut self,
13565        _: &DeleteToNextSubwordEnd,
13566        window: &mut Window,
13567        cx: &mut Context<Self>,
13568    ) {
13569        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13570        self.transact(window, cx, |this, window, cx| {
13571            this.change_selections(Default::default(), window, cx, |s| {
13572                s.move_with(|map, selection| {
13573                    if selection.is_empty() {
13574                        let mut cursor = movement::next_subword_end(map, selection.head());
13575                        cursor =
13576                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13577                        selection.set_head(cursor, SelectionGoal::None);
13578                    }
13579                });
13580            });
13581            this.insert("", window, cx);
13582        });
13583    }
13584
13585    pub fn move_to_beginning_of_line(
13586        &mut self,
13587        action: &MoveToBeginningOfLine,
13588        window: &mut Window,
13589        cx: &mut Context<Self>,
13590    ) {
13591        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13592        self.change_selections(Default::default(), window, cx, |s| {
13593            s.move_cursors_with(|map, head, _| {
13594                (
13595                    movement::indented_line_beginning(
13596                        map,
13597                        head,
13598                        action.stop_at_soft_wraps,
13599                        action.stop_at_indent,
13600                    ),
13601                    SelectionGoal::None,
13602                )
13603            });
13604        })
13605    }
13606
13607    pub fn select_to_beginning_of_line(
13608        &mut self,
13609        action: &SelectToBeginningOfLine,
13610        window: &mut Window,
13611        cx: &mut Context<Self>,
13612    ) {
13613        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13614        self.change_selections(Default::default(), window, cx, |s| {
13615            s.move_heads_with(|map, head, _| {
13616                (
13617                    movement::indented_line_beginning(
13618                        map,
13619                        head,
13620                        action.stop_at_soft_wraps,
13621                        action.stop_at_indent,
13622                    ),
13623                    SelectionGoal::None,
13624                )
13625            });
13626        });
13627    }
13628
13629    pub fn delete_to_beginning_of_line(
13630        &mut self,
13631        action: &DeleteToBeginningOfLine,
13632        window: &mut Window,
13633        cx: &mut Context<Self>,
13634    ) {
13635        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13636        self.transact(window, cx, |this, window, cx| {
13637            this.change_selections(Default::default(), window, cx, |s| {
13638                s.move_with(|_, selection| {
13639                    selection.reversed = true;
13640                });
13641            });
13642
13643            this.select_to_beginning_of_line(
13644                &SelectToBeginningOfLine {
13645                    stop_at_soft_wraps: false,
13646                    stop_at_indent: action.stop_at_indent,
13647                },
13648                window,
13649                cx,
13650            );
13651            this.backspace(&Backspace, window, cx);
13652        });
13653    }
13654
13655    pub fn move_to_end_of_line(
13656        &mut self,
13657        action: &MoveToEndOfLine,
13658        window: &mut Window,
13659        cx: &mut Context<Self>,
13660    ) {
13661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13662        self.change_selections(Default::default(), window, cx, |s| {
13663            s.move_cursors_with(|map, head, _| {
13664                (
13665                    movement::line_end(map, head, action.stop_at_soft_wraps),
13666                    SelectionGoal::None,
13667                )
13668            });
13669        })
13670    }
13671
13672    pub fn select_to_end_of_line(
13673        &mut self,
13674        action: &SelectToEndOfLine,
13675        window: &mut Window,
13676        cx: &mut Context<Self>,
13677    ) {
13678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13679        self.change_selections(Default::default(), window, cx, |s| {
13680            s.move_heads_with(|map, head, _| {
13681                (
13682                    movement::line_end(map, head, action.stop_at_soft_wraps),
13683                    SelectionGoal::None,
13684                )
13685            });
13686        })
13687    }
13688
13689    pub fn delete_to_end_of_line(
13690        &mut self,
13691        _: &DeleteToEndOfLine,
13692        window: &mut Window,
13693        cx: &mut Context<Self>,
13694    ) {
13695        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13696        self.transact(window, cx, |this, window, cx| {
13697            this.select_to_end_of_line(
13698                &SelectToEndOfLine {
13699                    stop_at_soft_wraps: false,
13700                },
13701                window,
13702                cx,
13703            );
13704            this.delete(&Delete, window, cx);
13705        });
13706    }
13707
13708    pub fn cut_to_end_of_line(
13709        &mut self,
13710        action: &CutToEndOfLine,
13711        window: &mut Window,
13712        cx: &mut Context<Self>,
13713    ) {
13714        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13715        self.transact(window, cx, |this, window, cx| {
13716            this.select_to_end_of_line(
13717                &SelectToEndOfLine {
13718                    stop_at_soft_wraps: false,
13719                },
13720                window,
13721                cx,
13722            );
13723            if !action.stop_at_newlines {
13724                this.change_selections(Default::default(), window, cx, |s| {
13725                    s.move_with(|_, sel| {
13726                        if sel.is_empty() {
13727                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13728                        }
13729                    });
13730                });
13731            }
13732            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13733            let item = this.cut_common(false, window, cx);
13734            cx.write_to_clipboard(item);
13735        });
13736    }
13737
13738    pub fn move_to_start_of_paragraph(
13739        &mut self,
13740        _: &MoveToStartOfParagraph,
13741        window: &mut Window,
13742        cx: &mut Context<Self>,
13743    ) {
13744        if matches!(self.mode, EditorMode::SingleLine) {
13745            cx.propagate();
13746            return;
13747        }
13748        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13749        self.change_selections(Default::default(), window, cx, |s| {
13750            s.move_with(|map, selection| {
13751                selection.collapse_to(
13752                    movement::start_of_paragraph(map, selection.head(), 1),
13753                    SelectionGoal::None,
13754                )
13755            });
13756        })
13757    }
13758
13759    pub fn move_to_end_of_paragraph(
13760        &mut self,
13761        _: &MoveToEndOfParagraph,
13762        window: &mut Window,
13763        cx: &mut Context<Self>,
13764    ) {
13765        if matches!(self.mode, EditorMode::SingleLine) {
13766            cx.propagate();
13767            return;
13768        }
13769        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13770        self.change_selections(Default::default(), window, cx, |s| {
13771            s.move_with(|map, selection| {
13772                selection.collapse_to(
13773                    movement::end_of_paragraph(map, selection.head(), 1),
13774                    SelectionGoal::None,
13775                )
13776            });
13777        })
13778    }
13779
13780    pub fn select_to_start_of_paragraph(
13781        &mut self,
13782        _: &SelectToStartOfParagraph,
13783        window: &mut Window,
13784        cx: &mut Context<Self>,
13785    ) {
13786        if matches!(self.mode, EditorMode::SingleLine) {
13787            cx.propagate();
13788            return;
13789        }
13790        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13791        self.change_selections(Default::default(), window, cx, |s| {
13792            s.move_heads_with(|map, head, _| {
13793                (
13794                    movement::start_of_paragraph(map, head, 1),
13795                    SelectionGoal::None,
13796                )
13797            });
13798        })
13799    }
13800
13801    pub fn select_to_end_of_paragraph(
13802        &mut self,
13803        _: &SelectToEndOfParagraph,
13804        window: &mut Window,
13805        cx: &mut Context<Self>,
13806    ) {
13807        if matches!(self.mode, EditorMode::SingleLine) {
13808            cx.propagate();
13809            return;
13810        }
13811        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13812        self.change_selections(Default::default(), window, cx, |s| {
13813            s.move_heads_with(|map, head, _| {
13814                (
13815                    movement::end_of_paragraph(map, head, 1),
13816                    SelectionGoal::None,
13817                )
13818            });
13819        })
13820    }
13821
13822    pub fn move_to_start_of_excerpt(
13823        &mut self,
13824        _: &MoveToStartOfExcerpt,
13825        window: &mut Window,
13826        cx: &mut Context<Self>,
13827    ) {
13828        if matches!(self.mode, EditorMode::SingleLine) {
13829            cx.propagate();
13830            return;
13831        }
13832        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13833        self.change_selections(Default::default(), window, cx, |s| {
13834            s.move_with(|map, selection| {
13835                selection.collapse_to(
13836                    movement::start_of_excerpt(
13837                        map,
13838                        selection.head(),
13839                        workspace::searchable::Direction::Prev,
13840                    ),
13841                    SelectionGoal::None,
13842                )
13843            });
13844        })
13845    }
13846
13847    pub fn move_to_start_of_next_excerpt(
13848        &mut self,
13849        _: &MoveToStartOfNextExcerpt,
13850        window: &mut Window,
13851        cx: &mut Context<Self>,
13852    ) {
13853        if matches!(self.mode, EditorMode::SingleLine) {
13854            cx.propagate();
13855            return;
13856        }
13857
13858        self.change_selections(Default::default(), window, cx, |s| {
13859            s.move_with(|map, selection| {
13860                selection.collapse_to(
13861                    movement::start_of_excerpt(
13862                        map,
13863                        selection.head(),
13864                        workspace::searchable::Direction::Next,
13865                    ),
13866                    SelectionGoal::None,
13867                )
13868            });
13869        })
13870    }
13871
13872    pub fn move_to_end_of_excerpt(
13873        &mut self,
13874        _: &MoveToEndOfExcerpt,
13875        window: &mut Window,
13876        cx: &mut Context<Self>,
13877    ) {
13878        if matches!(self.mode, EditorMode::SingleLine) {
13879            cx.propagate();
13880            return;
13881        }
13882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13883        self.change_selections(Default::default(), window, cx, |s| {
13884            s.move_with(|map, selection| {
13885                selection.collapse_to(
13886                    movement::end_of_excerpt(
13887                        map,
13888                        selection.head(),
13889                        workspace::searchable::Direction::Next,
13890                    ),
13891                    SelectionGoal::None,
13892                )
13893            });
13894        })
13895    }
13896
13897    pub fn move_to_end_of_previous_excerpt(
13898        &mut self,
13899        _: &MoveToEndOfPreviousExcerpt,
13900        window: &mut Window,
13901        cx: &mut Context<Self>,
13902    ) {
13903        if matches!(self.mode, EditorMode::SingleLine) {
13904            cx.propagate();
13905            return;
13906        }
13907        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13908        self.change_selections(Default::default(), window, cx, |s| {
13909            s.move_with(|map, selection| {
13910                selection.collapse_to(
13911                    movement::end_of_excerpt(
13912                        map,
13913                        selection.head(),
13914                        workspace::searchable::Direction::Prev,
13915                    ),
13916                    SelectionGoal::None,
13917                )
13918            });
13919        })
13920    }
13921
13922    pub fn select_to_start_of_excerpt(
13923        &mut self,
13924        _: &SelectToStartOfExcerpt,
13925        window: &mut Window,
13926        cx: &mut Context<Self>,
13927    ) {
13928        if matches!(self.mode, EditorMode::SingleLine) {
13929            cx.propagate();
13930            return;
13931        }
13932        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13933        self.change_selections(Default::default(), window, cx, |s| {
13934            s.move_heads_with(|map, head, _| {
13935                (
13936                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13937                    SelectionGoal::None,
13938                )
13939            });
13940        })
13941    }
13942
13943    pub fn select_to_start_of_next_excerpt(
13944        &mut self,
13945        _: &SelectToStartOfNextExcerpt,
13946        window: &mut Window,
13947        cx: &mut Context<Self>,
13948    ) {
13949        if matches!(self.mode, EditorMode::SingleLine) {
13950            cx.propagate();
13951            return;
13952        }
13953        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13954        self.change_selections(Default::default(), window, cx, |s| {
13955            s.move_heads_with(|map, head, _| {
13956                (
13957                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13958                    SelectionGoal::None,
13959                )
13960            });
13961        })
13962    }
13963
13964    pub fn select_to_end_of_excerpt(
13965        &mut self,
13966        _: &SelectToEndOfExcerpt,
13967        window: &mut Window,
13968        cx: &mut Context<Self>,
13969    ) {
13970        if matches!(self.mode, EditorMode::SingleLine) {
13971            cx.propagate();
13972            return;
13973        }
13974        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13975        self.change_selections(Default::default(), window, cx, |s| {
13976            s.move_heads_with(|map, head, _| {
13977                (
13978                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13979                    SelectionGoal::None,
13980                )
13981            });
13982        })
13983    }
13984
13985    pub fn select_to_end_of_previous_excerpt(
13986        &mut self,
13987        _: &SelectToEndOfPreviousExcerpt,
13988        window: &mut Window,
13989        cx: &mut Context<Self>,
13990    ) {
13991        if matches!(self.mode, EditorMode::SingleLine) {
13992            cx.propagate();
13993            return;
13994        }
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13996        self.change_selections(Default::default(), window, cx, |s| {
13997            s.move_heads_with(|map, head, _| {
13998                (
13999                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14000                    SelectionGoal::None,
14001                )
14002            });
14003        })
14004    }
14005
14006    pub fn move_to_beginning(
14007        &mut self,
14008        _: &MoveToBeginning,
14009        window: &mut Window,
14010        cx: &mut Context<Self>,
14011    ) {
14012        if matches!(self.mode, EditorMode::SingleLine) {
14013            cx.propagate();
14014            return;
14015        }
14016        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14017        self.change_selections(Default::default(), window, cx, |s| {
14018            s.select_ranges(vec![0..0]);
14019        });
14020    }
14021
14022    pub fn select_to_beginning(
14023        &mut self,
14024        _: &SelectToBeginning,
14025        window: &mut Window,
14026        cx: &mut Context<Self>,
14027    ) {
14028        let mut selection = self.selections.last::<Point>(cx);
14029        selection.set_head(Point::zero(), SelectionGoal::None);
14030        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14031        self.change_selections(Default::default(), window, cx, |s| {
14032            s.select(vec![selection]);
14033        });
14034    }
14035
14036    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14037        if matches!(self.mode, EditorMode::SingleLine) {
14038            cx.propagate();
14039            return;
14040        }
14041        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14042        let cursor = self.buffer.read(cx).read(cx).len();
14043        self.change_selections(Default::default(), window, cx, |s| {
14044            s.select_ranges(vec![cursor..cursor])
14045        });
14046    }
14047
14048    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14049        self.nav_history = nav_history;
14050    }
14051
14052    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14053        self.nav_history.as_ref()
14054    }
14055
14056    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14057        self.push_to_nav_history(
14058            self.selections.newest_anchor().head(),
14059            None,
14060            false,
14061            true,
14062            cx,
14063        );
14064    }
14065
14066    fn push_to_nav_history(
14067        &mut self,
14068        cursor_anchor: Anchor,
14069        new_position: Option<Point>,
14070        is_deactivate: bool,
14071        always: bool,
14072        cx: &mut Context<Self>,
14073    ) {
14074        if let Some(nav_history) = self.nav_history.as_mut() {
14075            let buffer = self.buffer.read(cx).read(cx);
14076            let cursor_position = cursor_anchor.to_point(&buffer);
14077            let scroll_state = self.scroll_manager.anchor();
14078            let scroll_top_row = scroll_state.top_row(&buffer);
14079            drop(buffer);
14080
14081            if let Some(new_position) = new_position {
14082                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14083                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14084                    return;
14085                }
14086            }
14087
14088            nav_history.push(
14089                Some(NavigationData {
14090                    cursor_anchor,
14091                    cursor_position,
14092                    scroll_anchor: scroll_state,
14093                    scroll_top_row,
14094                }),
14095                cx,
14096            );
14097            cx.emit(EditorEvent::PushedToNavHistory {
14098                anchor: cursor_anchor,
14099                is_deactivate,
14100            })
14101        }
14102    }
14103
14104    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14105        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14106        let buffer = self.buffer.read(cx).snapshot(cx);
14107        let mut selection = self.selections.first::<usize>(cx);
14108        selection.set_head(buffer.len(), SelectionGoal::None);
14109        self.change_selections(Default::default(), window, cx, |s| {
14110            s.select(vec![selection]);
14111        });
14112    }
14113
14114    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14115        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14116        let end = self.buffer.read(cx).read(cx).len();
14117        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14118            s.select_ranges(vec![0..end]);
14119        });
14120    }
14121
14122    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14123        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14124        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14125        let mut selections = self.selections.all::<Point>(cx);
14126        let max_point = display_map.buffer_snapshot().max_point();
14127        for selection in &mut selections {
14128            let rows = selection.spanned_rows(true, &display_map);
14129            selection.start = Point::new(rows.start.0, 0);
14130            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14131            selection.reversed = false;
14132        }
14133        self.change_selections(Default::default(), window, cx, |s| {
14134            s.select(selections);
14135        });
14136    }
14137
14138    pub fn split_selection_into_lines(
14139        &mut self,
14140        action: &SplitSelectionIntoLines,
14141        window: &mut Window,
14142        cx: &mut Context<Self>,
14143    ) {
14144        let selections = self
14145            .selections
14146            .all::<Point>(cx)
14147            .into_iter()
14148            .map(|selection| selection.start..selection.end)
14149            .collect::<Vec<_>>();
14150        self.unfold_ranges(&selections, true, true, cx);
14151
14152        let mut new_selection_ranges = Vec::new();
14153        {
14154            let buffer = self.buffer.read(cx).read(cx);
14155            for selection in selections {
14156                for row in selection.start.row..selection.end.row {
14157                    let line_start = Point::new(row, 0);
14158                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14159
14160                    if action.keep_selections {
14161                        // Keep the selection range for each line
14162                        let selection_start = if row == selection.start.row {
14163                            selection.start
14164                        } else {
14165                            line_start
14166                        };
14167                        new_selection_ranges.push(selection_start..line_end);
14168                    } else {
14169                        // Collapse to cursor at end of line
14170                        new_selection_ranges.push(line_end..line_end);
14171                    }
14172                }
14173
14174                let is_multiline_selection = selection.start.row != selection.end.row;
14175                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14176                // so this action feels more ergonomic when paired with other selection operations
14177                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14178                if !should_skip_last {
14179                    if action.keep_selections {
14180                        if is_multiline_selection {
14181                            let line_start = Point::new(selection.end.row, 0);
14182                            new_selection_ranges.push(line_start..selection.end);
14183                        } else {
14184                            new_selection_ranges.push(selection.start..selection.end);
14185                        }
14186                    } else {
14187                        new_selection_ranges.push(selection.end..selection.end);
14188                    }
14189                }
14190            }
14191        }
14192        self.change_selections(Default::default(), window, cx, |s| {
14193            s.select_ranges(new_selection_ranges);
14194        });
14195    }
14196
14197    pub fn add_selection_above(
14198        &mut self,
14199        _: &AddSelectionAbove,
14200        window: &mut Window,
14201        cx: &mut Context<Self>,
14202    ) {
14203        self.add_selection(true, window, cx);
14204    }
14205
14206    pub fn add_selection_below(
14207        &mut self,
14208        _: &AddSelectionBelow,
14209        window: &mut Window,
14210        cx: &mut Context<Self>,
14211    ) {
14212        self.add_selection(false, window, cx);
14213    }
14214
14215    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14216        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14217
14218        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14219        let all_selections = self.selections.all::<Point>(cx);
14220        let text_layout_details = self.text_layout_details(window);
14221
14222        let (mut columnar_selections, new_selections_to_columnarize) = {
14223            if let Some(state) = self.add_selections_state.as_ref() {
14224                let columnar_selection_ids: HashSet<_> = state
14225                    .groups
14226                    .iter()
14227                    .flat_map(|group| group.stack.iter())
14228                    .copied()
14229                    .collect();
14230
14231                all_selections
14232                    .into_iter()
14233                    .partition(|s| columnar_selection_ids.contains(&s.id))
14234            } else {
14235                (Vec::new(), all_selections)
14236            }
14237        };
14238
14239        let mut state = self
14240            .add_selections_state
14241            .take()
14242            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14243
14244        for selection in new_selections_to_columnarize {
14245            let range = selection.display_range(&display_map).sorted();
14246            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14247            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14248            let positions = start_x.min(end_x)..start_x.max(end_x);
14249            let mut stack = Vec::new();
14250            for row in range.start.row().0..=range.end.row().0 {
14251                if let Some(selection) = self.selections.build_columnar_selection(
14252                    &display_map,
14253                    DisplayRow(row),
14254                    &positions,
14255                    selection.reversed,
14256                    &text_layout_details,
14257                ) {
14258                    stack.push(selection.id);
14259                    columnar_selections.push(selection);
14260                }
14261            }
14262            if !stack.is_empty() {
14263                if above {
14264                    stack.reverse();
14265                }
14266                state.groups.push(AddSelectionsGroup { above, stack });
14267            }
14268        }
14269
14270        let mut final_selections = Vec::new();
14271        let end_row = if above {
14272            DisplayRow(0)
14273        } else {
14274            display_map.max_point().row()
14275        };
14276
14277        let mut last_added_item_per_group = HashMap::default();
14278        for group in state.groups.iter_mut() {
14279            if let Some(last_id) = group.stack.last() {
14280                last_added_item_per_group.insert(*last_id, group);
14281            }
14282        }
14283
14284        for selection in columnar_selections {
14285            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14286                if above == group.above {
14287                    let range = selection.display_range(&display_map).sorted();
14288                    debug_assert_eq!(range.start.row(), range.end.row());
14289                    let mut row = range.start.row();
14290                    let positions =
14291                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14292                            Pixels::from(start)..Pixels::from(end)
14293                        } else {
14294                            let start_x =
14295                                display_map.x_for_display_point(range.start, &text_layout_details);
14296                            let end_x =
14297                                display_map.x_for_display_point(range.end, &text_layout_details);
14298                            start_x.min(end_x)..start_x.max(end_x)
14299                        };
14300
14301                    let mut maybe_new_selection = None;
14302                    while row != end_row {
14303                        if above {
14304                            row.0 -= 1;
14305                        } else {
14306                            row.0 += 1;
14307                        }
14308                        if let Some(new_selection) = self.selections.build_columnar_selection(
14309                            &display_map,
14310                            row,
14311                            &positions,
14312                            selection.reversed,
14313                            &text_layout_details,
14314                        ) {
14315                            maybe_new_selection = Some(new_selection);
14316                            break;
14317                        }
14318                    }
14319
14320                    if let Some(new_selection) = maybe_new_selection {
14321                        group.stack.push(new_selection.id);
14322                        if above {
14323                            final_selections.push(new_selection);
14324                            final_selections.push(selection);
14325                        } else {
14326                            final_selections.push(selection);
14327                            final_selections.push(new_selection);
14328                        }
14329                    } else {
14330                        final_selections.push(selection);
14331                    }
14332                } else {
14333                    group.stack.pop();
14334                }
14335            } else {
14336                final_selections.push(selection);
14337            }
14338        }
14339
14340        self.change_selections(Default::default(), window, cx, |s| {
14341            s.select(final_selections);
14342        });
14343
14344        let final_selection_ids: HashSet<_> = self
14345            .selections
14346            .all::<Point>(cx)
14347            .iter()
14348            .map(|s| s.id)
14349            .collect();
14350        state.groups.retain_mut(|group| {
14351            // selections might get merged above so we remove invalid items from stacks
14352            group.stack.retain(|id| final_selection_ids.contains(id));
14353
14354            // single selection in stack can be treated as initial state
14355            group.stack.len() > 1
14356        });
14357
14358        if !state.groups.is_empty() {
14359            self.add_selections_state = Some(state);
14360        }
14361    }
14362
14363    fn select_match_ranges(
14364        &mut self,
14365        range: Range<usize>,
14366        reversed: bool,
14367        replace_newest: bool,
14368        auto_scroll: Option<Autoscroll>,
14369        window: &mut Window,
14370        cx: &mut Context<Editor>,
14371    ) {
14372        self.unfold_ranges(
14373            std::slice::from_ref(&range),
14374            false,
14375            auto_scroll.is_some(),
14376            cx,
14377        );
14378        let effects = if let Some(scroll) = auto_scroll {
14379            SelectionEffects::scroll(scroll)
14380        } else {
14381            SelectionEffects::no_scroll()
14382        };
14383        self.change_selections(effects, window, cx, |s| {
14384            if replace_newest {
14385                s.delete(s.newest_anchor().id);
14386            }
14387            if reversed {
14388                s.insert_range(range.end..range.start);
14389            } else {
14390                s.insert_range(range);
14391            }
14392        });
14393    }
14394
14395    pub fn select_next_match_internal(
14396        &mut self,
14397        display_map: &DisplaySnapshot,
14398        replace_newest: bool,
14399        autoscroll: Option<Autoscroll>,
14400        window: &mut Window,
14401        cx: &mut Context<Self>,
14402    ) -> Result<()> {
14403        let buffer = display_map.buffer_snapshot();
14404        let mut selections = self.selections.all::<usize>(cx);
14405        if let Some(mut select_next_state) = self.select_next_state.take() {
14406            let query = &select_next_state.query;
14407            if !select_next_state.done {
14408                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14409                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14410                let mut next_selected_range = None;
14411
14412                let bytes_after_last_selection =
14413                    buffer.bytes_in_range(last_selection.end..buffer.len());
14414                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14415                let query_matches = query
14416                    .stream_find_iter(bytes_after_last_selection)
14417                    .map(|result| (last_selection.end, result))
14418                    .chain(
14419                        query
14420                            .stream_find_iter(bytes_before_first_selection)
14421                            .map(|result| (0, result)),
14422                    );
14423
14424                for (start_offset, query_match) in query_matches {
14425                    let query_match = query_match.unwrap(); // can only fail due to I/O
14426                    let offset_range =
14427                        start_offset + query_match.start()..start_offset + query_match.end();
14428
14429                    if !select_next_state.wordwise
14430                        || (!buffer.is_inside_word(offset_range.start, None)
14431                            && !buffer.is_inside_word(offset_range.end, None))
14432                    {
14433                        // TODO: This is n^2, because we might check all the selections
14434                        if !selections
14435                            .iter()
14436                            .any(|selection| selection.range().overlaps(&offset_range))
14437                        {
14438                            next_selected_range = Some(offset_range);
14439                            break;
14440                        }
14441                    }
14442                }
14443
14444                if let Some(next_selected_range) = next_selected_range {
14445                    self.select_match_ranges(
14446                        next_selected_range,
14447                        last_selection.reversed,
14448                        replace_newest,
14449                        autoscroll,
14450                        window,
14451                        cx,
14452                    );
14453                } else {
14454                    select_next_state.done = true;
14455                }
14456            }
14457
14458            self.select_next_state = Some(select_next_state);
14459        } else {
14460            let mut only_carets = true;
14461            let mut same_text_selected = true;
14462            let mut selected_text = None;
14463
14464            let mut selections_iter = selections.iter().peekable();
14465            while let Some(selection) = selections_iter.next() {
14466                if selection.start != selection.end {
14467                    only_carets = false;
14468                }
14469
14470                if same_text_selected {
14471                    if selected_text.is_none() {
14472                        selected_text =
14473                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14474                    }
14475
14476                    if let Some(next_selection) = selections_iter.peek() {
14477                        if next_selection.range().len() == selection.range().len() {
14478                            let next_selected_text = buffer
14479                                .text_for_range(next_selection.range())
14480                                .collect::<String>();
14481                            if Some(next_selected_text) != selected_text {
14482                                same_text_selected = false;
14483                                selected_text = None;
14484                            }
14485                        } else {
14486                            same_text_selected = false;
14487                            selected_text = None;
14488                        }
14489                    }
14490                }
14491            }
14492
14493            if only_carets {
14494                for selection in &mut selections {
14495                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14496                    selection.start = word_range.start;
14497                    selection.end = word_range.end;
14498                    selection.goal = SelectionGoal::None;
14499                    selection.reversed = false;
14500                    self.select_match_ranges(
14501                        selection.start..selection.end,
14502                        selection.reversed,
14503                        replace_newest,
14504                        autoscroll,
14505                        window,
14506                        cx,
14507                    );
14508                }
14509
14510                if selections.len() == 1 {
14511                    let selection = selections
14512                        .last()
14513                        .expect("ensured that there's only one selection");
14514                    let query = buffer
14515                        .text_for_range(selection.start..selection.end)
14516                        .collect::<String>();
14517                    let is_empty = query.is_empty();
14518                    let select_state = SelectNextState {
14519                        query: AhoCorasick::new(&[query])?,
14520                        wordwise: true,
14521                        done: is_empty,
14522                    };
14523                    self.select_next_state = Some(select_state);
14524                } else {
14525                    self.select_next_state = None;
14526                }
14527            } else if let Some(selected_text) = selected_text {
14528                self.select_next_state = Some(SelectNextState {
14529                    query: AhoCorasick::new(&[selected_text])?,
14530                    wordwise: false,
14531                    done: false,
14532                });
14533                self.select_next_match_internal(
14534                    display_map,
14535                    replace_newest,
14536                    autoscroll,
14537                    window,
14538                    cx,
14539                )?;
14540            }
14541        }
14542        Ok(())
14543    }
14544
14545    pub fn select_all_matches(
14546        &mut self,
14547        _action: &SelectAllMatches,
14548        window: &mut Window,
14549        cx: &mut Context<Self>,
14550    ) -> Result<()> {
14551        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14552
14553        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14554
14555        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14556        let Some(select_next_state) = self.select_next_state.as_mut() else {
14557            return Ok(());
14558        };
14559        if select_next_state.done {
14560            return Ok(());
14561        }
14562
14563        let mut new_selections = Vec::new();
14564
14565        let reversed = self.selections.oldest::<usize>(cx).reversed;
14566        let buffer = display_map.buffer_snapshot();
14567        let query_matches = select_next_state
14568            .query
14569            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14570
14571        for query_match in query_matches.into_iter() {
14572            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14573            let offset_range = if reversed {
14574                query_match.end()..query_match.start()
14575            } else {
14576                query_match.start()..query_match.end()
14577            };
14578
14579            if !select_next_state.wordwise
14580                || (!buffer.is_inside_word(offset_range.start, None)
14581                    && !buffer.is_inside_word(offset_range.end, None))
14582            {
14583                new_selections.push(offset_range.start..offset_range.end);
14584            }
14585        }
14586
14587        select_next_state.done = true;
14588
14589        if new_selections.is_empty() {
14590            log::error!("bug: new_selections is empty in select_all_matches");
14591            return Ok(());
14592        }
14593
14594        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14595        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14596            selections.select_ranges(new_selections)
14597        });
14598
14599        Ok(())
14600    }
14601
14602    pub fn select_next(
14603        &mut self,
14604        action: &SelectNext,
14605        window: &mut Window,
14606        cx: &mut Context<Self>,
14607    ) -> Result<()> {
14608        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14609        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14610        self.select_next_match_internal(
14611            &display_map,
14612            action.replace_newest,
14613            Some(Autoscroll::newest()),
14614            window,
14615            cx,
14616        )?;
14617        Ok(())
14618    }
14619
14620    pub fn select_previous(
14621        &mut self,
14622        action: &SelectPrevious,
14623        window: &mut Window,
14624        cx: &mut Context<Self>,
14625    ) -> Result<()> {
14626        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14627        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14628        let buffer = display_map.buffer_snapshot();
14629        let mut selections = self.selections.all::<usize>(cx);
14630        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14631            let query = &select_prev_state.query;
14632            if !select_prev_state.done {
14633                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14634                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14635                let mut next_selected_range = None;
14636                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14637                let bytes_before_last_selection =
14638                    buffer.reversed_bytes_in_range(0..last_selection.start);
14639                let bytes_after_first_selection =
14640                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14641                let query_matches = query
14642                    .stream_find_iter(bytes_before_last_selection)
14643                    .map(|result| (last_selection.start, result))
14644                    .chain(
14645                        query
14646                            .stream_find_iter(bytes_after_first_selection)
14647                            .map(|result| (buffer.len(), result)),
14648                    );
14649                for (end_offset, query_match) in query_matches {
14650                    let query_match = query_match.unwrap(); // can only fail due to I/O
14651                    let offset_range =
14652                        end_offset - query_match.end()..end_offset - query_match.start();
14653
14654                    if !select_prev_state.wordwise
14655                        || (!buffer.is_inside_word(offset_range.start, None)
14656                            && !buffer.is_inside_word(offset_range.end, None))
14657                    {
14658                        next_selected_range = Some(offset_range);
14659                        break;
14660                    }
14661                }
14662
14663                if let Some(next_selected_range) = next_selected_range {
14664                    self.select_match_ranges(
14665                        next_selected_range,
14666                        last_selection.reversed,
14667                        action.replace_newest,
14668                        Some(Autoscroll::newest()),
14669                        window,
14670                        cx,
14671                    );
14672                } else {
14673                    select_prev_state.done = true;
14674                }
14675            }
14676
14677            self.select_prev_state = Some(select_prev_state);
14678        } else {
14679            let mut only_carets = true;
14680            let mut same_text_selected = true;
14681            let mut selected_text = None;
14682
14683            let mut selections_iter = selections.iter().peekable();
14684            while let Some(selection) = selections_iter.next() {
14685                if selection.start != selection.end {
14686                    only_carets = false;
14687                }
14688
14689                if same_text_selected {
14690                    if selected_text.is_none() {
14691                        selected_text =
14692                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14693                    }
14694
14695                    if let Some(next_selection) = selections_iter.peek() {
14696                        if next_selection.range().len() == selection.range().len() {
14697                            let next_selected_text = buffer
14698                                .text_for_range(next_selection.range())
14699                                .collect::<String>();
14700                            if Some(next_selected_text) != selected_text {
14701                                same_text_selected = false;
14702                                selected_text = None;
14703                            }
14704                        } else {
14705                            same_text_selected = false;
14706                            selected_text = None;
14707                        }
14708                    }
14709                }
14710            }
14711
14712            if only_carets {
14713                for selection in &mut selections {
14714                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14715                    selection.start = word_range.start;
14716                    selection.end = word_range.end;
14717                    selection.goal = SelectionGoal::None;
14718                    selection.reversed = false;
14719                    self.select_match_ranges(
14720                        selection.start..selection.end,
14721                        selection.reversed,
14722                        action.replace_newest,
14723                        Some(Autoscroll::newest()),
14724                        window,
14725                        cx,
14726                    );
14727                }
14728                if selections.len() == 1 {
14729                    let selection = selections
14730                        .last()
14731                        .expect("ensured that there's only one selection");
14732                    let query = buffer
14733                        .text_for_range(selection.start..selection.end)
14734                        .collect::<String>();
14735                    let is_empty = query.is_empty();
14736                    let select_state = SelectNextState {
14737                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14738                        wordwise: true,
14739                        done: is_empty,
14740                    };
14741                    self.select_prev_state = Some(select_state);
14742                } else {
14743                    self.select_prev_state = None;
14744                }
14745            } else if let Some(selected_text) = selected_text {
14746                self.select_prev_state = Some(SelectNextState {
14747                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14748                    wordwise: false,
14749                    done: false,
14750                });
14751                self.select_previous(action, window, cx)?;
14752            }
14753        }
14754        Ok(())
14755    }
14756
14757    pub fn find_next_match(
14758        &mut self,
14759        _: &FindNextMatch,
14760        window: &mut Window,
14761        cx: &mut Context<Self>,
14762    ) -> Result<()> {
14763        let selections = self.selections.disjoint_anchors_arc();
14764        match selections.first() {
14765            Some(first) if selections.len() >= 2 => {
14766                self.change_selections(Default::default(), window, cx, |s| {
14767                    s.select_ranges([first.range()]);
14768                });
14769            }
14770            _ => self.select_next(
14771                &SelectNext {
14772                    replace_newest: true,
14773                },
14774                window,
14775                cx,
14776            )?,
14777        }
14778        Ok(())
14779    }
14780
14781    pub fn find_previous_match(
14782        &mut self,
14783        _: &FindPreviousMatch,
14784        window: &mut Window,
14785        cx: &mut Context<Self>,
14786    ) -> Result<()> {
14787        let selections = self.selections.disjoint_anchors_arc();
14788        match selections.last() {
14789            Some(last) if selections.len() >= 2 => {
14790                self.change_selections(Default::default(), window, cx, |s| {
14791                    s.select_ranges([last.range()]);
14792                });
14793            }
14794            _ => self.select_previous(
14795                &SelectPrevious {
14796                    replace_newest: true,
14797                },
14798                window,
14799                cx,
14800            )?,
14801        }
14802        Ok(())
14803    }
14804
14805    pub fn toggle_comments(
14806        &mut self,
14807        action: &ToggleComments,
14808        window: &mut Window,
14809        cx: &mut Context<Self>,
14810    ) {
14811        if self.read_only(cx) {
14812            return;
14813        }
14814        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14815        let text_layout_details = &self.text_layout_details(window);
14816        self.transact(window, cx, |this, window, cx| {
14817            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14818            let mut edits = Vec::new();
14819            let mut selection_edit_ranges = Vec::new();
14820            let mut last_toggled_row = None;
14821            let snapshot = this.buffer.read(cx).read(cx);
14822            let empty_str: Arc<str> = Arc::default();
14823            let mut suffixes_inserted = Vec::new();
14824            let ignore_indent = action.ignore_indent;
14825
14826            fn comment_prefix_range(
14827                snapshot: &MultiBufferSnapshot,
14828                row: MultiBufferRow,
14829                comment_prefix: &str,
14830                comment_prefix_whitespace: &str,
14831                ignore_indent: bool,
14832            ) -> Range<Point> {
14833                let indent_size = if ignore_indent {
14834                    0
14835                } else {
14836                    snapshot.indent_size_for_line(row).len
14837                };
14838
14839                let start = Point::new(row.0, indent_size);
14840
14841                let mut line_bytes = snapshot
14842                    .bytes_in_range(start..snapshot.max_point())
14843                    .flatten()
14844                    .copied();
14845
14846                // If this line currently begins with the line comment prefix, then record
14847                // the range containing the prefix.
14848                if line_bytes
14849                    .by_ref()
14850                    .take(comment_prefix.len())
14851                    .eq(comment_prefix.bytes())
14852                {
14853                    // Include any whitespace that matches the comment prefix.
14854                    let matching_whitespace_len = line_bytes
14855                        .zip(comment_prefix_whitespace.bytes())
14856                        .take_while(|(a, b)| a == b)
14857                        .count() as u32;
14858                    let end = Point::new(
14859                        start.row,
14860                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14861                    );
14862                    start..end
14863                } else {
14864                    start..start
14865                }
14866            }
14867
14868            fn comment_suffix_range(
14869                snapshot: &MultiBufferSnapshot,
14870                row: MultiBufferRow,
14871                comment_suffix: &str,
14872                comment_suffix_has_leading_space: bool,
14873            ) -> Range<Point> {
14874                let end = Point::new(row.0, snapshot.line_len(row));
14875                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14876
14877                let mut line_end_bytes = snapshot
14878                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14879                    .flatten()
14880                    .copied();
14881
14882                let leading_space_len = if suffix_start_column > 0
14883                    && line_end_bytes.next() == Some(b' ')
14884                    && comment_suffix_has_leading_space
14885                {
14886                    1
14887                } else {
14888                    0
14889                };
14890
14891                // If this line currently begins with the line comment prefix, then record
14892                // the range containing the prefix.
14893                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14894                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14895                    start..end
14896                } else {
14897                    end..end
14898                }
14899            }
14900
14901            // TODO: Handle selections that cross excerpts
14902            for selection in &mut selections {
14903                let start_column = snapshot
14904                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14905                    .len;
14906                let language = if let Some(language) =
14907                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14908                {
14909                    language
14910                } else {
14911                    continue;
14912                };
14913
14914                selection_edit_ranges.clear();
14915
14916                // If multiple selections contain a given row, avoid processing that
14917                // row more than once.
14918                let mut start_row = MultiBufferRow(selection.start.row);
14919                if last_toggled_row == Some(start_row) {
14920                    start_row = start_row.next_row();
14921                }
14922                let end_row =
14923                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14924                        MultiBufferRow(selection.end.row - 1)
14925                    } else {
14926                        MultiBufferRow(selection.end.row)
14927                    };
14928                last_toggled_row = Some(end_row);
14929
14930                if start_row > end_row {
14931                    continue;
14932                }
14933
14934                // If the language has line comments, toggle those.
14935                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14936
14937                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14938                if ignore_indent {
14939                    full_comment_prefixes = full_comment_prefixes
14940                        .into_iter()
14941                        .map(|s| Arc::from(s.trim_end()))
14942                        .collect();
14943                }
14944
14945                if !full_comment_prefixes.is_empty() {
14946                    let first_prefix = full_comment_prefixes
14947                        .first()
14948                        .expect("prefixes is non-empty");
14949                    let prefix_trimmed_lengths = full_comment_prefixes
14950                        .iter()
14951                        .map(|p| p.trim_end_matches(' ').len())
14952                        .collect::<SmallVec<[usize; 4]>>();
14953
14954                    let mut all_selection_lines_are_comments = true;
14955
14956                    for row in start_row.0..=end_row.0 {
14957                        let row = MultiBufferRow(row);
14958                        if start_row < end_row && snapshot.is_line_blank(row) {
14959                            continue;
14960                        }
14961
14962                        let prefix_range = full_comment_prefixes
14963                            .iter()
14964                            .zip(prefix_trimmed_lengths.iter().copied())
14965                            .map(|(prefix, trimmed_prefix_len)| {
14966                                comment_prefix_range(
14967                                    snapshot.deref(),
14968                                    row,
14969                                    &prefix[..trimmed_prefix_len],
14970                                    &prefix[trimmed_prefix_len..],
14971                                    ignore_indent,
14972                                )
14973                            })
14974                            .max_by_key(|range| range.end.column - range.start.column)
14975                            .expect("prefixes is non-empty");
14976
14977                        if prefix_range.is_empty() {
14978                            all_selection_lines_are_comments = false;
14979                        }
14980
14981                        selection_edit_ranges.push(prefix_range);
14982                    }
14983
14984                    if all_selection_lines_are_comments {
14985                        edits.extend(
14986                            selection_edit_ranges
14987                                .iter()
14988                                .cloned()
14989                                .map(|range| (range, empty_str.clone())),
14990                        );
14991                    } else {
14992                        let min_column = selection_edit_ranges
14993                            .iter()
14994                            .map(|range| range.start.column)
14995                            .min()
14996                            .unwrap_or(0);
14997                        edits.extend(selection_edit_ranges.iter().map(|range| {
14998                            let position = Point::new(range.start.row, min_column);
14999                            (position..position, first_prefix.clone())
15000                        }));
15001                    }
15002                } else if let Some(BlockCommentConfig {
15003                    start: full_comment_prefix,
15004                    end: comment_suffix,
15005                    ..
15006                }) = language.block_comment()
15007                {
15008                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15009                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15010                    let prefix_range = comment_prefix_range(
15011                        snapshot.deref(),
15012                        start_row,
15013                        comment_prefix,
15014                        comment_prefix_whitespace,
15015                        ignore_indent,
15016                    );
15017                    let suffix_range = comment_suffix_range(
15018                        snapshot.deref(),
15019                        end_row,
15020                        comment_suffix.trim_start_matches(' '),
15021                        comment_suffix.starts_with(' '),
15022                    );
15023
15024                    if prefix_range.is_empty() || suffix_range.is_empty() {
15025                        edits.push((
15026                            prefix_range.start..prefix_range.start,
15027                            full_comment_prefix.clone(),
15028                        ));
15029                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15030                        suffixes_inserted.push((end_row, comment_suffix.len()));
15031                    } else {
15032                        edits.push((prefix_range, empty_str.clone()));
15033                        edits.push((suffix_range, empty_str.clone()));
15034                    }
15035                } else {
15036                    continue;
15037                }
15038            }
15039
15040            drop(snapshot);
15041            this.buffer.update(cx, |buffer, cx| {
15042                buffer.edit(edits, None, cx);
15043            });
15044
15045            // Adjust selections so that they end before any comment suffixes that
15046            // were inserted.
15047            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15048            let mut selections = this.selections.all::<Point>(cx);
15049            let snapshot = this.buffer.read(cx).read(cx);
15050            for selection in &mut selections {
15051                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15052                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15053                        Ordering::Less => {
15054                            suffixes_inserted.next();
15055                            continue;
15056                        }
15057                        Ordering::Greater => break,
15058                        Ordering::Equal => {
15059                            if selection.end.column == snapshot.line_len(row) {
15060                                if selection.is_empty() {
15061                                    selection.start.column -= suffix_len as u32;
15062                                }
15063                                selection.end.column -= suffix_len as u32;
15064                            }
15065                            break;
15066                        }
15067                    }
15068                }
15069            }
15070
15071            drop(snapshot);
15072            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15073
15074            let selections = this.selections.all::<Point>(cx);
15075            let selections_on_single_row = selections.windows(2).all(|selections| {
15076                selections[0].start.row == selections[1].start.row
15077                    && selections[0].end.row == selections[1].end.row
15078                    && selections[0].start.row == selections[0].end.row
15079            });
15080            let selections_selecting = selections
15081                .iter()
15082                .any(|selection| selection.start != selection.end);
15083            let advance_downwards = action.advance_downwards
15084                && selections_on_single_row
15085                && !selections_selecting
15086                && !matches!(this.mode, EditorMode::SingleLine);
15087
15088            if advance_downwards {
15089                let snapshot = this.buffer.read(cx).snapshot(cx);
15090
15091                this.change_selections(Default::default(), window, cx, |s| {
15092                    s.move_cursors_with(|display_snapshot, display_point, _| {
15093                        let mut point = display_point.to_point(display_snapshot);
15094                        point.row += 1;
15095                        point = snapshot.clip_point(point, Bias::Left);
15096                        let display_point = point.to_display_point(display_snapshot);
15097                        let goal = SelectionGoal::HorizontalPosition(
15098                            display_snapshot
15099                                .x_for_display_point(display_point, text_layout_details)
15100                                .into(),
15101                        );
15102                        (display_point, goal)
15103                    })
15104                });
15105            }
15106        });
15107    }
15108
15109    pub fn select_enclosing_symbol(
15110        &mut self,
15111        _: &SelectEnclosingSymbol,
15112        window: &mut Window,
15113        cx: &mut Context<Self>,
15114    ) {
15115        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15116
15117        let buffer = self.buffer.read(cx).snapshot(cx);
15118        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15119
15120        fn update_selection(
15121            selection: &Selection<usize>,
15122            buffer_snap: &MultiBufferSnapshot,
15123        ) -> Option<Selection<usize>> {
15124            let cursor = selection.head();
15125            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15126            for symbol in symbols.iter().rev() {
15127                let start = symbol.range.start.to_offset(buffer_snap);
15128                let end = symbol.range.end.to_offset(buffer_snap);
15129                let new_range = start..end;
15130                if start < selection.start || end > selection.end {
15131                    return Some(Selection {
15132                        id: selection.id,
15133                        start: new_range.start,
15134                        end: new_range.end,
15135                        goal: SelectionGoal::None,
15136                        reversed: selection.reversed,
15137                    });
15138                }
15139            }
15140            None
15141        }
15142
15143        let mut selected_larger_symbol = false;
15144        let new_selections = old_selections
15145            .iter()
15146            .map(|selection| match update_selection(selection, &buffer) {
15147                Some(new_selection) => {
15148                    if new_selection.range() != selection.range() {
15149                        selected_larger_symbol = true;
15150                    }
15151                    new_selection
15152                }
15153                None => selection.clone(),
15154            })
15155            .collect::<Vec<_>>();
15156
15157        if selected_larger_symbol {
15158            self.change_selections(Default::default(), window, cx, |s| {
15159                s.select(new_selections);
15160            });
15161        }
15162    }
15163
15164    pub fn select_larger_syntax_node(
15165        &mut self,
15166        _: &SelectLargerSyntaxNode,
15167        window: &mut Window,
15168        cx: &mut Context<Self>,
15169    ) {
15170        let Some(visible_row_count) = self.visible_row_count() else {
15171            return;
15172        };
15173        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15174        if old_selections.is_empty() {
15175            return;
15176        }
15177
15178        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15179
15180        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15181        let buffer = self.buffer.read(cx).snapshot(cx);
15182
15183        let mut selected_larger_node = false;
15184        let mut new_selections = old_selections
15185            .iter()
15186            .map(|selection| {
15187                let old_range = selection.start..selection.end;
15188
15189                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15190                    // manually select word at selection
15191                    if ["string_content", "inline"].contains(&node.kind()) {
15192                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15193                        // ignore if word is already selected
15194                        if !word_range.is_empty() && old_range != word_range {
15195                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15196                            // only select word if start and end point belongs to same word
15197                            if word_range == last_word_range {
15198                                selected_larger_node = true;
15199                                return Selection {
15200                                    id: selection.id,
15201                                    start: word_range.start,
15202                                    end: word_range.end,
15203                                    goal: SelectionGoal::None,
15204                                    reversed: selection.reversed,
15205                                };
15206                            }
15207                        }
15208                    }
15209                }
15210
15211                let mut new_range = old_range.clone();
15212                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15213                    new_range = range;
15214                    if !node.is_named() {
15215                        continue;
15216                    }
15217                    if !display_map.intersects_fold(new_range.start)
15218                        && !display_map.intersects_fold(new_range.end)
15219                    {
15220                        break;
15221                    }
15222                }
15223
15224                selected_larger_node |= new_range != old_range;
15225                Selection {
15226                    id: selection.id,
15227                    start: new_range.start,
15228                    end: new_range.end,
15229                    goal: SelectionGoal::None,
15230                    reversed: selection.reversed,
15231                }
15232            })
15233            .collect::<Vec<_>>();
15234
15235        if !selected_larger_node {
15236            return; // don't put this call in the history
15237        }
15238
15239        // scroll based on transformation done to the last selection created by the user
15240        let (last_old, last_new) = old_selections
15241            .last()
15242            .zip(new_selections.last().cloned())
15243            .expect("old_selections isn't empty");
15244
15245        // revert selection
15246        let is_selection_reversed = {
15247            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15248            new_selections.last_mut().expect("checked above").reversed =
15249                should_newest_selection_be_reversed;
15250            should_newest_selection_be_reversed
15251        };
15252
15253        if selected_larger_node {
15254            self.select_syntax_node_history.disable_clearing = true;
15255            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15256                s.select(new_selections.clone());
15257            });
15258            self.select_syntax_node_history.disable_clearing = false;
15259        }
15260
15261        let start_row = last_new.start.to_display_point(&display_map).row().0;
15262        let end_row = last_new.end.to_display_point(&display_map).row().0;
15263        let selection_height = end_row - start_row + 1;
15264        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15265
15266        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15267        let scroll_behavior = if fits_on_the_screen {
15268            self.request_autoscroll(Autoscroll::fit(), cx);
15269            SelectSyntaxNodeScrollBehavior::FitSelection
15270        } else if is_selection_reversed {
15271            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15272            SelectSyntaxNodeScrollBehavior::CursorTop
15273        } else {
15274            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15275            SelectSyntaxNodeScrollBehavior::CursorBottom
15276        };
15277
15278        self.select_syntax_node_history.push((
15279            old_selections,
15280            scroll_behavior,
15281            is_selection_reversed,
15282        ));
15283    }
15284
15285    pub fn select_smaller_syntax_node(
15286        &mut self,
15287        _: &SelectSmallerSyntaxNode,
15288        window: &mut Window,
15289        cx: &mut Context<Self>,
15290    ) {
15291        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15292
15293        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15294            self.select_syntax_node_history.pop()
15295        {
15296            if let Some(selection) = selections.last_mut() {
15297                selection.reversed = is_selection_reversed;
15298            }
15299
15300            self.select_syntax_node_history.disable_clearing = true;
15301            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15302                s.select(selections.to_vec());
15303            });
15304            self.select_syntax_node_history.disable_clearing = false;
15305
15306            match scroll_behavior {
15307                SelectSyntaxNodeScrollBehavior::CursorTop => {
15308                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15309                }
15310                SelectSyntaxNodeScrollBehavior::FitSelection => {
15311                    self.request_autoscroll(Autoscroll::fit(), cx);
15312                }
15313                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15314                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15315                }
15316            }
15317        }
15318    }
15319
15320    pub fn unwrap_syntax_node(
15321        &mut self,
15322        _: &UnwrapSyntaxNode,
15323        window: &mut Window,
15324        cx: &mut Context<Self>,
15325    ) {
15326        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15327
15328        let buffer = self.buffer.read(cx).snapshot(cx);
15329        let selections = self
15330            .selections
15331            .all::<usize>(cx)
15332            .into_iter()
15333            // subtracting the offset requires sorting
15334            .sorted_by_key(|i| i.start);
15335
15336        let full_edits = selections
15337            .into_iter()
15338            .filter_map(|selection| {
15339                let child = if selection.is_empty()
15340                    && let Some((_, ancestor_range)) =
15341                        buffer.syntax_ancestor(selection.start..selection.end)
15342                {
15343                    ancestor_range
15344                } else {
15345                    selection.range()
15346                };
15347
15348                let mut parent = child.clone();
15349                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15350                    parent = ancestor_range;
15351                    if parent.start < child.start || parent.end > child.end {
15352                        break;
15353                    }
15354                }
15355
15356                if parent == child {
15357                    return None;
15358                }
15359                let text = buffer.text_for_range(child).collect::<String>();
15360                Some((selection.id, parent, text))
15361            })
15362            .collect::<Vec<_>>();
15363        if full_edits.is_empty() {
15364            return;
15365        }
15366
15367        self.transact(window, cx, |this, window, cx| {
15368            this.buffer.update(cx, |buffer, cx| {
15369                buffer.edit(
15370                    full_edits
15371                        .iter()
15372                        .map(|(_, p, t)| (p.clone(), t.clone()))
15373                        .collect::<Vec<_>>(),
15374                    None,
15375                    cx,
15376                );
15377            });
15378            this.change_selections(Default::default(), window, cx, |s| {
15379                let mut offset = 0;
15380                let mut selections = vec![];
15381                for (id, parent, text) in full_edits {
15382                    let start = parent.start - offset;
15383                    offset += parent.len() - text.len();
15384                    selections.push(Selection {
15385                        id,
15386                        start,
15387                        end: start + text.len(),
15388                        reversed: false,
15389                        goal: Default::default(),
15390                    });
15391                }
15392                s.select(selections);
15393            });
15394        });
15395    }
15396
15397    pub fn select_next_syntax_node(
15398        &mut self,
15399        _: &SelectNextSyntaxNode,
15400        window: &mut Window,
15401        cx: &mut Context<Self>,
15402    ) {
15403        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15404        if old_selections.is_empty() {
15405            return;
15406        }
15407
15408        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15409
15410        let buffer = self.buffer.read(cx).snapshot(cx);
15411        let mut selected_sibling = false;
15412
15413        let new_selections = old_selections
15414            .iter()
15415            .map(|selection| {
15416                let old_range = selection.start..selection.end;
15417
15418                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15419                    let new_range = node.byte_range();
15420                    selected_sibling = true;
15421                    Selection {
15422                        id: selection.id,
15423                        start: new_range.start,
15424                        end: new_range.end,
15425                        goal: SelectionGoal::None,
15426                        reversed: selection.reversed,
15427                    }
15428                } else {
15429                    selection.clone()
15430                }
15431            })
15432            .collect::<Vec<_>>();
15433
15434        if selected_sibling {
15435            self.change_selections(
15436                SelectionEffects::scroll(Autoscroll::fit()),
15437                window,
15438                cx,
15439                |s| {
15440                    s.select(new_selections);
15441                },
15442            );
15443        }
15444    }
15445
15446    pub fn select_prev_syntax_node(
15447        &mut self,
15448        _: &SelectPreviousSyntaxNode,
15449        window: &mut Window,
15450        cx: &mut Context<Self>,
15451    ) {
15452        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15453        if old_selections.is_empty() {
15454            return;
15455        }
15456
15457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15458
15459        let buffer = self.buffer.read(cx).snapshot(cx);
15460        let mut selected_sibling = false;
15461
15462        let new_selections = old_selections
15463            .iter()
15464            .map(|selection| {
15465                let old_range = selection.start..selection.end;
15466
15467                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15468                    let new_range = node.byte_range();
15469                    selected_sibling = true;
15470                    Selection {
15471                        id: selection.id,
15472                        start: new_range.start,
15473                        end: new_range.end,
15474                        goal: SelectionGoal::None,
15475                        reversed: selection.reversed,
15476                    }
15477                } else {
15478                    selection.clone()
15479                }
15480            })
15481            .collect::<Vec<_>>();
15482
15483        if selected_sibling {
15484            self.change_selections(
15485                SelectionEffects::scroll(Autoscroll::fit()),
15486                window,
15487                cx,
15488                |s| {
15489                    s.select(new_selections);
15490                },
15491            );
15492        }
15493    }
15494
15495    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15496        if !EditorSettings::get_global(cx).gutter.runnables {
15497            self.clear_tasks();
15498            return Task::ready(());
15499        }
15500        let project = self.project().map(Entity::downgrade);
15501        let task_sources = self.lsp_task_sources(cx);
15502        let multi_buffer = self.buffer.downgrade();
15503        cx.spawn_in(window, async move |editor, cx| {
15504            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15505            let Some(project) = project.and_then(|p| p.upgrade()) else {
15506                return;
15507            };
15508            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15509                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15510            }) else {
15511                return;
15512            };
15513
15514            let hide_runnables = project
15515                .update(cx, |project, _| project.is_via_collab())
15516                .unwrap_or(true);
15517            if hide_runnables {
15518                return;
15519            }
15520            let new_rows =
15521                cx.background_spawn({
15522                    let snapshot = display_snapshot.clone();
15523                    async move {
15524                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15525                    }
15526                })
15527                    .await;
15528            let Ok(lsp_tasks) =
15529                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15530            else {
15531                return;
15532            };
15533            let lsp_tasks = lsp_tasks.await;
15534
15535            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15536                lsp_tasks
15537                    .into_iter()
15538                    .flat_map(|(kind, tasks)| {
15539                        tasks.into_iter().filter_map(move |(location, task)| {
15540                            Some((kind.clone(), location?, task))
15541                        })
15542                    })
15543                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15544                        let buffer = location.target.buffer;
15545                        let buffer_snapshot = buffer.read(cx).snapshot();
15546                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15547                            |(excerpt_id, snapshot, _)| {
15548                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15549                                    display_snapshot
15550                                        .buffer_snapshot()
15551                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15552                                } else {
15553                                    None
15554                                }
15555                            },
15556                        );
15557                        if let Some(offset) = offset {
15558                            let task_buffer_range =
15559                                location.target.range.to_point(&buffer_snapshot);
15560                            let context_buffer_range =
15561                                task_buffer_range.to_offset(&buffer_snapshot);
15562                            let context_range = BufferOffset(context_buffer_range.start)
15563                                ..BufferOffset(context_buffer_range.end);
15564
15565                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15566                                .or_insert_with(|| RunnableTasks {
15567                                    templates: Vec::new(),
15568                                    offset,
15569                                    column: task_buffer_range.start.column,
15570                                    extra_variables: HashMap::default(),
15571                                    context_range,
15572                                })
15573                                .templates
15574                                .push((kind, task.original_task().clone()));
15575                        }
15576
15577                        acc
15578                    })
15579            }) else {
15580                return;
15581            };
15582
15583            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15584                buffer.language_settings(cx).tasks.prefer_lsp
15585            }) else {
15586                return;
15587            };
15588
15589            let rows = Self::runnable_rows(
15590                project,
15591                display_snapshot,
15592                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15593                new_rows,
15594                cx.clone(),
15595            )
15596            .await;
15597            editor
15598                .update(cx, |editor, _| {
15599                    editor.clear_tasks();
15600                    for (key, mut value) in rows {
15601                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15602                            value.templates.extend(lsp_tasks.templates);
15603                        }
15604
15605                        editor.insert_tasks(key, value);
15606                    }
15607                    for (key, value) in lsp_tasks_by_rows {
15608                        editor.insert_tasks(key, value);
15609                    }
15610                })
15611                .ok();
15612        })
15613    }
15614    fn fetch_runnable_ranges(
15615        snapshot: &DisplaySnapshot,
15616        range: Range<Anchor>,
15617    ) -> Vec<language::RunnableRange> {
15618        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15619    }
15620
15621    fn runnable_rows(
15622        project: Entity<Project>,
15623        snapshot: DisplaySnapshot,
15624        prefer_lsp: bool,
15625        runnable_ranges: Vec<RunnableRange>,
15626        cx: AsyncWindowContext,
15627    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15628        cx.spawn(async move |cx| {
15629            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15630            for mut runnable in runnable_ranges {
15631                let Some(tasks) = cx
15632                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15633                    .ok()
15634                else {
15635                    continue;
15636                };
15637                let mut tasks = tasks.await;
15638
15639                if prefer_lsp {
15640                    tasks.retain(|(task_kind, _)| {
15641                        !matches!(task_kind, TaskSourceKind::Language { .. })
15642                    });
15643                }
15644                if tasks.is_empty() {
15645                    continue;
15646                }
15647
15648                let point = runnable
15649                    .run_range
15650                    .start
15651                    .to_point(&snapshot.buffer_snapshot());
15652                let Some(row) = snapshot
15653                    .buffer_snapshot()
15654                    .buffer_line_for_row(MultiBufferRow(point.row))
15655                    .map(|(_, range)| range.start.row)
15656                else {
15657                    continue;
15658                };
15659
15660                let context_range =
15661                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15662                runnable_rows.push((
15663                    (runnable.buffer_id, row),
15664                    RunnableTasks {
15665                        templates: tasks,
15666                        offset: snapshot
15667                            .buffer_snapshot()
15668                            .anchor_before(runnable.run_range.start),
15669                        context_range,
15670                        column: point.column,
15671                        extra_variables: runnable.extra_captures,
15672                    },
15673                ));
15674            }
15675            runnable_rows
15676        })
15677    }
15678
15679    fn templates_with_tags(
15680        project: &Entity<Project>,
15681        runnable: &mut Runnable,
15682        cx: &mut App,
15683    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15684        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15685            let (worktree_id, file) = project
15686                .buffer_for_id(runnable.buffer, cx)
15687                .and_then(|buffer| buffer.read(cx).file())
15688                .map(|file| (file.worktree_id(cx), file.clone()))
15689                .unzip();
15690
15691            (
15692                project.task_store().read(cx).task_inventory().cloned(),
15693                worktree_id,
15694                file,
15695            )
15696        });
15697
15698        let tags = mem::take(&mut runnable.tags);
15699        let language = runnable.language.clone();
15700        cx.spawn(async move |cx| {
15701            let mut templates_with_tags = Vec::new();
15702            if let Some(inventory) = inventory {
15703                for RunnableTag(tag) in tags {
15704                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15705                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15706                    }) else {
15707                        return templates_with_tags;
15708                    };
15709                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15710                        move |(_, template)| {
15711                            template.tags.iter().any(|source_tag| source_tag == &tag)
15712                        },
15713                    ));
15714                }
15715            }
15716            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15717
15718            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15719                // Strongest source wins; if we have worktree tag binding, prefer that to
15720                // global and language bindings;
15721                // if we have a global binding, prefer that to language binding.
15722                let first_mismatch = templates_with_tags
15723                    .iter()
15724                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15725                if let Some(index) = first_mismatch {
15726                    templates_with_tags.truncate(index);
15727                }
15728            }
15729
15730            templates_with_tags
15731        })
15732    }
15733
15734    pub fn move_to_enclosing_bracket(
15735        &mut self,
15736        _: &MoveToEnclosingBracket,
15737        window: &mut Window,
15738        cx: &mut Context<Self>,
15739    ) {
15740        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15741        self.change_selections(Default::default(), window, cx, |s| {
15742            s.move_offsets_with(|snapshot, selection| {
15743                let Some(enclosing_bracket_ranges) =
15744                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15745                else {
15746                    return;
15747                };
15748
15749                let mut best_length = usize::MAX;
15750                let mut best_inside = false;
15751                let mut best_in_bracket_range = false;
15752                let mut best_destination = None;
15753                for (open, close) in enclosing_bracket_ranges {
15754                    let close = close.to_inclusive();
15755                    let length = close.end() - open.start;
15756                    let inside = selection.start >= open.end && selection.end <= *close.start();
15757                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15758                        || close.contains(&selection.head());
15759
15760                    // If best is next to a bracket and current isn't, skip
15761                    if !in_bracket_range && best_in_bracket_range {
15762                        continue;
15763                    }
15764
15765                    // Prefer smaller lengths unless best is inside and current isn't
15766                    if length > best_length && (best_inside || !inside) {
15767                        continue;
15768                    }
15769
15770                    best_length = length;
15771                    best_inside = inside;
15772                    best_in_bracket_range = in_bracket_range;
15773                    best_destination = Some(
15774                        if close.contains(&selection.start) && close.contains(&selection.end) {
15775                            if inside { open.end } else { open.start }
15776                        } else if inside {
15777                            *close.start()
15778                        } else {
15779                            *close.end()
15780                        },
15781                    );
15782                }
15783
15784                if let Some(destination) = best_destination {
15785                    selection.collapse_to(destination, SelectionGoal::None);
15786                }
15787            })
15788        });
15789    }
15790
15791    pub fn undo_selection(
15792        &mut self,
15793        _: &UndoSelection,
15794        window: &mut Window,
15795        cx: &mut Context<Self>,
15796    ) {
15797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15798        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15799            self.selection_history.mode = SelectionHistoryMode::Undoing;
15800            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15801                this.end_selection(window, cx);
15802                this.change_selections(
15803                    SelectionEffects::scroll(Autoscroll::newest()),
15804                    window,
15805                    cx,
15806                    |s| s.select_anchors(entry.selections.to_vec()),
15807                );
15808            });
15809            self.selection_history.mode = SelectionHistoryMode::Normal;
15810
15811            self.select_next_state = entry.select_next_state;
15812            self.select_prev_state = entry.select_prev_state;
15813            self.add_selections_state = entry.add_selections_state;
15814        }
15815    }
15816
15817    pub fn redo_selection(
15818        &mut self,
15819        _: &RedoSelection,
15820        window: &mut Window,
15821        cx: &mut Context<Self>,
15822    ) {
15823        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15824        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15825            self.selection_history.mode = SelectionHistoryMode::Redoing;
15826            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15827                this.end_selection(window, cx);
15828                this.change_selections(
15829                    SelectionEffects::scroll(Autoscroll::newest()),
15830                    window,
15831                    cx,
15832                    |s| s.select_anchors(entry.selections.to_vec()),
15833                );
15834            });
15835            self.selection_history.mode = SelectionHistoryMode::Normal;
15836
15837            self.select_next_state = entry.select_next_state;
15838            self.select_prev_state = entry.select_prev_state;
15839            self.add_selections_state = entry.add_selections_state;
15840        }
15841    }
15842
15843    pub fn expand_excerpts(
15844        &mut self,
15845        action: &ExpandExcerpts,
15846        _: &mut Window,
15847        cx: &mut Context<Self>,
15848    ) {
15849        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15850    }
15851
15852    pub fn expand_excerpts_down(
15853        &mut self,
15854        action: &ExpandExcerptsDown,
15855        _: &mut Window,
15856        cx: &mut Context<Self>,
15857    ) {
15858        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15859    }
15860
15861    pub fn expand_excerpts_up(
15862        &mut self,
15863        action: &ExpandExcerptsUp,
15864        _: &mut Window,
15865        cx: &mut Context<Self>,
15866    ) {
15867        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15868    }
15869
15870    pub fn expand_excerpts_for_direction(
15871        &mut self,
15872        lines: u32,
15873        direction: ExpandExcerptDirection,
15874
15875        cx: &mut Context<Self>,
15876    ) {
15877        let selections = self.selections.disjoint_anchors_arc();
15878
15879        let lines = if lines == 0 {
15880            EditorSettings::get_global(cx).expand_excerpt_lines
15881        } else {
15882            lines
15883        };
15884
15885        self.buffer.update(cx, |buffer, cx| {
15886            let snapshot = buffer.snapshot(cx);
15887            let mut excerpt_ids = selections
15888                .iter()
15889                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15890                .collect::<Vec<_>>();
15891            excerpt_ids.sort();
15892            excerpt_ids.dedup();
15893            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15894        })
15895    }
15896
15897    pub fn expand_excerpt(
15898        &mut self,
15899        excerpt: ExcerptId,
15900        direction: ExpandExcerptDirection,
15901        window: &mut Window,
15902        cx: &mut Context<Self>,
15903    ) {
15904        let current_scroll_position = self.scroll_position(cx);
15905        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15906        let mut should_scroll_up = false;
15907
15908        if direction == ExpandExcerptDirection::Down {
15909            let multi_buffer = self.buffer.read(cx);
15910            let snapshot = multi_buffer.snapshot(cx);
15911            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15912                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15913                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15914            {
15915                let buffer_snapshot = buffer.read(cx).snapshot();
15916                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15917                let last_row = buffer_snapshot.max_point().row;
15918                let lines_below = last_row.saturating_sub(excerpt_end_row);
15919                should_scroll_up = lines_below >= lines_to_expand;
15920            }
15921        }
15922
15923        self.buffer.update(cx, |buffer, cx| {
15924            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15925        });
15926
15927        if should_scroll_up {
15928            let new_scroll_position =
15929                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15930            self.set_scroll_position(new_scroll_position, window, cx);
15931        }
15932    }
15933
15934    pub fn go_to_singleton_buffer_point(
15935        &mut self,
15936        point: Point,
15937        window: &mut Window,
15938        cx: &mut Context<Self>,
15939    ) {
15940        self.go_to_singleton_buffer_range(point..point, window, cx);
15941    }
15942
15943    pub fn go_to_singleton_buffer_range(
15944        &mut self,
15945        range: Range<Point>,
15946        window: &mut Window,
15947        cx: &mut Context<Self>,
15948    ) {
15949        let multibuffer = self.buffer().read(cx);
15950        let Some(buffer) = multibuffer.as_singleton() else {
15951            return;
15952        };
15953        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15954            return;
15955        };
15956        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15957            return;
15958        };
15959        self.change_selections(
15960            SelectionEffects::default().nav_history(true),
15961            window,
15962            cx,
15963            |s| s.select_anchor_ranges([start..end]),
15964        );
15965    }
15966
15967    pub fn go_to_diagnostic(
15968        &mut self,
15969        action: &GoToDiagnostic,
15970        window: &mut Window,
15971        cx: &mut Context<Self>,
15972    ) {
15973        if !self.diagnostics_enabled() {
15974            return;
15975        }
15976        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15977        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15978    }
15979
15980    pub fn go_to_prev_diagnostic(
15981        &mut self,
15982        action: &GoToPreviousDiagnostic,
15983        window: &mut Window,
15984        cx: &mut Context<Self>,
15985    ) {
15986        if !self.diagnostics_enabled() {
15987            return;
15988        }
15989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15990        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15991    }
15992
15993    pub fn go_to_diagnostic_impl(
15994        &mut self,
15995        direction: Direction,
15996        severity: GoToDiagnosticSeverityFilter,
15997        window: &mut Window,
15998        cx: &mut Context<Self>,
15999    ) {
16000        let buffer = self.buffer.read(cx).snapshot(cx);
16001        let selection = self.selections.newest::<usize>(cx);
16002
16003        let mut active_group_id = None;
16004        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16005            && active_group.active_range.start.to_offset(&buffer) == selection.start
16006        {
16007            active_group_id = Some(active_group.group_id);
16008        }
16009
16010        fn filtered<'a>(
16011            snapshot: EditorSnapshot,
16012            severity: GoToDiagnosticSeverityFilter,
16013            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16014        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16015            diagnostics
16016                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16017                .filter(|entry| entry.range.start != entry.range.end)
16018                .filter(|entry| !entry.diagnostic.is_unnecessary)
16019                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16020        }
16021
16022        let snapshot = self.snapshot(window, cx);
16023        let before = filtered(
16024            snapshot.clone(),
16025            severity,
16026            buffer
16027                .diagnostics_in_range(0..selection.start)
16028                .filter(|entry| entry.range.start <= selection.start),
16029        );
16030        let after = filtered(
16031            snapshot,
16032            severity,
16033            buffer
16034                .diagnostics_in_range(selection.start..buffer.len())
16035                .filter(|entry| entry.range.start >= selection.start),
16036        );
16037
16038        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16039        if direction == Direction::Prev {
16040            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16041            {
16042                for diagnostic in prev_diagnostics.into_iter().rev() {
16043                    if diagnostic.range.start != selection.start
16044                        || active_group_id
16045                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16046                    {
16047                        found = Some(diagnostic);
16048                        break 'outer;
16049                    }
16050                }
16051            }
16052        } else {
16053            for diagnostic in after.chain(before) {
16054                if diagnostic.range.start != selection.start
16055                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16056                {
16057                    found = Some(diagnostic);
16058                    break;
16059                }
16060            }
16061        }
16062        let Some(next_diagnostic) = found else {
16063            return;
16064        };
16065
16066        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16067        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16068            return;
16069        };
16070        self.change_selections(Default::default(), window, cx, |s| {
16071            s.select_ranges(vec![
16072                next_diagnostic.range.start..next_diagnostic.range.start,
16073            ])
16074        });
16075        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16076        self.refresh_edit_prediction(false, true, window, cx);
16077    }
16078
16079    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16081        let snapshot = self.snapshot(window, cx);
16082        let selection = self.selections.newest::<Point>(cx);
16083        self.go_to_hunk_before_or_after_position(
16084            &snapshot,
16085            selection.head(),
16086            Direction::Next,
16087            window,
16088            cx,
16089        );
16090    }
16091
16092    pub fn go_to_hunk_before_or_after_position(
16093        &mut self,
16094        snapshot: &EditorSnapshot,
16095        position: Point,
16096        direction: Direction,
16097        window: &mut Window,
16098        cx: &mut Context<Editor>,
16099    ) {
16100        let row = if direction == Direction::Next {
16101            self.hunk_after_position(snapshot, position)
16102                .map(|hunk| hunk.row_range.start)
16103        } else {
16104            self.hunk_before_position(snapshot, position)
16105        };
16106
16107        if let Some(row) = row {
16108            let destination = Point::new(row.0, 0);
16109            let autoscroll = Autoscroll::center();
16110
16111            self.unfold_ranges(&[destination..destination], false, false, cx);
16112            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16113                s.select_ranges([destination..destination]);
16114            });
16115        }
16116    }
16117
16118    fn hunk_after_position(
16119        &mut self,
16120        snapshot: &EditorSnapshot,
16121        position: Point,
16122    ) -> Option<MultiBufferDiffHunk> {
16123        snapshot
16124            .buffer_snapshot()
16125            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16126            .find(|hunk| hunk.row_range.start.0 > position.row)
16127            .or_else(|| {
16128                snapshot
16129                    .buffer_snapshot()
16130                    .diff_hunks_in_range(Point::zero()..position)
16131                    .find(|hunk| hunk.row_range.end.0 < position.row)
16132            })
16133    }
16134
16135    fn go_to_prev_hunk(
16136        &mut self,
16137        _: &GoToPreviousHunk,
16138        window: &mut Window,
16139        cx: &mut Context<Self>,
16140    ) {
16141        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16142        let snapshot = self.snapshot(window, cx);
16143        let selection = self.selections.newest::<Point>(cx);
16144        self.go_to_hunk_before_or_after_position(
16145            &snapshot,
16146            selection.head(),
16147            Direction::Prev,
16148            window,
16149            cx,
16150        );
16151    }
16152
16153    fn hunk_before_position(
16154        &mut self,
16155        snapshot: &EditorSnapshot,
16156        position: Point,
16157    ) -> Option<MultiBufferRow> {
16158        snapshot
16159            .buffer_snapshot()
16160            .diff_hunk_before(position)
16161            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16162    }
16163
16164    fn go_to_next_change(
16165        &mut self,
16166        _: &GoToNextChange,
16167        window: &mut Window,
16168        cx: &mut Context<Self>,
16169    ) {
16170        if let Some(selections) = self
16171            .change_list
16172            .next_change(1, Direction::Next)
16173            .map(|s| s.to_vec())
16174        {
16175            self.change_selections(Default::default(), window, cx, |s| {
16176                let map = s.display_map();
16177                s.select_display_ranges(selections.iter().map(|a| {
16178                    let point = a.to_display_point(&map);
16179                    point..point
16180                }))
16181            })
16182        }
16183    }
16184
16185    fn go_to_previous_change(
16186        &mut self,
16187        _: &GoToPreviousChange,
16188        window: &mut Window,
16189        cx: &mut Context<Self>,
16190    ) {
16191        if let Some(selections) = self
16192            .change_list
16193            .next_change(1, Direction::Prev)
16194            .map(|s| s.to_vec())
16195        {
16196            self.change_selections(Default::default(), window, cx, |s| {
16197                let map = s.display_map();
16198                s.select_display_ranges(selections.iter().map(|a| {
16199                    let point = a.to_display_point(&map);
16200                    point..point
16201                }))
16202            })
16203        }
16204    }
16205
16206    pub fn go_to_next_document_highlight(
16207        &mut self,
16208        _: &GoToNextDocumentHighlight,
16209        window: &mut Window,
16210        cx: &mut Context<Self>,
16211    ) {
16212        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16213    }
16214
16215    pub fn go_to_prev_document_highlight(
16216        &mut self,
16217        _: &GoToPreviousDocumentHighlight,
16218        window: &mut Window,
16219        cx: &mut Context<Self>,
16220    ) {
16221        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16222    }
16223
16224    pub fn go_to_document_highlight_before_or_after_position(
16225        &mut self,
16226        direction: Direction,
16227        window: &mut Window,
16228        cx: &mut Context<Editor>,
16229    ) {
16230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16231        let snapshot = self.snapshot(window, cx);
16232        let buffer = &snapshot.buffer_snapshot();
16233        let position = self.selections.newest::<Point>(cx).head();
16234        let anchor_position = buffer.anchor_after(position);
16235
16236        // Get all document highlights (both read and write)
16237        let mut all_highlights = Vec::new();
16238
16239        if let Some((_, read_highlights)) = self
16240            .background_highlights
16241            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16242        {
16243            all_highlights.extend(read_highlights.iter());
16244        }
16245
16246        if let Some((_, write_highlights)) = self
16247            .background_highlights
16248            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16249        {
16250            all_highlights.extend(write_highlights.iter());
16251        }
16252
16253        if all_highlights.is_empty() {
16254            return;
16255        }
16256
16257        // Sort highlights by position
16258        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16259
16260        let target_highlight = match direction {
16261            Direction::Next => {
16262                // Find the first highlight after the current position
16263                all_highlights
16264                    .iter()
16265                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16266            }
16267            Direction::Prev => {
16268                // Find the last highlight before the current position
16269                all_highlights
16270                    .iter()
16271                    .rev()
16272                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16273            }
16274        };
16275
16276        if let Some(highlight) = target_highlight {
16277            let destination = highlight.start.to_point(buffer);
16278            let autoscroll = Autoscroll::center();
16279
16280            self.unfold_ranges(&[destination..destination], false, false, cx);
16281            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16282                s.select_ranges([destination..destination]);
16283            });
16284        }
16285    }
16286
16287    fn go_to_line<T: 'static>(
16288        &mut self,
16289        position: Anchor,
16290        highlight_color: Option<Hsla>,
16291        window: &mut Window,
16292        cx: &mut Context<Self>,
16293    ) {
16294        let snapshot = self.snapshot(window, cx).display_snapshot;
16295        let position = position.to_point(&snapshot.buffer_snapshot());
16296        let start = snapshot
16297            .buffer_snapshot()
16298            .clip_point(Point::new(position.row, 0), Bias::Left);
16299        let end = start + Point::new(1, 0);
16300        let start = snapshot.buffer_snapshot().anchor_before(start);
16301        let end = snapshot.buffer_snapshot().anchor_before(end);
16302
16303        self.highlight_rows::<T>(
16304            start..end,
16305            highlight_color
16306                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16307            Default::default(),
16308            cx,
16309        );
16310
16311        if self.buffer.read(cx).is_singleton() {
16312            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16313        }
16314    }
16315
16316    pub fn go_to_definition(
16317        &mut self,
16318        _: &GoToDefinition,
16319        window: &mut Window,
16320        cx: &mut Context<Self>,
16321    ) -> Task<Result<Navigated>> {
16322        let definition =
16323            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16324        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16325        cx.spawn_in(window, async move |editor, cx| {
16326            if definition.await? == Navigated::Yes {
16327                return Ok(Navigated::Yes);
16328            }
16329            match fallback_strategy {
16330                GoToDefinitionFallback::None => Ok(Navigated::No),
16331                GoToDefinitionFallback::FindAllReferences => {
16332                    match editor.update_in(cx, |editor, window, cx| {
16333                        editor.find_all_references(&FindAllReferences, window, cx)
16334                    })? {
16335                        Some(references) => references.await,
16336                        None => Ok(Navigated::No),
16337                    }
16338                }
16339            }
16340        })
16341    }
16342
16343    pub fn go_to_declaration(
16344        &mut self,
16345        _: &GoToDeclaration,
16346        window: &mut Window,
16347        cx: &mut Context<Self>,
16348    ) -> Task<Result<Navigated>> {
16349        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16350    }
16351
16352    pub fn go_to_declaration_split(
16353        &mut self,
16354        _: &GoToDeclaration,
16355        window: &mut Window,
16356        cx: &mut Context<Self>,
16357    ) -> Task<Result<Navigated>> {
16358        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16359    }
16360
16361    pub fn go_to_implementation(
16362        &mut self,
16363        _: &GoToImplementation,
16364        window: &mut Window,
16365        cx: &mut Context<Self>,
16366    ) -> Task<Result<Navigated>> {
16367        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16368    }
16369
16370    pub fn go_to_implementation_split(
16371        &mut self,
16372        _: &GoToImplementationSplit,
16373        window: &mut Window,
16374        cx: &mut Context<Self>,
16375    ) -> Task<Result<Navigated>> {
16376        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16377    }
16378
16379    pub fn go_to_type_definition(
16380        &mut self,
16381        _: &GoToTypeDefinition,
16382        window: &mut Window,
16383        cx: &mut Context<Self>,
16384    ) -> Task<Result<Navigated>> {
16385        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16386    }
16387
16388    pub fn go_to_definition_split(
16389        &mut self,
16390        _: &GoToDefinitionSplit,
16391        window: &mut Window,
16392        cx: &mut Context<Self>,
16393    ) -> Task<Result<Navigated>> {
16394        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16395    }
16396
16397    pub fn go_to_type_definition_split(
16398        &mut self,
16399        _: &GoToTypeDefinitionSplit,
16400        window: &mut Window,
16401        cx: &mut Context<Self>,
16402    ) -> Task<Result<Navigated>> {
16403        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16404    }
16405
16406    fn go_to_definition_of_kind(
16407        &mut self,
16408        kind: GotoDefinitionKind,
16409        split: bool,
16410        window: &mut Window,
16411        cx: &mut Context<Self>,
16412    ) -> Task<Result<Navigated>> {
16413        let Some(provider) = self.semantics_provider.clone() else {
16414            return Task::ready(Ok(Navigated::No));
16415        };
16416        let head = self.selections.newest::<usize>(cx).head();
16417        let buffer = self.buffer.read(cx);
16418        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16419            return Task::ready(Ok(Navigated::No));
16420        };
16421        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16422            return Task::ready(Ok(Navigated::No));
16423        };
16424
16425        cx.spawn_in(window, async move |editor, cx| {
16426            let Some(definitions) = definitions.await? else {
16427                return Ok(Navigated::No);
16428            };
16429            let navigated = editor
16430                .update_in(cx, |editor, window, cx| {
16431                    editor.navigate_to_hover_links(
16432                        Some(kind),
16433                        definitions
16434                            .into_iter()
16435                            .filter(|location| {
16436                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16437                            })
16438                            .map(HoverLink::Text)
16439                            .collect::<Vec<_>>(),
16440                        split,
16441                        window,
16442                        cx,
16443                    )
16444                })?
16445                .await?;
16446            anyhow::Ok(navigated)
16447        })
16448    }
16449
16450    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16451        let selection = self.selections.newest_anchor();
16452        let head = selection.head();
16453        let tail = selection.tail();
16454
16455        let Some((buffer, start_position)) =
16456            self.buffer.read(cx).text_anchor_for_position(head, cx)
16457        else {
16458            return;
16459        };
16460
16461        let end_position = if head != tail {
16462            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16463                return;
16464            };
16465            Some(pos)
16466        } else {
16467            None
16468        };
16469
16470        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16471            let url = if let Some(end_pos) = end_position {
16472                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16473            } else {
16474                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16475            };
16476
16477            if let Some(url) = url {
16478                cx.update(|window, cx| {
16479                    if parse_zed_link(&url, cx).is_some() {
16480                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16481                    } else {
16482                        cx.open_url(&url);
16483                    }
16484                })?;
16485            }
16486
16487            anyhow::Ok(())
16488        });
16489
16490        url_finder.detach();
16491    }
16492
16493    pub fn open_selected_filename(
16494        &mut self,
16495        _: &OpenSelectedFilename,
16496        window: &mut Window,
16497        cx: &mut Context<Self>,
16498    ) {
16499        let Some(workspace) = self.workspace() else {
16500            return;
16501        };
16502
16503        let position = self.selections.newest_anchor().head();
16504
16505        let Some((buffer, buffer_position)) =
16506            self.buffer.read(cx).text_anchor_for_position(position, cx)
16507        else {
16508            return;
16509        };
16510
16511        let project = self.project.clone();
16512
16513        cx.spawn_in(window, async move |_, cx| {
16514            let result = find_file(&buffer, project, buffer_position, cx).await;
16515
16516            if let Some((_, path)) = result {
16517                workspace
16518                    .update_in(cx, |workspace, window, cx| {
16519                        workspace.open_resolved_path(path, window, cx)
16520                    })?
16521                    .await?;
16522            }
16523            anyhow::Ok(())
16524        })
16525        .detach();
16526    }
16527
16528    pub(crate) fn navigate_to_hover_links(
16529        &mut self,
16530        kind: Option<GotoDefinitionKind>,
16531        definitions: Vec<HoverLink>,
16532        split: bool,
16533        window: &mut Window,
16534        cx: &mut Context<Editor>,
16535    ) -> Task<Result<Navigated>> {
16536        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16537        let mut first_url_or_file = None;
16538        let definitions: Vec<_> = definitions
16539            .into_iter()
16540            .filter_map(|def| match def {
16541                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16542                HoverLink::InlayHint(lsp_location, server_id) => {
16543                    let computation =
16544                        self.compute_target_location(lsp_location, server_id, window, cx);
16545                    Some(cx.background_spawn(computation))
16546                }
16547                HoverLink::Url(url) => {
16548                    first_url_or_file = Some(Either::Left(url));
16549                    None
16550                }
16551                HoverLink::File(path) => {
16552                    first_url_or_file = Some(Either::Right(path));
16553                    None
16554                }
16555            })
16556            .collect();
16557
16558        let workspace = self.workspace();
16559
16560        cx.spawn_in(window, async move |editor, cx| {
16561            let locations: Vec<Location> = future::join_all(definitions)
16562                .await
16563                .into_iter()
16564                .filter_map(|location| location.transpose())
16565                .collect::<Result<_>>()
16566                .context("location tasks")?;
16567            let mut locations = cx.update(|_, cx| {
16568                locations
16569                    .into_iter()
16570                    .map(|location| {
16571                        let buffer = location.buffer.read(cx);
16572                        (location.buffer, location.range.to_point(buffer))
16573                    })
16574                    .into_group_map()
16575            })?;
16576            let mut num_locations = 0;
16577            for ranges in locations.values_mut() {
16578                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16579                ranges.dedup();
16580                num_locations += ranges.len();
16581            }
16582
16583            if num_locations > 1 {
16584                let Some(workspace) = workspace else {
16585                    return Ok(Navigated::No);
16586                };
16587
16588                let tab_kind = match kind {
16589                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16590                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16591                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16592                    Some(GotoDefinitionKind::Type) => "Types",
16593                };
16594                let title = editor
16595                    .update_in(cx, |_, _, cx| {
16596                        let target = locations
16597                            .iter()
16598                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16599                            .map(|(buffer, location)| {
16600                                buffer
16601                                    .read(cx)
16602                                    .text_for_range(location.clone())
16603                                    .collect::<String>()
16604                            })
16605                            .filter(|text| !text.contains('\n'))
16606                            .unique()
16607                            .take(3)
16608                            .join(", ");
16609                        if target.is_empty() {
16610                            tab_kind.to_owned()
16611                        } else {
16612                            format!("{tab_kind} for {target}")
16613                        }
16614                    })
16615                    .context("buffer title")?;
16616
16617                let opened = workspace
16618                    .update_in(cx, |workspace, window, cx| {
16619                        Self::open_locations_in_multibuffer(
16620                            workspace,
16621                            locations,
16622                            title,
16623                            split,
16624                            MultibufferSelectionMode::First,
16625                            window,
16626                            cx,
16627                        )
16628                    })
16629                    .is_ok();
16630
16631                anyhow::Ok(Navigated::from_bool(opened))
16632            } else if num_locations == 0 {
16633                // If there is one url or file, open it directly
16634                match first_url_or_file {
16635                    Some(Either::Left(url)) => {
16636                        cx.update(|_, cx| cx.open_url(&url))?;
16637                        Ok(Navigated::Yes)
16638                    }
16639                    Some(Either::Right(path)) => {
16640                        let Some(workspace) = workspace else {
16641                            return Ok(Navigated::No);
16642                        };
16643
16644                        workspace
16645                            .update_in(cx, |workspace, window, cx| {
16646                                workspace.open_resolved_path(path, window, cx)
16647                            })?
16648                            .await?;
16649                        Ok(Navigated::Yes)
16650                    }
16651                    None => Ok(Navigated::No),
16652                }
16653            } else {
16654                let Some(workspace) = workspace else {
16655                    return Ok(Navigated::No);
16656                };
16657
16658                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16659                let target_range = target_ranges.first().unwrap().clone();
16660
16661                editor.update_in(cx, |editor, window, cx| {
16662                    let range = target_range.to_point(target_buffer.read(cx));
16663                    let range = editor.range_for_match(&range);
16664                    let range = collapse_multiline_range(range);
16665
16666                    if !split
16667                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16668                    {
16669                        editor.go_to_singleton_buffer_range(range, window, cx);
16670                    } else {
16671                        let pane = workspace.read(cx).active_pane().clone();
16672                        window.defer(cx, move |window, cx| {
16673                            let target_editor: Entity<Self> =
16674                                workspace.update(cx, |workspace, cx| {
16675                                    let pane = if split {
16676                                        workspace.adjacent_pane(window, cx)
16677                                    } else {
16678                                        workspace.active_pane().clone()
16679                                    };
16680
16681                                    workspace.open_project_item(
16682                                        pane,
16683                                        target_buffer.clone(),
16684                                        true,
16685                                        true,
16686                                        window,
16687                                        cx,
16688                                    )
16689                                });
16690                            target_editor.update(cx, |target_editor, cx| {
16691                                // When selecting a definition in a different buffer, disable the nav history
16692                                // to avoid creating a history entry at the previous cursor location.
16693                                pane.update(cx, |pane, _| pane.disable_history());
16694                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16695                                pane.update(cx, |pane, _| pane.enable_history());
16696                            });
16697                        });
16698                    }
16699                    Navigated::Yes
16700                })
16701            }
16702        })
16703    }
16704
16705    fn compute_target_location(
16706        &self,
16707        lsp_location: lsp::Location,
16708        server_id: LanguageServerId,
16709        window: &mut Window,
16710        cx: &mut Context<Self>,
16711    ) -> Task<anyhow::Result<Option<Location>>> {
16712        let Some(project) = self.project.clone() else {
16713            return Task::ready(Ok(None));
16714        };
16715
16716        cx.spawn_in(window, async move |editor, cx| {
16717            let location_task = editor.update(cx, |_, cx| {
16718                project.update(cx, |project, cx| {
16719                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16720                })
16721            })?;
16722            let location = Some({
16723                let target_buffer_handle = location_task.await.context("open local buffer")?;
16724                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16725                    let target_start = target_buffer
16726                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16727                    let target_end = target_buffer
16728                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16729                    target_buffer.anchor_after(target_start)
16730                        ..target_buffer.anchor_before(target_end)
16731                })?;
16732                Location {
16733                    buffer: target_buffer_handle,
16734                    range,
16735                }
16736            });
16737            Ok(location)
16738        })
16739    }
16740
16741    pub fn find_all_references(
16742        &mut self,
16743        _: &FindAllReferences,
16744        window: &mut Window,
16745        cx: &mut Context<Self>,
16746    ) -> Option<Task<Result<Navigated>>> {
16747        let selection = self.selections.newest::<usize>(cx);
16748        let multi_buffer = self.buffer.read(cx);
16749        let head = selection.head();
16750
16751        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16752        let head_anchor = multi_buffer_snapshot.anchor_at(
16753            head,
16754            if head < selection.tail() {
16755                Bias::Right
16756            } else {
16757                Bias::Left
16758            },
16759        );
16760
16761        match self
16762            .find_all_references_task_sources
16763            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16764        {
16765            Ok(_) => {
16766                log::info!(
16767                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16768                );
16769                return None;
16770            }
16771            Err(i) => {
16772                self.find_all_references_task_sources.insert(i, head_anchor);
16773            }
16774        }
16775
16776        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16777        let workspace = self.workspace()?;
16778        let project = workspace.read(cx).project().clone();
16779        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16780        Some(cx.spawn_in(window, async move |editor, cx| {
16781            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16782                if let Ok(i) = editor
16783                    .find_all_references_task_sources
16784                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16785                {
16786                    editor.find_all_references_task_sources.remove(i);
16787                }
16788            });
16789
16790            let Some(locations) = references.await? else {
16791                return anyhow::Ok(Navigated::No);
16792            };
16793            let mut locations = cx.update(|_, cx| {
16794                locations
16795                    .into_iter()
16796                    .map(|location| {
16797                        let buffer = location.buffer.read(cx);
16798                        (location.buffer, location.range.to_point(buffer))
16799                    })
16800                    .into_group_map()
16801            })?;
16802            if locations.is_empty() {
16803                return anyhow::Ok(Navigated::No);
16804            }
16805            for ranges in locations.values_mut() {
16806                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16807                ranges.dedup();
16808            }
16809
16810            workspace.update_in(cx, |workspace, window, cx| {
16811                let target = locations
16812                    .iter()
16813                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16814                    .map(|(buffer, location)| {
16815                        buffer
16816                            .read(cx)
16817                            .text_for_range(location.clone())
16818                            .collect::<String>()
16819                    })
16820                    .filter(|text| !text.contains('\n'))
16821                    .unique()
16822                    .take(3)
16823                    .join(", ");
16824                let title = if target.is_empty() {
16825                    "References".to_owned()
16826                } else {
16827                    format!("References to {target}")
16828                };
16829                Self::open_locations_in_multibuffer(
16830                    workspace,
16831                    locations,
16832                    title,
16833                    false,
16834                    MultibufferSelectionMode::First,
16835                    window,
16836                    cx,
16837                );
16838                Navigated::Yes
16839            })
16840        }))
16841    }
16842
16843    /// Opens a multibuffer with the given project locations in it
16844    pub fn open_locations_in_multibuffer(
16845        workspace: &mut Workspace,
16846        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16847        title: String,
16848        split: bool,
16849        multibuffer_selection_mode: MultibufferSelectionMode,
16850        window: &mut Window,
16851        cx: &mut Context<Workspace>,
16852    ) {
16853        if locations.is_empty() {
16854            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16855            return;
16856        }
16857
16858        let capability = workspace.project().read(cx).capability();
16859        let mut ranges = <Vec<Range<Anchor>>>::new();
16860
16861        // a key to find existing multibuffer editors with the same set of locations
16862        // to prevent us from opening more and more multibuffer tabs for searches and the like
16863        let mut key = (title.clone(), vec![]);
16864        let excerpt_buffer = cx.new(|cx| {
16865            let key = &mut key.1;
16866            let mut multibuffer = MultiBuffer::new(capability);
16867            for (buffer, mut ranges_for_buffer) in locations {
16868                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16869                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16870                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16871                    PathKey::for_buffer(&buffer, cx),
16872                    buffer.clone(),
16873                    ranges_for_buffer,
16874                    multibuffer_context_lines(cx),
16875                    cx,
16876                );
16877                ranges.extend(new_ranges)
16878            }
16879
16880            multibuffer.with_title(title)
16881        });
16882        let existing = workspace.active_pane().update(cx, |pane, cx| {
16883            pane.items()
16884                .filter_map(|item| item.downcast::<Editor>())
16885                .find(|editor| {
16886                    editor
16887                        .read(cx)
16888                        .lookup_key
16889                        .as_ref()
16890                        .and_then(|it| {
16891                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16892                        })
16893                        .is_some_and(|it| *it == key)
16894                })
16895        });
16896        let editor = existing.unwrap_or_else(|| {
16897            cx.new(|cx| {
16898                let mut editor = Editor::for_multibuffer(
16899                    excerpt_buffer,
16900                    Some(workspace.project().clone()),
16901                    window,
16902                    cx,
16903                );
16904                editor.lookup_key = Some(Box::new(key));
16905                editor
16906            })
16907        });
16908        editor.update(cx, |editor, cx| {
16909            match multibuffer_selection_mode {
16910                MultibufferSelectionMode::First => {
16911                    if let Some(first_range) = ranges.first() {
16912                        editor.change_selections(
16913                            SelectionEffects::no_scroll(),
16914                            window,
16915                            cx,
16916                            |selections| {
16917                                selections.clear_disjoint();
16918                                selections
16919                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16920                            },
16921                        );
16922                    }
16923                    editor.highlight_background::<Self>(
16924                        &ranges,
16925                        |theme| theme.colors().editor_highlighted_line_background,
16926                        cx,
16927                    );
16928                }
16929                MultibufferSelectionMode::All => {
16930                    editor.change_selections(
16931                        SelectionEffects::no_scroll(),
16932                        window,
16933                        cx,
16934                        |selections| {
16935                            selections.clear_disjoint();
16936                            selections.select_anchor_ranges(ranges);
16937                        },
16938                    );
16939                }
16940            }
16941            editor.register_buffers_with_language_servers(cx);
16942        });
16943
16944        let item = Box::new(editor);
16945        let item_id = item.item_id();
16946
16947        if split {
16948            let pane = workspace.adjacent_pane(window, cx);
16949            workspace.add_item(pane, item, None, true, true, window, cx);
16950        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16951            let (preview_item_id, preview_item_idx) =
16952                workspace.active_pane().read_with(cx, |pane, _| {
16953                    (pane.preview_item_id(), pane.preview_item_idx())
16954                });
16955
16956            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16957
16958            if let Some(preview_item_id) = preview_item_id {
16959                workspace.active_pane().update(cx, |pane, cx| {
16960                    pane.remove_item(preview_item_id, false, false, window, cx);
16961                });
16962            }
16963        } else {
16964            workspace.add_item_to_active_pane(item, None, true, window, cx);
16965        }
16966        workspace.active_pane().update(cx, |pane, cx| {
16967            pane.set_preview_item_id(Some(item_id), cx);
16968        });
16969    }
16970
16971    pub fn rename(
16972        &mut self,
16973        _: &Rename,
16974        window: &mut Window,
16975        cx: &mut Context<Self>,
16976    ) -> Option<Task<Result<()>>> {
16977        use language::ToOffset as _;
16978
16979        let provider = self.semantics_provider.clone()?;
16980        let selection = self.selections.newest_anchor().clone();
16981        let (cursor_buffer, cursor_buffer_position) = self
16982            .buffer
16983            .read(cx)
16984            .text_anchor_for_position(selection.head(), cx)?;
16985        let (tail_buffer, cursor_buffer_position_end) = self
16986            .buffer
16987            .read(cx)
16988            .text_anchor_for_position(selection.tail(), cx)?;
16989        if tail_buffer != cursor_buffer {
16990            return None;
16991        }
16992
16993        let snapshot = cursor_buffer.read(cx).snapshot();
16994        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16995        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16996        let prepare_rename = provider
16997            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16998            .unwrap_or_else(|| Task::ready(Ok(None)));
16999        drop(snapshot);
17000
17001        Some(cx.spawn_in(window, async move |this, cx| {
17002            let rename_range = if let Some(range) = prepare_rename.await? {
17003                Some(range)
17004            } else {
17005                this.update(cx, |this, cx| {
17006                    let buffer = this.buffer.read(cx).snapshot(cx);
17007                    let mut buffer_highlights = this
17008                        .document_highlights_for_position(selection.head(), &buffer)
17009                        .filter(|highlight| {
17010                            highlight.start.excerpt_id == selection.head().excerpt_id
17011                                && highlight.end.excerpt_id == selection.head().excerpt_id
17012                        });
17013                    buffer_highlights
17014                        .next()
17015                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17016                })?
17017            };
17018            if let Some(rename_range) = rename_range {
17019                this.update_in(cx, |this, window, cx| {
17020                    let snapshot = cursor_buffer.read(cx).snapshot();
17021                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17022                    let cursor_offset_in_rename_range =
17023                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17024                    let cursor_offset_in_rename_range_end =
17025                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17026
17027                    this.take_rename(false, window, cx);
17028                    let buffer = this.buffer.read(cx).read(cx);
17029                    let cursor_offset = selection.head().to_offset(&buffer);
17030                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17031                    let rename_end = rename_start + rename_buffer_range.len();
17032                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17033                    let mut old_highlight_id = None;
17034                    let old_name: Arc<str> = buffer
17035                        .chunks(rename_start..rename_end, true)
17036                        .map(|chunk| {
17037                            if old_highlight_id.is_none() {
17038                                old_highlight_id = chunk.syntax_highlight_id;
17039                            }
17040                            chunk.text
17041                        })
17042                        .collect::<String>()
17043                        .into();
17044
17045                    drop(buffer);
17046
17047                    // Position the selection in the rename editor so that it matches the current selection.
17048                    this.show_local_selections = false;
17049                    let rename_editor = cx.new(|cx| {
17050                        let mut editor = Editor::single_line(window, cx);
17051                        editor.buffer.update(cx, |buffer, cx| {
17052                            buffer.edit([(0..0, old_name.clone())], None, cx)
17053                        });
17054                        let rename_selection_range = match cursor_offset_in_rename_range
17055                            .cmp(&cursor_offset_in_rename_range_end)
17056                        {
17057                            Ordering::Equal => {
17058                                editor.select_all(&SelectAll, window, cx);
17059                                return editor;
17060                            }
17061                            Ordering::Less => {
17062                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17063                            }
17064                            Ordering::Greater => {
17065                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17066                            }
17067                        };
17068                        if rename_selection_range.end > old_name.len() {
17069                            editor.select_all(&SelectAll, window, cx);
17070                        } else {
17071                            editor.change_selections(Default::default(), window, cx, |s| {
17072                                s.select_ranges([rename_selection_range]);
17073                            });
17074                        }
17075                        editor
17076                    });
17077                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17078                        if e == &EditorEvent::Focused {
17079                            cx.emit(EditorEvent::FocusedIn)
17080                        }
17081                    })
17082                    .detach();
17083
17084                    let write_highlights =
17085                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17086                    let read_highlights =
17087                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17088                    let ranges = write_highlights
17089                        .iter()
17090                        .flat_map(|(_, ranges)| ranges.iter())
17091                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17092                        .cloned()
17093                        .collect();
17094
17095                    this.highlight_text::<Rename>(
17096                        ranges,
17097                        HighlightStyle {
17098                            fade_out: Some(0.6),
17099                            ..Default::default()
17100                        },
17101                        cx,
17102                    );
17103                    let rename_focus_handle = rename_editor.focus_handle(cx);
17104                    window.focus(&rename_focus_handle);
17105                    let block_id = this.insert_blocks(
17106                        [BlockProperties {
17107                            style: BlockStyle::Flex,
17108                            placement: BlockPlacement::Below(range.start),
17109                            height: Some(1),
17110                            render: Arc::new({
17111                                let rename_editor = rename_editor.clone();
17112                                move |cx: &mut BlockContext| {
17113                                    let mut text_style = cx.editor_style.text.clone();
17114                                    if let Some(highlight_style) = old_highlight_id
17115                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17116                                    {
17117                                        text_style = text_style.highlight(highlight_style);
17118                                    }
17119                                    div()
17120                                        .block_mouse_except_scroll()
17121                                        .pl(cx.anchor_x)
17122                                        .child(EditorElement::new(
17123                                            &rename_editor,
17124                                            EditorStyle {
17125                                                background: cx.theme().system().transparent,
17126                                                local_player: cx.editor_style.local_player,
17127                                                text: text_style,
17128                                                scrollbar_width: cx.editor_style.scrollbar_width,
17129                                                syntax: cx.editor_style.syntax.clone(),
17130                                                status: cx.editor_style.status.clone(),
17131                                                inlay_hints_style: HighlightStyle {
17132                                                    font_weight: Some(FontWeight::BOLD),
17133                                                    ..make_inlay_hints_style(cx.app)
17134                                                },
17135                                                edit_prediction_styles: make_suggestion_styles(
17136                                                    cx.app,
17137                                                ),
17138                                                ..EditorStyle::default()
17139                                            },
17140                                        ))
17141                                        .into_any_element()
17142                                }
17143                            }),
17144                            priority: 0,
17145                        }],
17146                        Some(Autoscroll::fit()),
17147                        cx,
17148                    )[0];
17149                    this.pending_rename = Some(RenameState {
17150                        range,
17151                        old_name,
17152                        editor: rename_editor,
17153                        block_id,
17154                    });
17155                })?;
17156            }
17157
17158            Ok(())
17159        }))
17160    }
17161
17162    pub fn confirm_rename(
17163        &mut self,
17164        _: &ConfirmRename,
17165        window: &mut Window,
17166        cx: &mut Context<Self>,
17167    ) -> Option<Task<Result<()>>> {
17168        let rename = self.take_rename(false, window, cx)?;
17169        let workspace = self.workspace()?.downgrade();
17170        let (buffer, start) = self
17171            .buffer
17172            .read(cx)
17173            .text_anchor_for_position(rename.range.start, cx)?;
17174        let (end_buffer, _) = self
17175            .buffer
17176            .read(cx)
17177            .text_anchor_for_position(rename.range.end, cx)?;
17178        if buffer != end_buffer {
17179            return None;
17180        }
17181
17182        let old_name = rename.old_name;
17183        let new_name = rename.editor.read(cx).text(cx);
17184
17185        let rename = self.semantics_provider.as_ref()?.perform_rename(
17186            &buffer,
17187            start,
17188            new_name.clone(),
17189            cx,
17190        )?;
17191
17192        Some(cx.spawn_in(window, async move |editor, cx| {
17193            let project_transaction = rename.await?;
17194            Self::open_project_transaction(
17195                &editor,
17196                workspace,
17197                project_transaction,
17198                format!("Rename: {}{}", old_name, new_name),
17199                cx,
17200            )
17201            .await?;
17202
17203            editor.update(cx, |editor, cx| {
17204                editor.refresh_document_highlights(cx);
17205            })?;
17206            Ok(())
17207        }))
17208    }
17209
17210    fn take_rename(
17211        &mut self,
17212        moving_cursor: bool,
17213        window: &mut Window,
17214        cx: &mut Context<Self>,
17215    ) -> Option<RenameState> {
17216        let rename = self.pending_rename.take()?;
17217        if rename.editor.focus_handle(cx).is_focused(window) {
17218            window.focus(&self.focus_handle);
17219        }
17220
17221        self.remove_blocks(
17222            [rename.block_id].into_iter().collect(),
17223            Some(Autoscroll::fit()),
17224            cx,
17225        );
17226        self.clear_highlights::<Rename>(cx);
17227        self.show_local_selections = true;
17228
17229        if moving_cursor {
17230            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17231                editor.selections.newest::<usize>(cx).head()
17232            });
17233
17234            // Update the selection to match the position of the selection inside
17235            // the rename editor.
17236            let snapshot = self.buffer.read(cx).read(cx);
17237            let rename_range = rename.range.to_offset(&snapshot);
17238            let cursor_in_editor = snapshot
17239                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17240                .min(rename_range.end);
17241            drop(snapshot);
17242
17243            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17244                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17245            });
17246        } else {
17247            self.refresh_document_highlights(cx);
17248        }
17249
17250        Some(rename)
17251    }
17252
17253    pub fn pending_rename(&self) -> Option<&RenameState> {
17254        self.pending_rename.as_ref()
17255    }
17256
17257    fn format(
17258        &mut self,
17259        _: &Format,
17260        window: &mut Window,
17261        cx: &mut Context<Self>,
17262    ) -> Option<Task<Result<()>>> {
17263        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17264
17265        let project = match &self.project {
17266            Some(project) => project.clone(),
17267            None => return None,
17268        };
17269
17270        Some(self.perform_format(
17271            project,
17272            FormatTrigger::Manual,
17273            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17274            window,
17275            cx,
17276        ))
17277    }
17278
17279    fn format_selections(
17280        &mut self,
17281        _: &FormatSelections,
17282        window: &mut Window,
17283        cx: &mut Context<Self>,
17284    ) -> Option<Task<Result<()>>> {
17285        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17286
17287        let project = match &self.project {
17288            Some(project) => project.clone(),
17289            None => return None,
17290        };
17291
17292        let ranges = self
17293            .selections
17294            .all_adjusted(cx)
17295            .into_iter()
17296            .map(|selection| selection.range())
17297            .collect_vec();
17298
17299        Some(self.perform_format(
17300            project,
17301            FormatTrigger::Manual,
17302            FormatTarget::Ranges(ranges),
17303            window,
17304            cx,
17305        ))
17306    }
17307
17308    fn perform_format(
17309        &mut self,
17310        project: Entity<Project>,
17311        trigger: FormatTrigger,
17312        target: FormatTarget,
17313        window: &mut Window,
17314        cx: &mut Context<Self>,
17315    ) -> Task<Result<()>> {
17316        let buffer = self.buffer.clone();
17317        let (buffers, target) = match target {
17318            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17319            FormatTarget::Ranges(selection_ranges) => {
17320                let multi_buffer = buffer.read(cx);
17321                let snapshot = multi_buffer.read(cx);
17322                let mut buffers = HashSet::default();
17323                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17324                    BTreeMap::new();
17325                for selection_range in selection_ranges {
17326                    for (buffer, buffer_range, _) in
17327                        snapshot.range_to_buffer_ranges(selection_range)
17328                    {
17329                        let buffer_id = buffer.remote_id();
17330                        let start = buffer.anchor_before(buffer_range.start);
17331                        let end = buffer.anchor_after(buffer_range.end);
17332                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17333                        buffer_id_to_ranges
17334                            .entry(buffer_id)
17335                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17336                            .or_insert_with(|| vec![start..end]);
17337                    }
17338                }
17339                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17340            }
17341        };
17342
17343        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17344        let selections_prev = transaction_id_prev
17345            .and_then(|transaction_id_prev| {
17346                // default to selections as they were after the last edit, if we have them,
17347                // instead of how they are now.
17348                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17349                // will take you back to where you made the last edit, instead of staying where you scrolled
17350                self.selection_history
17351                    .transaction(transaction_id_prev)
17352                    .map(|t| t.0.clone())
17353            })
17354            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17355
17356        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17357        let format = project.update(cx, |project, cx| {
17358            project.format(buffers, target, true, trigger, cx)
17359        });
17360
17361        cx.spawn_in(window, async move |editor, cx| {
17362            let transaction = futures::select_biased! {
17363                transaction = format.log_err().fuse() => transaction,
17364                () = timeout => {
17365                    log::warn!("timed out waiting for formatting");
17366                    None
17367                }
17368            };
17369
17370            buffer
17371                .update(cx, |buffer, cx| {
17372                    if let Some(transaction) = transaction
17373                        && !buffer.is_singleton()
17374                    {
17375                        buffer.push_transaction(&transaction.0, cx);
17376                    }
17377                    cx.notify();
17378                })
17379                .ok();
17380
17381            if let Some(transaction_id_now) =
17382                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17383            {
17384                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17385                if has_new_transaction {
17386                    _ = editor.update(cx, |editor, _| {
17387                        editor
17388                            .selection_history
17389                            .insert_transaction(transaction_id_now, selections_prev);
17390                    });
17391                }
17392            }
17393
17394            Ok(())
17395        })
17396    }
17397
17398    fn organize_imports(
17399        &mut self,
17400        _: &OrganizeImports,
17401        window: &mut Window,
17402        cx: &mut Context<Self>,
17403    ) -> Option<Task<Result<()>>> {
17404        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17405        let project = match &self.project {
17406            Some(project) => project.clone(),
17407            None => return None,
17408        };
17409        Some(self.perform_code_action_kind(
17410            project,
17411            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17412            window,
17413            cx,
17414        ))
17415    }
17416
17417    fn perform_code_action_kind(
17418        &mut self,
17419        project: Entity<Project>,
17420        kind: CodeActionKind,
17421        window: &mut Window,
17422        cx: &mut Context<Self>,
17423    ) -> Task<Result<()>> {
17424        let buffer = self.buffer.clone();
17425        let buffers = buffer.read(cx).all_buffers();
17426        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17427        let apply_action = project.update(cx, |project, cx| {
17428            project.apply_code_action_kind(buffers, kind, true, cx)
17429        });
17430        cx.spawn_in(window, async move |_, cx| {
17431            let transaction = futures::select_biased! {
17432                () = timeout => {
17433                    log::warn!("timed out waiting for executing code action");
17434                    None
17435                }
17436                transaction = apply_action.log_err().fuse() => transaction,
17437            };
17438            buffer
17439                .update(cx, |buffer, cx| {
17440                    // check if we need this
17441                    if let Some(transaction) = transaction
17442                        && !buffer.is_singleton()
17443                    {
17444                        buffer.push_transaction(&transaction.0, cx);
17445                    }
17446                    cx.notify();
17447                })
17448                .ok();
17449            Ok(())
17450        })
17451    }
17452
17453    pub fn restart_language_server(
17454        &mut self,
17455        _: &RestartLanguageServer,
17456        _: &mut Window,
17457        cx: &mut Context<Self>,
17458    ) {
17459        if let Some(project) = self.project.clone() {
17460            self.buffer.update(cx, |multi_buffer, cx| {
17461                project.update(cx, |project, cx| {
17462                    project.restart_language_servers_for_buffers(
17463                        multi_buffer.all_buffers().into_iter().collect(),
17464                        HashSet::default(),
17465                        cx,
17466                    );
17467                });
17468            })
17469        }
17470    }
17471
17472    pub fn stop_language_server(
17473        &mut self,
17474        _: &StopLanguageServer,
17475        _: &mut Window,
17476        cx: &mut Context<Self>,
17477    ) {
17478        if let Some(project) = self.project.clone() {
17479            self.buffer.update(cx, |multi_buffer, cx| {
17480                project.update(cx, |project, cx| {
17481                    project.stop_language_servers_for_buffers(
17482                        multi_buffer.all_buffers().into_iter().collect(),
17483                        HashSet::default(),
17484                        cx,
17485                    );
17486                    cx.emit(project::Event::RefreshInlayHints);
17487                });
17488            });
17489        }
17490    }
17491
17492    fn cancel_language_server_work(
17493        workspace: &mut Workspace,
17494        _: &actions::CancelLanguageServerWork,
17495        _: &mut Window,
17496        cx: &mut Context<Workspace>,
17497    ) {
17498        let project = workspace.project();
17499        let buffers = workspace
17500            .active_item(cx)
17501            .and_then(|item| item.act_as::<Editor>(cx))
17502            .map_or(HashSet::default(), |editor| {
17503                editor.read(cx).buffer.read(cx).all_buffers()
17504            });
17505        project.update(cx, |project, cx| {
17506            project.cancel_language_server_work_for_buffers(buffers, cx);
17507        });
17508    }
17509
17510    fn show_character_palette(
17511        &mut self,
17512        _: &ShowCharacterPalette,
17513        window: &mut Window,
17514        _: &mut Context<Self>,
17515    ) {
17516        window.show_character_palette();
17517    }
17518
17519    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17520        if !self.diagnostics_enabled() {
17521            return;
17522        }
17523
17524        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17525            let buffer = self.buffer.read(cx).snapshot(cx);
17526            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17527            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17528            let is_valid = buffer
17529                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17530                .any(|entry| {
17531                    entry.diagnostic.is_primary
17532                        && !entry.range.is_empty()
17533                        && entry.range.start == primary_range_start
17534                        && entry.diagnostic.message == active_diagnostics.active_message
17535                });
17536
17537            if !is_valid {
17538                self.dismiss_diagnostics(cx);
17539            }
17540        }
17541    }
17542
17543    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17544        match &self.active_diagnostics {
17545            ActiveDiagnostic::Group(group) => Some(group),
17546            _ => None,
17547        }
17548    }
17549
17550    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17551        if !self.diagnostics_enabled() {
17552            return;
17553        }
17554        self.dismiss_diagnostics(cx);
17555        self.active_diagnostics = ActiveDiagnostic::All;
17556    }
17557
17558    fn activate_diagnostics(
17559        &mut self,
17560        buffer_id: BufferId,
17561        diagnostic: DiagnosticEntryRef<'_, usize>,
17562        window: &mut Window,
17563        cx: &mut Context<Self>,
17564    ) {
17565        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17566            return;
17567        }
17568        self.dismiss_diagnostics(cx);
17569        let snapshot = self.snapshot(window, cx);
17570        let buffer = self.buffer.read(cx).snapshot(cx);
17571        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17572            return;
17573        };
17574
17575        let diagnostic_group = buffer
17576            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17577            .collect::<Vec<_>>();
17578
17579        let blocks =
17580            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17581
17582        let blocks = self.display_map.update(cx, |display_map, cx| {
17583            display_map.insert_blocks(blocks, cx).into_iter().collect()
17584        });
17585        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17586            active_range: buffer.anchor_before(diagnostic.range.start)
17587                ..buffer.anchor_after(diagnostic.range.end),
17588            active_message: diagnostic.diagnostic.message.clone(),
17589            group_id: diagnostic.diagnostic.group_id,
17590            blocks,
17591        });
17592        cx.notify();
17593    }
17594
17595    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17596        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17597            return;
17598        };
17599
17600        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17601        if let ActiveDiagnostic::Group(group) = prev {
17602            self.display_map.update(cx, |display_map, cx| {
17603                display_map.remove_blocks(group.blocks, cx);
17604            });
17605            cx.notify();
17606        }
17607    }
17608
17609    /// Disable inline diagnostics rendering for this editor.
17610    pub fn disable_inline_diagnostics(&mut self) {
17611        self.inline_diagnostics_enabled = false;
17612        self.inline_diagnostics_update = Task::ready(());
17613        self.inline_diagnostics.clear();
17614    }
17615
17616    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17617        self.diagnostics_enabled = false;
17618        self.dismiss_diagnostics(cx);
17619        self.inline_diagnostics_update = Task::ready(());
17620        self.inline_diagnostics.clear();
17621    }
17622
17623    pub fn disable_word_completions(&mut self) {
17624        self.word_completions_enabled = false;
17625    }
17626
17627    pub fn diagnostics_enabled(&self) -> bool {
17628        self.diagnostics_enabled && self.mode.is_full()
17629    }
17630
17631    pub fn inline_diagnostics_enabled(&self) -> bool {
17632        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17633    }
17634
17635    pub fn show_inline_diagnostics(&self) -> bool {
17636        self.show_inline_diagnostics
17637    }
17638
17639    pub fn toggle_inline_diagnostics(
17640        &mut self,
17641        _: &ToggleInlineDiagnostics,
17642        window: &mut Window,
17643        cx: &mut Context<Editor>,
17644    ) {
17645        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17646        self.refresh_inline_diagnostics(false, window, cx);
17647    }
17648
17649    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17650        self.diagnostics_max_severity = severity;
17651        self.display_map.update(cx, |display_map, _| {
17652            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17653        });
17654    }
17655
17656    pub fn toggle_diagnostics(
17657        &mut self,
17658        _: &ToggleDiagnostics,
17659        window: &mut Window,
17660        cx: &mut Context<Editor>,
17661    ) {
17662        if !self.diagnostics_enabled() {
17663            return;
17664        }
17665
17666        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17667            EditorSettings::get_global(cx)
17668                .diagnostics_max_severity
17669                .filter(|severity| severity != &DiagnosticSeverity::Off)
17670                .unwrap_or(DiagnosticSeverity::Hint)
17671        } else {
17672            DiagnosticSeverity::Off
17673        };
17674        self.set_max_diagnostics_severity(new_severity, cx);
17675        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17676            self.active_diagnostics = ActiveDiagnostic::None;
17677            self.inline_diagnostics_update = Task::ready(());
17678            self.inline_diagnostics.clear();
17679        } else {
17680            self.refresh_inline_diagnostics(false, window, cx);
17681        }
17682
17683        cx.notify();
17684    }
17685
17686    pub fn toggle_minimap(
17687        &mut self,
17688        _: &ToggleMinimap,
17689        window: &mut Window,
17690        cx: &mut Context<Editor>,
17691    ) {
17692        if self.supports_minimap(cx) {
17693            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17694        }
17695    }
17696
17697    fn refresh_inline_diagnostics(
17698        &mut self,
17699        debounce: bool,
17700        window: &mut Window,
17701        cx: &mut Context<Self>,
17702    ) {
17703        let max_severity = ProjectSettings::get_global(cx)
17704            .diagnostics
17705            .inline
17706            .max_severity
17707            .unwrap_or(self.diagnostics_max_severity);
17708
17709        if !self.inline_diagnostics_enabled()
17710            || !self.show_inline_diagnostics
17711            || max_severity == DiagnosticSeverity::Off
17712        {
17713            self.inline_diagnostics_update = Task::ready(());
17714            self.inline_diagnostics.clear();
17715            return;
17716        }
17717
17718        let debounce_ms = ProjectSettings::get_global(cx)
17719            .diagnostics
17720            .inline
17721            .update_debounce_ms;
17722        let debounce = if debounce && debounce_ms > 0 {
17723            Some(Duration::from_millis(debounce_ms))
17724        } else {
17725            None
17726        };
17727        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17728            if let Some(debounce) = debounce {
17729                cx.background_executor().timer(debounce).await;
17730            }
17731            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17732                editor
17733                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17734                    .ok()
17735            }) else {
17736                return;
17737            };
17738
17739            let new_inline_diagnostics = cx
17740                .background_spawn(async move {
17741                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17742                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17743                        let message = diagnostic_entry
17744                            .diagnostic
17745                            .message
17746                            .split_once('\n')
17747                            .map(|(line, _)| line)
17748                            .map(SharedString::new)
17749                            .unwrap_or_else(|| {
17750                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17751                            });
17752                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17753                        let (Ok(i) | Err(i)) = inline_diagnostics
17754                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17755                        inline_diagnostics.insert(
17756                            i,
17757                            (
17758                                start_anchor,
17759                                InlineDiagnostic {
17760                                    message,
17761                                    group_id: diagnostic_entry.diagnostic.group_id,
17762                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17763                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17764                                    severity: diagnostic_entry.diagnostic.severity,
17765                                },
17766                            ),
17767                        );
17768                    }
17769                    inline_diagnostics
17770                })
17771                .await;
17772
17773            editor
17774                .update(cx, |editor, cx| {
17775                    editor.inline_diagnostics = new_inline_diagnostics;
17776                    cx.notify();
17777                })
17778                .ok();
17779        });
17780    }
17781
17782    fn pull_diagnostics(
17783        &mut self,
17784        buffer_id: Option<BufferId>,
17785        window: &Window,
17786        cx: &mut Context<Self>,
17787    ) -> Option<()> {
17788        if !self.mode().is_full() {
17789            return None;
17790        }
17791        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17792            .diagnostics
17793            .lsp_pull_diagnostics;
17794        if !pull_diagnostics_settings.enabled {
17795            return None;
17796        }
17797        let project = self.project()?.downgrade();
17798        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17799        let mut buffers = self.buffer.read(cx).all_buffers();
17800        if let Some(buffer_id) = buffer_id {
17801            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17802        }
17803
17804        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17805            cx.background_executor().timer(debounce).await;
17806
17807            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17808                buffers
17809                    .into_iter()
17810                    .filter_map(|buffer| {
17811                        project
17812                            .update(cx, |project, cx| {
17813                                project.lsp_store().update(cx, |lsp_store, cx| {
17814                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17815                                })
17816                            })
17817                            .ok()
17818                    })
17819                    .collect::<FuturesUnordered<_>>()
17820            }) else {
17821                return;
17822            };
17823
17824            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17825                match pull_task {
17826                    Ok(()) => {
17827                        if editor
17828                            .update_in(cx, |editor, window, cx| {
17829                                editor.update_diagnostics_state(window, cx);
17830                            })
17831                            .is_err()
17832                        {
17833                            return;
17834                        }
17835                    }
17836                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17837                }
17838            }
17839        });
17840
17841        Some(())
17842    }
17843
17844    pub fn set_selections_from_remote(
17845        &mut self,
17846        selections: Vec<Selection<Anchor>>,
17847        pending_selection: Option<Selection<Anchor>>,
17848        window: &mut Window,
17849        cx: &mut Context<Self>,
17850    ) {
17851        let old_cursor_position = self.selections.newest_anchor().head();
17852        self.selections.change_with(cx, |s| {
17853            s.select_anchors(selections);
17854            if let Some(pending_selection) = pending_selection {
17855                s.set_pending(pending_selection, SelectMode::Character);
17856            } else {
17857                s.clear_pending();
17858            }
17859        });
17860        self.selections_did_change(
17861            false,
17862            &old_cursor_position,
17863            SelectionEffects::default(),
17864            window,
17865            cx,
17866        );
17867    }
17868
17869    pub fn transact(
17870        &mut self,
17871        window: &mut Window,
17872        cx: &mut Context<Self>,
17873        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17874    ) -> Option<TransactionId> {
17875        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17876            this.start_transaction_at(Instant::now(), window, cx);
17877            update(this, window, cx);
17878            this.end_transaction_at(Instant::now(), cx)
17879        })
17880    }
17881
17882    pub fn start_transaction_at(
17883        &mut self,
17884        now: Instant,
17885        window: &mut Window,
17886        cx: &mut Context<Self>,
17887    ) -> Option<TransactionId> {
17888        self.end_selection(window, cx);
17889        if let Some(tx_id) = self
17890            .buffer
17891            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17892        {
17893            self.selection_history
17894                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17895            cx.emit(EditorEvent::TransactionBegun {
17896                transaction_id: tx_id,
17897            });
17898            Some(tx_id)
17899        } else {
17900            None
17901        }
17902    }
17903
17904    pub fn end_transaction_at(
17905        &mut self,
17906        now: Instant,
17907        cx: &mut Context<Self>,
17908    ) -> Option<TransactionId> {
17909        if let Some(transaction_id) = self
17910            .buffer
17911            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17912        {
17913            if let Some((_, end_selections)) =
17914                self.selection_history.transaction_mut(transaction_id)
17915            {
17916                *end_selections = Some(self.selections.disjoint_anchors_arc());
17917            } else {
17918                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17919            }
17920
17921            cx.emit(EditorEvent::Edited { transaction_id });
17922            Some(transaction_id)
17923        } else {
17924            None
17925        }
17926    }
17927
17928    pub fn modify_transaction_selection_history(
17929        &mut self,
17930        transaction_id: TransactionId,
17931        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17932    ) -> bool {
17933        self.selection_history
17934            .transaction_mut(transaction_id)
17935            .map(modify)
17936            .is_some()
17937    }
17938
17939    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17940        if self.selection_mark_mode {
17941            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17942                s.move_with(|_, sel| {
17943                    sel.collapse_to(sel.head(), SelectionGoal::None);
17944                });
17945            })
17946        }
17947        self.selection_mark_mode = true;
17948        cx.notify();
17949    }
17950
17951    pub fn swap_selection_ends(
17952        &mut self,
17953        _: &actions::SwapSelectionEnds,
17954        window: &mut Window,
17955        cx: &mut Context<Self>,
17956    ) {
17957        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17958            s.move_with(|_, sel| {
17959                if sel.start != sel.end {
17960                    sel.reversed = !sel.reversed
17961                }
17962            });
17963        });
17964        self.request_autoscroll(Autoscroll::newest(), cx);
17965        cx.notify();
17966    }
17967
17968    pub fn toggle_focus(
17969        workspace: &mut Workspace,
17970        _: &actions::ToggleFocus,
17971        window: &mut Window,
17972        cx: &mut Context<Workspace>,
17973    ) {
17974        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17975            return;
17976        };
17977        workspace.activate_item(&item, true, true, window, cx);
17978    }
17979
17980    pub fn toggle_fold(
17981        &mut self,
17982        _: &actions::ToggleFold,
17983        window: &mut Window,
17984        cx: &mut Context<Self>,
17985    ) {
17986        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
17987            let selection = self.selections.newest::<Point>(cx);
17988
17989            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17990            let range = if selection.is_empty() {
17991                let point = selection.head().to_display_point(&display_map);
17992                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17993                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17994                    .to_point(&display_map);
17995                start..end
17996            } else {
17997                selection.range()
17998            };
17999            if display_map.folds_in_range(range).next().is_some() {
18000                self.unfold_lines(&Default::default(), window, cx)
18001            } else {
18002                self.fold(&Default::default(), window, cx)
18003            }
18004        } else {
18005            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18006            let buffer_ids: HashSet<_> = self
18007                .selections
18008                .disjoint_anchor_ranges()
18009                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18010                .collect();
18011
18012            let should_unfold = buffer_ids
18013                .iter()
18014                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18015
18016            for buffer_id in buffer_ids {
18017                if should_unfold {
18018                    self.unfold_buffer(buffer_id, cx);
18019                } else {
18020                    self.fold_buffer(buffer_id, cx);
18021                }
18022            }
18023        }
18024    }
18025
18026    pub fn toggle_fold_recursive(
18027        &mut self,
18028        _: &actions::ToggleFoldRecursive,
18029        window: &mut Window,
18030        cx: &mut Context<Self>,
18031    ) {
18032        let selection = self.selections.newest::<Point>(cx);
18033
18034        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18035        let range = if selection.is_empty() {
18036            let point = selection.head().to_display_point(&display_map);
18037            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18038            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18039                .to_point(&display_map);
18040            start..end
18041        } else {
18042            selection.range()
18043        };
18044        if display_map.folds_in_range(range).next().is_some() {
18045            self.unfold_recursive(&Default::default(), window, cx)
18046        } else {
18047            self.fold_recursive(&Default::default(), window, cx)
18048        }
18049    }
18050
18051    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18052        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18053            let mut to_fold = Vec::new();
18054            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18055            let selections = self.selections.all_adjusted(cx);
18056
18057            for selection in selections {
18058                let range = selection.range().sorted();
18059                let buffer_start_row = range.start.row;
18060
18061                if range.start.row != range.end.row {
18062                    let mut found = false;
18063                    let mut row = range.start.row;
18064                    while row <= range.end.row {
18065                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18066                        {
18067                            found = true;
18068                            row = crease.range().end.row + 1;
18069                            to_fold.push(crease);
18070                        } else {
18071                            row += 1
18072                        }
18073                    }
18074                    if found {
18075                        continue;
18076                    }
18077                }
18078
18079                for row in (0..=range.start.row).rev() {
18080                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18081                        && crease.range().end.row >= buffer_start_row
18082                    {
18083                        to_fold.push(crease);
18084                        if row <= range.start.row {
18085                            break;
18086                        }
18087                    }
18088                }
18089            }
18090
18091            self.fold_creases(to_fold, true, window, cx);
18092        } else {
18093            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18094            let buffer_ids = self
18095                .selections
18096                .disjoint_anchor_ranges()
18097                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18098                .collect::<HashSet<_>>();
18099            for buffer_id in buffer_ids {
18100                self.fold_buffer(buffer_id, cx);
18101            }
18102        }
18103    }
18104
18105    pub fn toggle_fold_all(
18106        &mut self,
18107        _: &actions::ToggleFoldAll,
18108        window: &mut Window,
18109        cx: &mut Context<Self>,
18110    ) {
18111        if self.buffer.read(cx).is_singleton() {
18112            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18113            let has_folds = display_map
18114                .folds_in_range(0..display_map.buffer_snapshot().len())
18115                .next()
18116                .is_some();
18117
18118            if has_folds {
18119                self.unfold_all(&actions::UnfoldAll, window, cx);
18120            } else {
18121                self.fold_all(&actions::FoldAll, window, cx);
18122            }
18123        } else {
18124            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18125            let should_unfold = buffer_ids
18126                .iter()
18127                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18128
18129            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18130                editor
18131                    .update_in(cx, |editor, _, cx| {
18132                        for buffer_id in buffer_ids {
18133                            if should_unfold {
18134                                editor.unfold_buffer(buffer_id, cx);
18135                            } else {
18136                                editor.fold_buffer(buffer_id, cx);
18137                            }
18138                        }
18139                    })
18140                    .ok();
18141            });
18142        }
18143    }
18144
18145    fn fold_at_level(
18146        &mut self,
18147        fold_at: &FoldAtLevel,
18148        window: &mut Window,
18149        cx: &mut Context<Self>,
18150    ) {
18151        if !self.buffer.read(cx).is_singleton() {
18152            return;
18153        }
18154
18155        let fold_at_level = fold_at.0;
18156        let snapshot = self.buffer.read(cx).snapshot(cx);
18157        let mut to_fold = Vec::new();
18158        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18159
18160        let row_ranges_to_keep: Vec<Range<u32>> = self
18161            .selections
18162            .all::<Point>(cx)
18163            .into_iter()
18164            .map(|sel| sel.start.row..sel.end.row)
18165            .collect();
18166
18167        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18168            while start_row < end_row {
18169                match self
18170                    .snapshot(window, cx)
18171                    .crease_for_buffer_row(MultiBufferRow(start_row))
18172                {
18173                    Some(crease) => {
18174                        let nested_start_row = crease.range().start.row + 1;
18175                        let nested_end_row = crease.range().end.row;
18176
18177                        if current_level < fold_at_level {
18178                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18179                        } else if current_level == fold_at_level {
18180                            // Fold iff there is no selection completely contained within the fold region
18181                            if !row_ranges_to_keep.iter().any(|selection| {
18182                                selection.end >= nested_start_row
18183                                    && selection.start <= nested_end_row
18184                            }) {
18185                                to_fold.push(crease);
18186                            }
18187                        }
18188
18189                        start_row = nested_end_row + 1;
18190                    }
18191                    None => start_row += 1,
18192                }
18193            }
18194        }
18195
18196        self.fold_creases(to_fold, true, window, cx);
18197    }
18198
18199    pub fn fold_at_level_1(
18200        &mut self,
18201        _: &actions::FoldAtLevel1,
18202        window: &mut Window,
18203        cx: &mut Context<Self>,
18204    ) {
18205        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18206    }
18207
18208    pub fn fold_at_level_2(
18209        &mut self,
18210        _: &actions::FoldAtLevel2,
18211        window: &mut Window,
18212        cx: &mut Context<Self>,
18213    ) {
18214        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18215    }
18216
18217    pub fn fold_at_level_3(
18218        &mut self,
18219        _: &actions::FoldAtLevel3,
18220        window: &mut Window,
18221        cx: &mut Context<Self>,
18222    ) {
18223        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18224    }
18225
18226    pub fn fold_at_level_4(
18227        &mut self,
18228        _: &actions::FoldAtLevel4,
18229        window: &mut Window,
18230        cx: &mut Context<Self>,
18231    ) {
18232        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18233    }
18234
18235    pub fn fold_at_level_5(
18236        &mut self,
18237        _: &actions::FoldAtLevel5,
18238        window: &mut Window,
18239        cx: &mut Context<Self>,
18240    ) {
18241        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18242    }
18243
18244    pub fn fold_at_level_6(
18245        &mut self,
18246        _: &actions::FoldAtLevel6,
18247        window: &mut Window,
18248        cx: &mut Context<Self>,
18249    ) {
18250        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18251    }
18252
18253    pub fn fold_at_level_7(
18254        &mut self,
18255        _: &actions::FoldAtLevel7,
18256        window: &mut Window,
18257        cx: &mut Context<Self>,
18258    ) {
18259        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18260    }
18261
18262    pub fn fold_at_level_8(
18263        &mut self,
18264        _: &actions::FoldAtLevel8,
18265        window: &mut Window,
18266        cx: &mut Context<Self>,
18267    ) {
18268        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18269    }
18270
18271    pub fn fold_at_level_9(
18272        &mut self,
18273        _: &actions::FoldAtLevel9,
18274        window: &mut Window,
18275        cx: &mut Context<Self>,
18276    ) {
18277        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18278    }
18279
18280    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18281        if self.buffer.read(cx).is_singleton() {
18282            let mut fold_ranges = Vec::new();
18283            let snapshot = self.buffer.read(cx).snapshot(cx);
18284
18285            for row in 0..snapshot.max_row().0 {
18286                if let Some(foldable_range) = self
18287                    .snapshot(window, cx)
18288                    .crease_for_buffer_row(MultiBufferRow(row))
18289                {
18290                    fold_ranges.push(foldable_range);
18291                }
18292            }
18293
18294            self.fold_creases(fold_ranges, true, window, cx);
18295        } else {
18296            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18297                editor
18298                    .update_in(cx, |editor, _, cx| {
18299                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18300                            editor.fold_buffer(buffer_id, cx);
18301                        }
18302                    })
18303                    .ok();
18304            });
18305        }
18306    }
18307
18308    pub fn fold_function_bodies(
18309        &mut self,
18310        _: &actions::FoldFunctionBodies,
18311        window: &mut Window,
18312        cx: &mut Context<Self>,
18313    ) {
18314        let snapshot = self.buffer.read(cx).snapshot(cx);
18315
18316        let ranges = snapshot
18317            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18318            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18319            .collect::<Vec<_>>();
18320
18321        let creases = ranges
18322            .into_iter()
18323            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18324            .collect();
18325
18326        self.fold_creases(creases, true, window, cx);
18327    }
18328
18329    pub fn fold_recursive(
18330        &mut self,
18331        _: &actions::FoldRecursive,
18332        window: &mut Window,
18333        cx: &mut Context<Self>,
18334    ) {
18335        let mut to_fold = Vec::new();
18336        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18337        let selections = self.selections.all_adjusted(cx);
18338
18339        for selection in selections {
18340            let range = selection.range().sorted();
18341            let buffer_start_row = range.start.row;
18342
18343            if range.start.row != range.end.row {
18344                let mut found = false;
18345                for row in range.start.row..=range.end.row {
18346                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18347                        found = true;
18348                        to_fold.push(crease);
18349                    }
18350                }
18351                if found {
18352                    continue;
18353                }
18354            }
18355
18356            for row in (0..=range.start.row).rev() {
18357                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18358                    if crease.range().end.row >= buffer_start_row {
18359                        to_fold.push(crease);
18360                    } else {
18361                        break;
18362                    }
18363                }
18364            }
18365        }
18366
18367        self.fold_creases(to_fold, true, window, cx);
18368    }
18369
18370    pub fn fold_at(
18371        &mut self,
18372        buffer_row: MultiBufferRow,
18373        window: &mut Window,
18374        cx: &mut Context<Self>,
18375    ) {
18376        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18377
18378        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18379            let autoscroll = self
18380                .selections
18381                .all::<Point>(cx)
18382                .iter()
18383                .any(|selection| crease.range().overlaps(&selection.range()));
18384
18385            self.fold_creases(vec![crease], autoscroll, window, cx);
18386        }
18387    }
18388
18389    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18390        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18391            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18392            let buffer = display_map.buffer_snapshot();
18393            let selections = self.selections.all::<Point>(cx);
18394            let ranges = selections
18395                .iter()
18396                .map(|s| {
18397                    let range = s.display_range(&display_map).sorted();
18398                    let mut start = range.start.to_point(&display_map);
18399                    let mut end = range.end.to_point(&display_map);
18400                    start.column = 0;
18401                    end.column = buffer.line_len(MultiBufferRow(end.row));
18402                    start..end
18403                })
18404                .collect::<Vec<_>>();
18405
18406            self.unfold_ranges(&ranges, true, true, cx);
18407        } else {
18408            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18409            let buffer_ids = self
18410                .selections
18411                .disjoint_anchor_ranges()
18412                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18413                .collect::<HashSet<_>>();
18414            for buffer_id in buffer_ids {
18415                self.unfold_buffer(buffer_id, cx);
18416            }
18417        }
18418    }
18419
18420    pub fn unfold_recursive(
18421        &mut self,
18422        _: &UnfoldRecursive,
18423        _window: &mut Window,
18424        cx: &mut Context<Self>,
18425    ) {
18426        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18427        let selections = self.selections.all::<Point>(cx);
18428        let ranges = selections
18429            .iter()
18430            .map(|s| {
18431                let mut range = s.display_range(&display_map).sorted();
18432                *range.start.column_mut() = 0;
18433                *range.end.column_mut() = display_map.line_len(range.end.row());
18434                let start = range.start.to_point(&display_map);
18435                let end = range.end.to_point(&display_map);
18436                start..end
18437            })
18438            .collect::<Vec<_>>();
18439
18440        self.unfold_ranges(&ranges, true, true, cx);
18441    }
18442
18443    pub fn unfold_at(
18444        &mut self,
18445        buffer_row: MultiBufferRow,
18446        _window: &mut Window,
18447        cx: &mut Context<Self>,
18448    ) {
18449        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18450
18451        let intersection_range = Point::new(buffer_row.0, 0)
18452            ..Point::new(
18453                buffer_row.0,
18454                display_map.buffer_snapshot().line_len(buffer_row),
18455            );
18456
18457        let autoscroll = self
18458            .selections
18459            .all::<Point>(cx)
18460            .iter()
18461            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18462
18463        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18464    }
18465
18466    pub fn unfold_all(
18467        &mut self,
18468        _: &actions::UnfoldAll,
18469        _window: &mut Window,
18470        cx: &mut Context<Self>,
18471    ) {
18472        if self.buffer.read(cx).is_singleton() {
18473            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18474            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18475        } else {
18476            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18477                editor
18478                    .update(cx, |editor, cx| {
18479                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18480                            editor.unfold_buffer(buffer_id, cx);
18481                        }
18482                    })
18483                    .ok();
18484            });
18485        }
18486    }
18487
18488    pub fn fold_selected_ranges(
18489        &mut self,
18490        _: &FoldSelectedRanges,
18491        window: &mut Window,
18492        cx: &mut Context<Self>,
18493    ) {
18494        let selections = self.selections.all_adjusted(cx);
18495        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18496        let ranges = selections
18497            .into_iter()
18498            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18499            .collect::<Vec<_>>();
18500        self.fold_creases(ranges, true, window, cx);
18501    }
18502
18503    pub fn fold_ranges<T: ToOffset + Clone>(
18504        &mut self,
18505        ranges: Vec<Range<T>>,
18506        auto_scroll: bool,
18507        window: &mut Window,
18508        cx: &mut Context<Self>,
18509    ) {
18510        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18511        let ranges = ranges
18512            .into_iter()
18513            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18514            .collect::<Vec<_>>();
18515        self.fold_creases(ranges, auto_scroll, window, cx);
18516    }
18517
18518    pub fn fold_creases<T: ToOffset + Clone>(
18519        &mut self,
18520        creases: Vec<Crease<T>>,
18521        auto_scroll: bool,
18522        _window: &mut Window,
18523        cx: &mut Context<Self>,
18524    ) {
18525        if creases.is_empty() {
18526            return;
18527        }
18528
18529        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18530
18531        if auto_scroll {
18532            self.request_autoscroll(Autoscroll::fit(), cx);
18533        }
18534
18535        cx.notify();
18536
18537        self.scrollbar_marker_state.dirty = true;
18538        self.folds_did_change(cx);
18539    }
18540
18541    /// Removes any folds whose ranges intersect any of the given ranges.
18542    pub fn unfold_ranges<T: ToOffset + Clone>(
18543        &mut self,
18544        ranges: &[Range<T>],
18545        inclusive: bool,
18546        auto_scroll: bool,
18547        cx: &mut Context<Self>,
18548    ) {
18549        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18550            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18551        });
18552        self.folds_did_change(cx);
18553    }
18554
18555    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18556        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18557            return;
18558        }
18559        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18560        self.display_map.update(cx, |display_map, cx| {
18561            display_map.fold_buffers([buffer_id], cx)
18562        });
18563        cx.emit(EditorEvent::BufferFoldToggled {
18564            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18565            folded: true,
18566        });
18567        cx.notify();
18568    }
18569
18570    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18571        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18572            return;
18573        }
18574        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18575        self.display_map.update(cx, |display_map, cx| {
18576            display_map.unfold_buffers([buffer_id], cx);
18577        });
18578        cx.emit(EditorEvent::BufferFoldToggled {
18579            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18580            folded: false,
18581        });
18582        cx.notify();
18583    }
18584
18585    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18586        self.display_map.read(cx).is_buffer_folded(buffer)
18587    }
18588
18589    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18590        self.display_map.read(cx).folded_buffers()
18591    }
18592
18593    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18594        self.display_map.update(cx, |display_map, cx| {
18595            display_map.disable_header_for_buffer(buffer_id, cx);
18596        });
18597        cx.notify();
18598    }
18599
18600    /// Removes any folds with the given ranges.
18601    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18602        &mut self,
18603        ranges: &[Range<T>],
18604        type_id: TypeId,
18605        auto_scroll: bool,
18606        cx: &mut Context<Self>,
18607    ) {
18608        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18609            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18610        });
18611        self.folds_did_change(cx);
18612    }
18613
18614    fn remove_folds_with<T: ToOffset + Clone>(
18615        &mut self,
18616        ranges: &[Range<T>],
18617        auto_scroll: bool,
18618        cx: &mut Context<Self>,
18619        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18620    ) {
18621        if ranges.is_empty() {
18622            return;
18623        }
18624
18625        let mut buffers_affected = HashSet::default();
18626        let multi_buffer = self.buffer().read(cx);
18627        for range in ranges {
18628            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18629                buffers_affected.insert(buffer.read(cx).remote_id());
18630            };
18631        }
18632
18633        self.display_map.update(cx, update);
18634
18635        if auto_scroll {
18636            self.request_autoscroll(Autoscroll::fit(), cx);
18637        }
18638
18639        cx.notify();
18640        self.scrollbar_marker_state.dirty = true;
18641        self.active_indent_guides_state.dirty = true;
18642    }
18643
18644    pub fn update_renderer_widths(
18645        &mut self,
18646        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18647        cx: &mut Context<Self>,
18648    ) -> bool {
18649        self.display_map
18650            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18651    }
18652
18653    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18654        self.display_map.read(cx).fold_placeholder.clone()
18655    }
18656
18657    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18658        self.buffer.update(cx, |buffer, cx| {
18659            buffer.set_all_diff_hunks_expanded(cx);
18660        });
18661    }
18662
18663    pub fn expand_all_diff_hunks(
18664        &mut self,
18665        _: &ExpandAllDiffHunks,
18666        _window: &mut Window,
18667        cx: &mut Context<Self>,
18668    ) {
18669        self.buffer.update(cx, |buffer, cx| {
18670            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18671        });
18672    }
18673
18674    pub fn toggle_selected_diff_hunks(
18675        &mut self,
18676        _: &ToggleSelectedDiffHunks,
18677        _window: &mut Window,
18678        cx: &mut Context<Self>,
18679    ) {
18680        let ranges: Vec<_> = self
18681            .selections
18682            .disjoint_anchors()
18683            .iter()
18684            .map(|s| s.range())
18685            .collect();
18686        self.toggle_diff_hunks_in_ranges(ranges, cx);
18687    }
18688
18689    pub fn diff_hunks_in_ranges<'a>(
18690        &'a self,
18691        ranges: &'a [Range<Anchor>],
18692        buffer: &'a MultiBufferSnapshot,
18693    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18694        ranges.iter().flat_map(move |range| {
18695            let end_excerpt_id = range.end.excerpt_id;
18696            let range = range.to_point(buffer);
18697            let mut peek_end = range.end;
18698            if range.end.row < buffer.max_row().0 {
18699                peek_end = Point::new(range.end.row + 1, 0);
18700            }
18701            buffer
18702                .diff_hunks_in_range(range.start..peek_end)
18703                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18704        })
18705    }
18706
18707    pub fn has_stageable_diff_hunks_in_ranges(
18708        &self,
18709        ranges: &[Range<Anchor>],
18710        snapshot: &MultiBufferSnapshot,
18711    ) -> bool {
18712        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18713        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18714    }
18715
18716    pub fn toggle_staged_selected_diff_hunks(
18717        &mut self,
18718        _: &::git::ToggleStaged,
18719        _: &mut Window,
18720        cx: &mut Context<Self>,
18721    ) {
18722        let snapshot = self.buffer.read(cx).snapshot(cx);
18723        let ranges: Vec<_> = self
18724            .selections
18725            .disjoint_anchors()
18726            .iter()
18727            .map(|s| s.range())
18728            .collect();
18729        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18730        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18731    }
18732
18733    pub fn set_render_diff_hunk_controls(
18734        &mut self,
18735        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18736        cx: &mut Context<Self>,
18737    ) {
18738        self.render_diff_hunk_controls = render_diff_hunk_controls;
18739        cx.notify();
18740    }
18741
18742    pub fn stage_and_next(
18743        &mut self,
18744        _: &::git::StageAndNext,
18745        window: &mut Window,
18746        cx: &mut Context<Self>,
18747    ) {
18748        self.do_stage_or_unstage_and_next(true, window, cx);
18749    }
18750
18751    pub fn unstage_and_next(
18752        &mut self,
18753        _: &::git::UnstageAndNext,
18754        window: &mut Window,
18755        cx: &mut Context<Self>,
18756    ) {
18757        self.do_stage_or_unstage_and_next(false, window, cx);
18758    }
18759
18760    pub fn stage_or_unstage_diff_hunks(
18761        &mut self,
18762        stage: bool,
18763        ranges: Vec<Range<Anchor>>,
18764        cx: &mut Context<Self>,
18765    ) {
18766        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18767        cx.spawn(async move |this, cx| {
18768            task.await?;
18769            this.update(cx, |this, cx| {
18770                let snapshot = this.buffer.read(cx).snapshot(cx);
18771                let chunk_by = this
18772                    .diff_hunks_in_ranges(&ranges, &snapshot)
18773                    .chunk_by(|hunk| hunk.buffer_id);
18774                for (buffer_id, hunks) in &chunk_by {
18775                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18776                }
18777            })
18778        })
18779        .detach_and_log_err(cx);
18780    }
18781
18782    fn save_buffers_for_ranges_if_needed(
18783        &mut self,
18784        ranges: &[Range<Anchor>],
18785        cx: &mut Context<Editor>,
18786    ) -> Task<Result<()>> {
18787        let multibuffer = self.buffer.read(cx);
18788        let snapshot = multibuffer.read(cx);
18789        let buffer_ids: HashSet<_> = ranges
18790            .iter()
18791            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18792            .collect();
18793        drop(snapshot);
18794
18795        let mut buffers = HashSet::default();
18796        for buffer_id in buffer_ids {
18797            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18798                let buffer = buffer_entity.read(cx);
18799                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18800                {
18801                    buffers.insert(buffer_entity);
18802                }
18803            }
18804        }
18805
18806        if let Some(project) = &self.project {
18807            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18808        } else {
18809            Task::ready(Ok(()))
18810        }
18811    }
18812
18813    fn do_stage_or_unstage_and_next(
18814        &mut self,
18815        stage: bool,
18816        window: &mut Window,
18817        cx: &mut Context<Self>,
18818    ) {
18819        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18820
18821        if ranges.iter().any(|range| range.start != range.end) {
18822            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18823            return;
18824        }
18825
18826        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18827        let snapshot = self.snapshot(window, cx);
18828        let position = self.selections.newest::<Point>(cx).head();
18829        let mut row = snapshot
18830            .buffer_snapshot()
18831            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18832            .find(|hunk| hunk.row_range.start.0 > position.row)
18833            .map(|hunk| hunk.row_range.start);
18834
18835        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18836        // Outside of the project diff editor, wrap around to the beginning.
18837        if !all_diff_hunks_expanded {
18838            row = row.or_else(|| {
18839                snapshot
18840                    .buffer_snapshot()
18841                    .diff_hunks_in_range(Point::zero()..position)
18842                    .find(|hunk| hunk.row_range.end.0 < position.row)
18843                    .map(|hunk| hunk.row_range.start)
18844            });
18845        }
18846
18847        if let Some(row) = row {
18848            let destination = Point::new(row.0, 0);
18849            let autoscroll = Autoscroll::center();
18850
18851            self.unfold_ranges(&[destination..destination], false, false, cx);
18852            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18853                s.select_ranges([destination..destination]);
18854            });
18855        }
18856    }
18857
18858    fn do_stage_or_unstage(
18859        &self,
18860        stage: bool,
18861        buffer_id: BufferId,
18862        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18863        cx: &mut App,
18864    ) -> Option<()> {
18865        let project = self.project()?;
18866        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18867        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18868        let buffer_snapshot = buffer.read(cx).snapshot();
18869        let file_exists = buffer_snapshot
18870            .file()
18871            .is_some_and(|file| file.disk_state().exists());
18872        diff.update(cx, |diff, cx| {
18873            diff.stage_or_unstage_hunks(
18874                stage,
18875                &hunks
18876                    .map(|hunk| buffer_diff::DiffHunk {
18877                        buffer_range: hunk.buffer_range,
18878                        diff_base_byte_range: hunk.diff_base_byte_range,
18879                        secondary_status: hunk.secondary_status,
18880                        range: Point::zero()..Point::zero(), // unused
18881                    })
18882                    .collect::<Vec<_>>(),
18883                &buffer_snapshot,
18884                file_exists,
18885                cx,
18886            )
18887        });
18888        None
18889    }
18890
18891    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18892        let ranges: Vec<_> = self
18893            .selections
18894            .disjoint_anchors()
18895            .iter()
18896            .map(|s| s.range())
18897            .collect();
18898        self.buffer
18899            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18900    }
18901
18902    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18903        self.buffer.update(cx, |buffer, cx| {
18904            let ranges = vec![Anchor::min()..Anchor::max()];
18905            if !buffer.all_diff_hunks_expanded()
18906                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18907            {
18908                buffer.collapse_diff_hunks(ranges, cx);
18909                true
18910            } else {
18911                false
18912            }
18913        })
18914    }
18915
18916    fn toggle_diff_hunks_in_ranges(
18917        &mut self,
18918        ranges: Vec<Range<Anchor>>,
18919        cx: &mut Context<Editor>,
18920    ) {
18921        self.buffer.update(cx, |buffer, cx| {
18922            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18923            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18924        })
18925    }
18926
18927    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18928        self.buffer.update(cx, |buffer, cx| {
18929            let snapshot = buffer.snapshot(cx);
18930            let excerpt_id = range.end.excerpt_id;
18931            let point_range = range.to_point(&snapshot);
18932            let expand = !buffer.single_hunk_is_expanded(range, cx);
18933            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18934        })
18935    }
18936
18937    pub(crate) fn apply_all_diff_hunks(
18938        &mut self,
18939        _: &ApplyAllDiffHunks,
18940        window: &mut Window,
18941        cx: &mut Context<Self>,
18942    ) {
18943        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18944
18945        let buffers = self.buffer.read(cx).all_buffers();
18946        for branch_buffer in buffers {
18947            branch_buffer.update(cx, |branch_buffer, cx| {
18948                branch_buffer.merge_into_base(Vec::new(), cx);
18949            });
18950        }
18951
18952        if let Some(project) = self.project.clone() {
18953            self.save(
18954                SaveOptions {
18955                    format: true,
18956                    autosave: false,
18957                },
18958                project,
18959                window,
18960                cx,
18961            )
18962            .detach_and_log_err(cx);
18963        }
18964    }
18965
18966    pub(crate) fn apply_selected_diff_hunks(
18967        &mut self,
18968        _: &ApplyDiffHunk,
18969        window: &mut Window,
18970        cx: &mut Context<Self>,
18971    ) {
18972        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18973        let snapshot = self.snapshot(window, cx);
18974        let hunks = snapshot.hunks_for_ranges(
18975            self.selections
18976                .all(cx)
18977                .into_iter()
18978                .map(|selection| selection.range()),
18979        );
18980        let mut ranges_by_buffer = HashMap::default();
18981        self.transact(window, cx, |editor, _window, cx| {
18982            for hunk in hunks {
18983                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18984                    ranges_by_buffer
18985                        .entry(buffer.clone())
18986                        .or_insert_with(Vec::new)
18987                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18988                }
18989            }
18990
18991            for (buffer, ranges) in ranges_by_buffer {
18992                buffer.update(cx, |buffer, cx| {
18993                    buffer.merge_into_base(ranges, cx);
18994                });
18995            }
18996        });
18997
18998        if let Some(project) = self.project.clone() {
18999            self.save(
19000                SaveOptions {
19001                    format: true,
19002                    autosave: false,
19003                },
19004                project,
19005                window,
19006                cx,
19007            )
19008            .detach_and_log_err(cx);
19009        }
19010    }
19011
19012    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19013        if hovered != self.gutter_hovered {
19014            self.gutter_hovered = hovered;
19015            cx.notify();
19016        }
19017    }
19018
19019    pub fn insert_blocks(
19020        &mut self,
19021        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19022        autoscroll: Option<Autoscroll>,
19023        cx: &mut Context<Self>,
19024    ) -> Vec<CustomBlockId> {
19025        let blocks = self
19026            .display_map
19027            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19028        if let Some(autoscroll) = autoscroll {
19029            self.request_autoscroll(autoscroll, cx);
19030        }
19031        cx.notify();
19032        blocks
19033    }
19034
19035    pub fn resize_blocks(
19036        &mut self,
19037        heights: HashMap<CustomBlockId, u32>,
19038        autoscroll: Option<Autoscroll>,
19039        cx: &mut Context<Self>,
19040    ) {
19041        self.display_map
19042            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19043        if let Some(autoscroll) = autoscroll {
19044            self.request_autoscroll(autoscroll, cx);
19045        }
19046        cx.notify();
19047    }
19048
19049    pub fn replace_blocks(
19050        &mut self,
19051        renderers: HashMap<CustomBlockId, RenderBlock>,
19052        autoscroll: Option<Autoscroll>,
19053        cx: &mut Context<Self>,
19054    ) {
19055        self.display_map
19056            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19057        if let Some(autoscroll) = autoscroll {
19058            self.request_autoscroll(autoscroll, cx);
19059        }
19060        cx.notify();
19061    }
19062
19063    pub fn remove_blocks(
19064        &mut self,
19065        block_ids: HashSet<CustomBlockId>,
19066        autoscroll: Option<Autoscroll>,
19067        cx: &mut Context<Self>,
19068    ) {
19069        self.display_map.update(cx, |display_map, cx| {
19070            display_map.remove_blocks(block_ids, cx)
19071        });
19072        if let Some(autoscroll) = autoscroll {
19073            self.request_autoscroll(autoscroll, cx);
19074        }
19075        cx.notify();
19076    }
19077
19078    pub fn row_for_block(
19079        &self,
19080        block_id: CustomBlockId,
19081        cx: &mut Context<Self>,
19082    ) -> Option<DisplayRow> {
19083        self.display_map
19084            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19085    }
19086
19087    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19088        self.focused_block = Some(focused_block);
19089    }
19090
19091    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19092        self.focused_block.take()
19093    }
19094
19095    pub fn insert_creases(
19096        &mut self,
19097        creases: impl IntoIterator<Item = Crease<Anchor>>,
19098        cx: &mut Context<Self>,
19099    ) -> Vec<CreaseId> {
19100        self.display_map
19101            .update(cx, |map, cx| map.insert_creases(creases, cx))
19102    }
19103
19104    pub fn remove_creases(
19105        &mut self,
19106        ids: impl IntoIterator<Item = CreaseId>,
19107        cx: &mut Context<Self>,
19108    ) -> Vec<(CreaseId, Range<Anchor>)> {
19109        self.display_map
19110            .update(cx, |map, cx| map.remove_creases(ids, cx))
19111    }
19112
19113    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19114        self.display_map
19115            .update(cx, |map, cx| map.snapshot(cx))
19116            .longest_row()
19117    }
19118
19119    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19120        self.display_map
19121            .update(cx, |map, cx| map.snapshot(cx))
19122            .max_point()
19123    }
19124
19125    pub fn text(&self, cx: &App) -> String {
19126        self.buffer.read(cx).read(cx).text()
19127    }
19128
19129    pub fn is_empty(&self, cx: &App) -> bool {
19130        self.buffer.read(cx).read(cx).is_empty()
19131    }
19132
19133    pub fn text_option(&self, cx: &App) -> Option<String> {
19134        let text = self.text(cx);
19135        let text = text.trim();
19136
19137        if text.is_empty() {
19138            return None;
19139        }
19140
19141        Some(text.to_string())
19142    }
19143
19144    pub fn set_text(
19145        &mut self,
19146        text: impl Into<Arc<str>>,
19147        window: &mut Window,
19148        cx: &mut Context<Self>,
19149    ) {
19150        self.transact(window, cx, |this, _, cx| {
19151            this.buffer
19152                .read(cx)
19153                .as_singleton()
19154                .expect("you can only call set_text on editors for singleton buffers")
19155                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19156        });
19157    }
19158
19159    pub fn display_text(&self, cx: &mut App) -> String {
19160        self.display_map
19161            .update(cx, |map, cx| map.snapshot(cx))
19162            .text()
19163    }
19164
19165    fn create_minimap(
19166        &self,
19167        minimap_settings: MinimapSettings,
19168        window: &mut Window,
19169        cx: &mut Context<Self>,
19170    ) -> Option<Entity<Self>> {
19171        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19172            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19173    }
19174
19175    fn initialize_new_minimap(
19176        &self,
19177        minimap_settings: MinimapSettings,
19178        window: &mut Window,
19179        cx: &mut Context<Self>,
19180    ) -> Entity<Self> {
19181        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19182
19183        let mut minimap = Editor::new_internal(
19184            EditorMode::Minimap {
19185                parent: cx.weak_entity(),
19186            },
19187            self.buffer.clone(),
19188            None,
19189            Some(self.display_map.clone()),
19190            window,
19191            cx,
19192        );
19193        minimap.scroll_manager.clone_state(&self.scroll_manager);
19194        minimap.set_text_style_refinement(TextStyleRefinement {
19195            font_size: Some(MINIMAP_FONT_SIZE),
19196            font_weight: Some(MINIMAP_FONT_WEIGHT),
19197            ..Default::default()
19198        });
19199        minimap.update_minimap_configuration(minimap_settings, cx);
19200        cx.new(|_| minimap)
19201    }
19202
19203    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19204        let current_line_highlight = minimap_settings
19205            .current_line_highlight
19206            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19207        self.set_current_line_highlight(Some(current_line_highlight));
19208    }
19209
19210    pub fn minimap(&self) -> Option<&Entity<Self>> {
19211        self.minimap
19212            .as_ref()
19213            .filter(|_| self.minimap_visibility.visible())
19214    }
19215
19216    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19217        let mut wrap_guides = smallvec![];
19218
19219        if self.show_wrap_guides == Some(false) {
19220            return wrap_guides;
19221        }
19222
19223        let settings = self.buffer.read(cx).language_settings(cx);
19224        if settings.show_wrap_guides {
19225            match self.soft_wrap_mode(cx) {
19226                SoftWrap::Column(soft_wrap) => {
19227                    wrap_guides.push((soft_wrap as usize, true));
19228                }
19229                SoftWrap::Bounded(soft_wrap) => {
19230                    wrap_guides.push((soft_wrap as usize, true));
19231                }
19232                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19233            }
19234            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19235        }
19236
19237        wrap_guides
19238    }
19239
19240    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19241        let settings = self.buffer.read(cx).language_settings(cx);
19242        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19243        match mode {
19244            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19245                SoftWrap::None
19246            }
19247            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19248            language_settings::SoftWrap::PreferredLineLength => {
19249                SoftWrap::Column(settings.preferred_line_length)
19250            }
19251            language_settings::SoftWrap::Bounded => {
19252                SoftWrap::Bounded(settings.preferred_line_length)
19253            }
19254        }
19255    }
19256
19257    pub fn set_soft_wrap_mode(
19258        &mut self,
19259        mode: language_settings::SoftWrap,
19260
19261        cx: &mut Context<Self>,
19262    ) {
19263        self.soft_wrap_mode_override = Some(mode);
19264        cx.notify();
19265    }
19266
19267    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19268        self.hard_wrap = hard_wrap;
19269        cx.notify();
19270    }
19271
19272    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19273        self.text_style_refinement = Some(style);
19274    }
19275
19276    /// called by the Element so we know what style we were most recently rendered with.
19277    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19278        // We intentionally do not inform the display map about the minimap style
19279        // so that wrapping is not recalculated and stays consistent for the editor
19280        // and its linked minimap.
19281        if !self.mode.is_minimap() {
19282            let font = style.text.font();
19283            let font_size = style.text.font_size.to_pixels(window.rem_size());
19284            let display_map = self
19285                .placeholder_display_map
19286                .as_ref()
19287                .filter(|_| self.is_empty(cx))
19288                .unwrap_or(&self.display_map);
19289
19290            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19291        }
19292        self.style = Some(style);
19293    }
19294
19295    pub fn style(&self) -> Option<&EditorStyle> {
19296        self.style.as_ref()
19297    }
19298
19299    // Called by the element. This method is not designed to be called outside of the editor
19300    // element's layout code because it does not notify when rewrapping is computed synchronously.
19301    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19302        if self.is_empty(cx) {
19303            self.placeholder_display_map
19304                .as_ref()
19305                .map_or(false, |display_map| {
19306                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19307                })
19308        } else {
19309            self.display_map
19310                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19311        }
19312    }
19313
19314    pub fn set_soft_wrap(&mut self) {
19315        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19316    }
19317
19318    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19319        if self.soft_wrap_mode_override.is_some() {
19320            self.soft_wrap_mode_override.take();
19321        } else {
19322            let soft_wrap = match self.soft_wrap_mode(cx) {
19323                SoftWrap::GitDiff => return,
19324                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19325                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19326                    language_settings::SoftWrap::None
19327                }
19328            };
19329            self.soft_wrap_mode_override = Some(soft_wrap);
19330        }
19331        cx.notify();
19332    }
19333
19334    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19335        let Some(workspace) = self.workspace() else {
19336            return;
19337        };
19338        let fs = workspace.read(cx).app_state().fs.clone();
19339        let current_show = TabBarSettings::get_global(cx).show;
19340        update_settings_file(fs, cx, move |setting, _| {
19341            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19342        });
19343    }
19344
19345    pub fn toggle_indent_guides(
19346        &mut self,
19347        _: &ToggleIndentGuides,
19348        _: &mut Window,
19349        cx: &mut Context<Self>,
19350    ) {
19351        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19352            self.buffer
19353                .read(cx)
19354                .language_settings(cx)
19355                .indent_guides
19356                .enabled
19357        });
19358        self.show_indent_guides = Some(!currently_enabled);
19359        cx.notify();
19360    }
19361
19362    fn should_show_indent_guides(&self) -> Option<bool> {
19363        self.show_indent_guides
19364    }
19365
19366    pub fn toggle_line_numbers(
19367        &mut self,
19368        _: &ToggleLineNumbers,
19369        _: &mut Window,
19370        cx: &mut Context<Self>,
19371    ) {
19372        let mut editor_settings = EditorSettings::get_global(cx).clone();
19373        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19374        EditorSettings::override_global(editor_settings, cx);
19375    }
19376
19377    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19378        if let Some(show_line_numbers) = self.show_line_numbers {
19379            return show_line_numbers;
19380        }
19381        EditorSettings::get_global(cx).gutter.line_numbers
19382    }
19383
19384    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19385        self.use_relative_line_numbers
19386            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19387    }
19388
19389    pub fn toggle_relative_line_numbers(
19390        &mut self,
19391        _: &ToggleRelativeLineNumbers,
19392        _: &mut Window,
19393        cx: &mut Context<Self>,
19394    ) {
19395        let is_relative = self.should_use_relative_line_numbers(cx);
19396        self.set_relative_line_number(Some(!is_relative), cx)
19397    }
19398
19399    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19400        self.use_relative_line_numbers = is_relative;
19401        cx.notify();
19402    }
19403
19404    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19405        self.show_gutter = show_gutter;
19406        cx.notify();
19407    }
19408
19409    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19410        self.show_scrollbars = ScrollbarAxes {
19411            horizontal: show,
19412            vertical: show,
19413        };
19414        cx.notify();
19415    }
19416
19417    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19418        self.show_scrollbars.vertical = show;
19419        cx.notify();
19420    }
19421
19422    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19423        self.show_scrollbars.horizontal = show;
19424        cx.notify();
19425    }
19426
19427    pub fn set_minimap_visibility(
19428        &mut self,
19429        minimap_visibility: MinimapVisibility,
19430        window: &mut Window,
19431        cx: &mut Context<Self>,
19432    ) {
19433        if self.minimap_visibility != minimap_visibility {
19434            if minimap_visibility.visible() && self.minimap.is_none() {
19435                let minimap_settings = EditorSettings::get_global(cx).minimap;
19436                self.minimap =
19437                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19438            }
19439            self.minimap_visibility = minimap_visibility;
19440            cx.notify();
19441        }
19442    }
19443
19444    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19445        self.set_show_scrollbars(false, cx);
19446        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19447    }
19448
19449    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19450        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19451    }
19452
19453    /// Normally the text in full mode and auto height editors is padded on the
19454    /// left side by roughly half a character width for improved hit testing.
19455    ///
19456    /// Use this method to disable this for cases where this is not wanted (e.g.
19457    /// if you want to align the editor text with some other text above or below)
19458    /// or if you want to add this padding to single-line editors.
19459    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19460        self.offset_content = offset_content;
19461        cx.notify();
19462    }
19463
19464    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19465        self.show_line_numbers = Some(show_line_numbers);
19466        cx.notify();
19467    }
19468
19469    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19470        self.disable_expand_excerpt_buttons = true;
19471        cx.notify();
19472    }
19473
19474    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19475        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19476        cx.notify();
19477    }
19478
19479    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19480        self.show_code_actions = Some(show_code_actions);
19481        cx.notify();
19482    }
19483
19484    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19485        self.show_runnables = Some(show_runnables);
19486        cx.notify();
19487    }
19488
19489    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19490        self.show_breakpoints = Some(show_breakpoints);
19491        cx.notify();
19492    }
19493
19494    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19495        if self.display_map.read(cx).masked != masked {
19496            self.display_map.update(cx, |map, _| map.masked = masked);
19497        }
19498        cx.notify()
19499    }
19500
19501    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19502        self.show_wrap_guides = Some(show_wrap_guides);
19503        cx.notify();
19504    }
19505
19506    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19507        self.show_indent_guides = Some(show_indent_guides);
19508        cx.notify();
19509    }
19510
19511    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19512        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19513            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19514                && let Some(dir) = file.abs_path(cx).parent()
19515            {
19516                return Some(dir.to_owned());
19517            }
19518        }
19519
19520        None
19521    }
19522
19523    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19524        self.active_excerpt(cx)?
19525            .1
19526            .read(cx)
19527            .file()
19528            .and_then(|f| f.as_local())
19529    }
19530
19531    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19532        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19533            let buffer = buffer.read(cx);
19534            if let Some(project_path) = buffer.project_path(cx) {
19535                let project = self.project()?.read(cx);
19536                project.absolute_path(&project_path, cx)
19537            } else {
19538                buffer
19539                    .file()
19540                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19541            }
19542        })
19543    }
19544
19545    pub fn reveal_in_finder(
19546        &mut self,
19547        _: &RevealInFileManager,
19548        _window: &mut Window,
19549        cx: &mut Context<Self>,
19550    ) {
19551        if let Some(target) = self.target_file(cx) {
19552            cx.reveal_path(&target.abs_path(cx));
19553        }
19554    }
19555
19556    pub fn copy_path(
19557        &mut self,
19558        _: &zed_actions::workspace::CopyPath,
19559        _window: &mut Window,
19560        cx: &mut Context<Self>,
19561    ) {
19562        if let Some(path) = self.target_file_abs_path(cx)
19563            && let Some(path) = path.to_str()
19564        {
19565            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19566        } else {
19567            cx.propagate();
19568        }
19569    }
19570
19571    pub fn copy_relative_path(
19572        &mut self,
19573        _: &zed_actions::workspace::CopyRelativePath,
19574        _window: &mut Window,
19575        cx: &mut Context<Self>,
19576    ) {
19577        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19578            let project = self.project()?.read(cx);
19579            let path = buffer.read(cx).file()?.path();
19580            let path = path.display(project.path_style(cx));
19581            Some(path)
19582        }) {
19583            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19584        } else {
19585            cx.propagate();
19586        }
19587    }
19588
19589    /// Returns the project path for the editor's buffer, if any buffer is
19590    /// opened in the editor.
19591    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19592        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19593            buffer.read(cx).project_path(cx)
19594        } else {
19595            None
19596        }
19597    }
19598
19599    // Returns true if the editor handled a go-to-line request
19600    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19601        maybe!({
19602            let breakpoint_store = self.breakpoint_store.as_ref()?;
19603
19604            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19605            else {
19606                self.clear_row_highlights::<ActiveDebugLine>();
19607                return None;
19608            };
19609
19610            let position = active_stack_frame.position;
19611            let buffer_id = position.buffer_id?;
19612            let snapshot = self
19613                .project
19614                .as_ref()?
19615                .read(cx)
19616                .buffer_for_id(buffer_id, cx)?
19617                .read(cx)
19618                .snapshot();
19619
19620            let mut handled = false;
19621            for (id, ExcerptRange { context, .. }) in
19622                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19623            {
19624                if context.start.cmp(&position, &snapshot).is_ge()
19625                    || context.end.cmp(&position, &snapshot).is_lt()
19626                {
19627                    continue;
19628                }
19629                let snapshot = self.buffer.read(cx).snapshot(cx);
19630                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19631
19632                handled = true;
19633                self.clear_row_highlights::<ActiveDebugLine>();
19634
19635                self.go_to_line::<ActiveDebugLine>(
19636                    multibuffer_anchor,
19637                    Some(cx.theme().colors().editor_debugger_active_line_background),
19638                    window,
19639                    cx,
19640                );
19641
19642                cx.notify();
19643            }
19644
19645            handled.then_some(())
19646        })
19647        .is_some()
19648    }
19649
19650    pub fn copy_file_name_without_extension(
19651        &mut self,
19652        _: &CopyFileNameWithoutExtension,
19653        _: &mut Window,
19654        cx: &mut Context<Self>,
19655    ) {
19656        if let Some(file) = self.target_file(cx)
19657            && let Some(file_stem) = file.path().file_stem()
19658        {
19659            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19660        }
19661    }
19662
19663    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19664        if let Some(file) = self.target_file(cx)
19665            && let Some(name) = file.path().file_name()
19666        {
19667            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19668        }
19669    }
19670
19671    pub fn toggle_git_blame(
19672        &mut self,
19673        _: &::git::Blame,
19674        window: &mut Window,
19675        cx: &mut Context<Self>,
19676    ) {
19677        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19678
19679        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19680            self.start_git_blame(true, window, cx);
19681        }
19682
19683        cx.notify();
19684    }
19685
19686    pub fn toggle_git_blame_inline(
19687        &mut self,
19688        _: &ToggleGitBlameInline,
19689        window: &mut Window,
19690        cx: &mut Context<Self>,
19691    ) {
19692        self.toggle_git_blame_inline_internal(true, window, cx);
19693        cx.notify();
19694    }
19695
19696    pub fn open_git_blame_commit(
19697        &mut self,
19698        _: &OpenGitBlameCommit,
19699        window: &mut Window,
19700        cx: &mut Context<Self>,
19701    ) {
19702        self.open_git_blame_commit_internal(window, cx);
19703    }
19704
19705    fn open_git_blame_commit_internal(
19706        &mut self,
19707        window: &mut Window,
19708        cx: &mut Context<Self>,
19709    ) -> Option<()> {
19710        let blame = self.blame.as_ref()?;
19711        let snapshot = self.snapshot(window, cx);
19712        let cursor = self.selections.newest::<Point>(cx).head();
19713        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19714        let (_, blame_entry) = blame
19715            .update(cx, |blame, cx| {
19716                blame
19717                    .blame_for_rows(
19718                        &[RowInfo {
19719                            buffer_id: Some(buffer.remote_id()),
19720                            buffer_row: Some(point.row),
19721                            ..Default::default()
19722                        }],
19723                        cx,
19724                    )
19725                    .next()
19726            })
19727            .flatten()?;
19728        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19729        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19730        let workspace = self.workspace()?.downgrade();
19731        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19732        None
19733    }
19734
19735    pub fn git_blame_inline_enabled(&self) -> bool {
19736        self.git_blame_inline_enabled
19737    }
19738
19739    pub fn toggle_selection_menu(
19740        &mut self,
19741        _: &ToggleSelectionMenu,
19742        _: &mut Window,
19743        cx: &mut Context<Self>,
19744    ) {
19745        self.show_selection_menu = self
19746            .show_selection_menu
19747            .map(|show_selections_menu| !show_selections_menu)
19748            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19749
19750        cx.notify();
19751    }
19752
19753    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19754        self.show_selection_menu
19755            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19756    }
19757
19758    fn start_git_blame(
19759        &mut self,
19760        user_triggered: bool,
19761        window: &mut Window,
19762        cx: &mut Context<Self>,
19763    ) {
19764        if let Some(project) = self.project() {
19765            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19766                && buffer.read(cx).file().is_none()
19767            {
19768                return;
19769            }
19770
19771            let focused = self.focus_handle(cx).contains_focused(window, cx);
19772
19773            let project = project.clone();
19774            let blame = cx
19775                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19776            self.blame_subscription =
19777                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19778            self.blame = Some(blame);
19779        }
19780    }
19781
19782    fn toggle_git_blame_inline_internal(
19783        &mut self,
19784        user_triggered: bool,
19785        window: &mut Window,
19786        cx: &mut Context<Self>,
19787    ) {
19788        if self.git_blame_inline_enabled {
19789            self.git_blame_inline_enabled = false;
19790            self.show_git_blame_inline = false;
19791            self.show_git_blame_inline_delay_task.take();
19792        } else {
19793            self.git_blame_inline_enabled = true;
19794            self.start_git_blame_inline(user_triggered, window, cx);
19795        }
19796
19797        cx.notify();
19798    }
19799
19800    fn start_git_blame_inline(
19801        &mut self,
19802        user_triggered: bool,
19803        window: &mut Window,
19804        cx: &mut Context<Self>,
19805    ) {
19806        self.start_git_blame(user_triggered, window, cx);
19807
19808        if ProjectSettings::get_global(cx)
19809            .git
19810            .inline_blame_delay()
19811            .is_some()
19812        {
19813            self.start_inline_blame_timer(window, cx);
19814        } else {
19815            self.show_git_blame_inline = true
19816        }
19817    }
19818
19819    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19820        self.blame.as_ref()
19821    }
19822
19823    pub fn show_git_blame_gutter(&self) -> bool {
19824        self.show_git_blame_gutter
19825    }
19826
19827    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19828        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19829    }
19830
19831    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19832        self.show_git_blame_inline
19833            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19834            && !self.newest_selection_head_on_empty_line(cx)
19835            && self.has_blame_entries(cx)
19836    }
19837
19838    fn has_blame_entries(&self, cx: &App) -> bool {
19839        self.blame()
19840            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19841    }
19842
19843    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19844        let cursor_anchor = self.selections.newest_anchor().head();
19845
19846        let snapshot = self.buffer.read(cx).snapshot(cx);
19847        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19848
19849        snapshot.line_len(buffer_row) == 0
19850    }
19851
19852    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19853        let buffer_and_selection = maybe!({
19854            let selection = self.selections.newest::<Point>(cx);
19855            let selection_range = selection.range();
19856
19857            let multi_buffer = self.buffer().read(cx);
19858            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19859            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19860
19861            let (buffer, range, _) = if selection.reversed {
19862                buffer_ranges.first()
19863            } else {
19864                buffer_ranges.last()
19865            }?;
19866
19867            let selection = text::ToPoint::to_point(&range.start, buffer).row
19868                ..text::ToPoint::to_point(&range.end, buffer).row;
19869            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19870        });
19871
19872        let Some((buffer, selection)) = buffer_and_selection else {
19873            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19874        };
19875
19876        let Some(project) = self.project() else {
19877            return Task::ready(Err(anyhow!("editor does not have project")));
19878        };
19879
19880        project.update(cx, |project, cx| {
19881            project.get_permalink_to_line(&buffer, selection, cx)
19882        })
19883    }
19884
19885    pub fn copy_permalink_to_line(
19886        &mut self,
19887        _: &CopyPermalinkToLine,
19888        window: &mut Window,
19889        cx: &mut Context<Self>,
19890    ) {
19891        let permalink_task = self.get_permalink_to_line(cx);
19892        let workspace = self.workspace();
19893
19894        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19895            Ok(permalink) => {
19896                cx.update(|_, cx| {
19897                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19898                })
19899                .ok();
19900            }
19901            Err(err) => {
19902                let message = format!("Failed to copy permalink: {err}");
19903
19904                anyhow::Result::<()>::Err(err).log_err();
19905
19906                if let Some(workspace) = workspace {
19907                    workspace
19908                        .update_in(cx, |workspace, _, cx| {
19909                            struct CopyPermalinkToLine;
19910
19911                            workspace.show_toast(
19912                                Toast::new(
19913                                    NotificationId::unique::<CopyPermalinkToLine>(),
19914                                    message,
19915                                ),
19916                                cx,
19917                            )
19918                        })
19919                        .ok();
19920                }
19921            }
19922        })
19923        .detach();
19924    }
19925
19926    pub fn copy_file_location(
19927        &mut self,
19928        _: &CopyFileLocation,
19929        _: &mut Window,
19930        cx: &mut Context<Self>,
19931    ) {
19932        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19933        if let Some(file) = self.target_file(cx) {
19934            let path = file.path().display(file.path_style(cx));
19935            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19936        }
19937    }
19938
19939    pub fn open_permalink_to_line(
19940        &mut self,
19941        _: &OpenPermalinkToLine,
19942        window: &mut Window,
19943        cx: &mut Context<Self>,
19944    ) {
19945        let permalink_task = self.get_permalink_to_line(cx);
19946        let workspace = self.workspace();
19947
19948        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19949            Ok(permalink) => {
19950                cx.update(|_, cx| {
19951                    cx.open_url(permalink.as_ref());
19952                })
19953                .ok();
19954            }
19955            Err(err) => {
19956                let message = format!("Failed to open permalink: {err}");
19957
19958                anyhow::Result::<()>::Err(err).log_err();
19959
19960                if let Some(workspace) = workspace {
19961                    workspace
19962                        .update(cx, |workspace, cx| {
19963                            struct OpenPermalinkToLine;
19964
19965                            workspace.show_toast(
19966                                Toast::new(
19967                                    NotificationId::unique::<OpenPermalinkToLine>(),
19968                                    message,
19969                                ),
19970                                cx,
19971                            )
19972                        })
19973                        .ok();
19974                }
19975            }
19976        })
19977        .detach();
19978    }
19979
19980    pub fn insert_uuid_v4(
19981        &mut self,
19982        _: &InsertUuidV4,
19983        window: &mut Window,
19984        cx: &mut Context<Self>,
19985    ) {
19986        self.insert_uuid(UuidVersion::V4, window, cx);
19987    }
19988
19989    pub fn insert_uuid_v7(
19990        &mut self,
19991        _: &InsertUuidV7,
19992        window: &mut Window,
19993        cx: &mut Context<Self>,
19994    ) {
19995        self.insert_uuid(UuidVersion::V7, window, cx);
19996    }
19997
19998    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19999        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20000        self.transact(window, cx, |this, window, cx| {
20001            let edits = this
20002                .selections
20003                .all::<Point>(cx)
20004                .into_iter()
20005                .map(|selection| {
20006                    let uuid = match version {
20007                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20008                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20009                    };
20010
20011                    (selection.range(), uuid.to_string())
20012                });
20013            this.edit(edits, cx);
20014            this.refresh_edit_prediction(true, false, window, cx);
20015        });
20016    }
20017
20018    pub fn open_selections_in_multibuffer(
20019        &mut self,
20020        _: &OpenSelectionsInMultibuffer,
20021        window: &mut Window,
20022        cx: &mut Context<Self>,
20023    ) {
20024        let multibuffer = self.buffer.read(cx);
20025
20026        let Some(buffer) = multibuffer.as_singleton() else {
20027            return;
20028        };
20029
20030        let Some(workspace) = self.workspace() else {
20031            return;
20032        };
20033
20034        let title = multibuffer.title(cx).to_string();
20035
20036        let locations = self
20037            .selections
20038            .all_anchors(cx)
20039            .iter()
20040            .map(|selection| {
20041                (
20042                    buffer.clone(),
20043                    (selection.start.text_anchor..selection.end.text_anchor)
20044                        .to_point(buffer.read(cx)),
20045                )
20046            })
20047            .into_group_map();
20048
20049        cx.spawn_in(window, async move |_, cx| {
20050            workspace.update_in(cx, |workspace, window, cx| {
20051                Self::open_locations_in_multibuffer(
20052                    workspace,
20053                    locations,
20054                    format!("Selections for '{title}'"),
20055                    false,
20056                    MultibufferSelectionMode::All,
20057                    window,
20058                    cx,
20059                );
20060            })
20061        })
20062        .detach();
20063    }
20064
20065    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20066    /// last highlight added will be used.
20067    ///
20068    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20069    pub fn highlight_rows<T: 'static>(
20070        &mut self,
20071        range: Range<Anchor>,
20072        color: Hsla,
20073        options: RowHighlightOptions,
20074        cx: &mut Context<Self>,
20075    ) {
20076        let snapshot = self.buffer().read(cx).snapshot(cx);
20077        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20078        let ix = row_highlights.binary_search_by(|highlight| {
20079            Ordering::Equal
20080                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20081                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20082        });
20083
20084        if let Err(mut ix) = ix {
20085            let index = post_inc(&mut self.highlight_order);
20086
20087            // If this range intersects with the preceding highlight, then merge it with
20088            // the preceding highlight. Otherwise insert a new highlight.
20089            let mut merged = false;
20090            if ix > 0 {
20091                let prev_highlight = &mut row_highlights[ix - 1];
20092                if prev_highlight
20093                    .range
20094                    .end
20095                    .cmp(&range.start, &snapshot)
20096                    .is_ge()
20097                {
20098                    ix -= 1;
20099                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20100                        prev_highlight.range.end = range.end;
20101                    }
20102                    merged = true;
20103                    prev_highlight.index = index;
20104                    prev_highlight.color = color;
20105                    prev_highlight.options = options;
20106                }
20107            }
20108
20109            if !merged {
20110                row_highlights.insert(
20111                    ix,
20112                    RowHighlight {
20113                        range,
20114                        index,
20115                        color,
20116                        options,
20117                        type_id: TypeId::of::<T>(),
20118                    },
20119                );
20120            }
20121
20122            // If any of the following highlights intersect with this one, merge them.
20123            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20124                let highlight = &row_highlights[ix];
20125                if next_highlight
20126                    .range
20127                    .start
20128                    .cmp(&highlight.range.end, &snapshot)
20129                    .is_le()
20130                {
20131                    if next_highlight
20132                        .range
20133                        .end
20134                        .cmp(&highlight.range.end, &snapshot)
20135                        .is_gt()
20136                    {
20137                        row_highlights[ix].range.end = next_highlight.range.end;
20138                    }
20139                    row_highlights.remove(ix + 1);
20140                } else {
20141                    break;
20142                }
20143            }
20144        }
20145    }
20146
20147    /// Remove any highlighted row ranges of the given type that intersect the
20148    /// given ranges.
20149    pub fn remove_highlighted_rows<T: 'static>(
20150        &mut self,
20151        ranges_to_remove: Vec<Range<Anchor>>,
20152        cx: &mut Context<Self>,
20153    ) {
20154        let snapshot = self.buffer().read(cx).snapshot(cx);
20155        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20156        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20157        row_highlights.retain(|highlight| {
20158            while let Some(range_to_remove) = ranges_to_remove.peek() {
20159                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20160                    Ordering::Less | Ordering::Equal => {
20161                        ranges_to_remove.next();
20162                    }
20163                    Ordering::Greater => {
20164                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20165                            Ordering::Less | Ordering::Equal => {
20166                                return false;
20167                            }
20168                            Ordering::Greater => break,
20169                        }
20170                    }
20171                }
20172            }
20173
20174            true
20175        })
20176    }
20177
20178    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20179    pub fn clear_row_highlights<T: 'static>(&mut self) {
20180        self.highlighted_rows.remove(&TypeId::of::<T>());
20181    }
20182
20183    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20184    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20185        self.highlighted_rows
20186            .get(&TypeId::of::<T>())
20187            .map_or(&[] as &[_], |vec| vec.as_slice())
20188            .iter()
20189            .map(|highlight| (highlight.range.clone(), highlight.color))
20190    }
20191
20192    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20193    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20194    /// Allows to ignore certain kinds of highlights.
20195    pub fn highlighted_display_rows(
20196        &self,
20197        window: &mut Window,
20198        cx: &mut App,
20199    ) -> BTreeMap<DisplayRow, LineHighlight> {
20200        let snapshot = self.snapshot(window, cx);
20201        let mut used_highlight_orders = HashMap::default();
20202        self.highlighted_rows
20203            .iter()
20204            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20205            .fold(
20206                BTreeMap::<DisplayRow, LineHighlight>::new(),
20207                |mut unique_rows, highlight| {
20208                    let start = highlight.range.start.to_display_point(&snapshot);
20209                    let end = highlight.range.end.to_display_point(&snapshot);
20210                    let start_row = start.row().0;
20211                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20212                        && end.column() == 0
20213                    {
20214                        end.row().0.saturating_sub(1)
20215                    } else {
20216                        end.row().0
20217                    };
20218                    for row in start_row..=end_row {
20219                        let used_index =
20220                            used_highlight_orders.entry(row).or_insert(highlight.index);
20221                        if highlight.index >= *used_index {
20222                            *used_index = highlight.index;
20223                            unique_rows.insert(
20224                                DisplayRow(row),
20225                                LineHighlight {
20226                                    include_gutter: highlight.options.include_gutter,
20227                                    border: None,
20228                                    background: highlight.color.into(),
20229                                    type_id: Some(highlight.type_id),
20230                                },
20231                            );
20232                        }
20233                    }
20234                    unique_rows
20235                },
20236            )
20237    }
20238
20239    pub fn highlighted_display_row_for_autoscroll(
20240        &self,
20241        snapshot: &DisplaySnapshot,
20242    ) -> Option<DisplayRow> {
20243        self.highlighted_rows
20244            .values()
20245            .flat_map(|highlighted_rows| highlighted_rows.iter())
20246            .filter_map(|highlight| {
20247                if highlight.options.autoscroll {
20248                    Some(highlight.range.start.to_display_point(snapshot).row())
20249                } else {
20250                    None
20251                }
20252            })
20253            .min()
20254    }
20255
20256    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20257        self.highlight_background::<SearchWithinRange>(
20258            ranges,
20259            |colors| colors.colors().editor_document_highlight_read_background,
20260            cx,
20261        )
20262    }
20263
20264    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20265        self.breadcrumb_header = Some(new_header);
20266    }
20267
20268    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20269        self.clear_background_highlights::<SearchWithinRange>(cx);
20270    }
20271
20272    pub fn highlight_background<T: 'static>(
20273        &mut self,
20274        ranges: &[Range<Anchor>],
20275        color_fetcher: fn(&Theme) -> Hsla,
20276        cx: &mut Context<Self>,
20277    ) {
20278        self.background_highlights.insert(
20279            HighlightKey::Type(TypeId::of::<T>()),
20280            (color_fetcher, Arc::from(ranges)),
20281        );
20282        self.scrollbar_marker_state.dirty = true;
20283        cx.notify();
20284    }
20285
20286    pub fn highlight_background_key<T: 'static>(
20287        &mut self,
20288        key: usize,
20289        ranges: &[Range<Anchor>],
20290        color_fetcher: fn(&Theme) -> Hsla,
20291        cx: &mut Context<Self>,
20292    ) {
20293        self.background_highlights.insert(
20294            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20295            (color_fetcher, Arc::from(ranges)),
20296        );
20297        self.scrollbar_marker_state.dirty = true;
20298        cx.notify();
20299    }
20300
20301    pub fn clear_background_highlights<T: 'static>(
20302        &mut self,
20303        cx: &mut Context<Self>,
20304    ) -> Option<BackgroundHighlight> {
20305        let text_highlights = self
20306            .background_highlights
20307            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20308        if !text_highlights.1.is_empty() {
20309            self.scrollbar_marker_state.dirty = true;
20310            cx.notify();
20311        }
20312        Some(text_highlights)
20313    }
20314
20315    pub fn highlight_gutter<T: 'static>(
20316        &mut self,
20317        ranges: impl Into<Vec<Range<Anchor>>>,
20318        color_fetcher: fn(&App) -> Hsla,
20319        cx: &mut Context<Self>,
20320    ) {
20321        self.gutter_highlights
20322            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20323        cx.notify();
20324    }
20325
20326    pub fn clear_gutter_highlights<T: 'static>(
20327        &mut self,
20328        cx: &mut Context<Self>,
20329    ) -> Option<GutterHighlight> {
20330        cx.notify();
20331        self.gutter_highlights.remove(&TypeId::of::<T>())
20332    }
20333
20334    pub fn insert_gutter_highlight<T: 'static>(
20335        &mut self,
20336        range: Range<Anchor>,
20337        color_fetcher: fn(&App) -> Hsla,
20338        cx: &mut Context<Self>,
20339    ) {
20340        let snapshot = self.buffer().read(cx).snapshot(cx);
20341        let mut highlights = self
20342            .gutter_highlights
20343            .remove(&TypeId::of::<T>())
20344            .map(|(_, highlights)| highlights)
20345            .unwrap_or_default();
20346        let ix = highlights.binary_search_by(|highlight| {
20347            Ordering::Equal
20348                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20349                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20350        });
20351        if let Err(ix) = ix {
20352            highlights.insert(ix, range);
20353        }
20354        self.gutter_highlights
20355            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20356    }
20357
20358    pub fn remove_gutter_highlights<T: 'static>(
20359        &mut self,
20360        ranges_to_remove: Vec<Range<Anchor>>,
20361        cx: &mut Context<Self>,
20362    ) {
20363        let snapshot = self.buffer().read(cx).snapshot(cx);
20364        let Some((color_fetcher, mut gutter_highlights)) =
20365            self.gutter_highlights.remove(&TypeId::of::<T>())
20366        else {
20367            return;
20368        };
20369        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20370        gutter_highlights.retain(|highlight| {
20371            while let Some(range_to_remove) = ranges_to_remove.peek() {
20372                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20373                    Ordering::Less | Ordering::Equal => {
20374                        ranges_to_remove.next();
20375                    }
20376                    Ordering::Greater => {
20377                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20378                            Ordering::Less | Ordering::Equal => {
20379                                return false;
20380                            }
20381                            Ordering::Greater => break,
20382                        }
20383                    }
20384                }
20385            }
20386
20387            true
20388        });
20389        self.gutter_highlights
20390            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20391    }
20392
20393    #[cfg(feature = "test-support")]
20394    pub fn all_text_highlights(
20395        &self,
20396        window: &mut Window,
20397        cx: &mut Context<Self>,
20398    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20399        let snapshot = self.snapshot(window, cx);
20400        self.display_map.update(cx, |display_map, _| {
20401            display_map
20402                .all_text_highlights()
20403                .map(|highlight| {
20404                    let (style, ranges) = highlight.as_ref();
20405                    (
20406                        *style,
20407                        ranges
20408                            .iter()
20409                            .map(|range| range.clone().to_display_points(&snapshot))
20410                            .collect(),
20411                    )
20412                })
20413                .collect()
20414        })
20415    }
20416
20417    #[cfg(feature = "test-support")]
20418    pub fn all_text_background_highlights(
20419        &self,
20420        window: &mut Window,
20421        cx: &mut Context<Self>,
20422    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20423        let snapshot = self.snapshot(window, cx);
20424        let buffer = &snapshot.buffer_snapshot();
20425        let start = buffer.anchor_before(0);
20426        let end = buffer.anchor_after(buffer.len());
20427        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20428    }
20429
20430    #[cfg(any(test, feature = "test-support"))]
20431    pub fn sorted_background_highlights_in_range(
20432        &self,
20433        search_range: Range<Anchor>,
20434        display_snapshot: &DisplaySnapshot,
20435        theme: &Theme,
20436    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20437        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20438        res.sort_by(|a, b| {
20439            a.0.start
20440                .cmp(&b.0.start)
20441                .then_with(|| a.0.end.cmp(&b.0.end))
20442                .then_with(|| a.1.cmp(&b.1))
20443        });
20444        res
20445    }
20446
20447    #[cfg(feature = "test-support")]
20448    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20449        let snapshot = self.buffer().read(cx).snapshot(cx);
20450
20451        let highlights = self
20452            .background_highlights
20453            .get(&HighlightKey::Type(TypeId::of::<
20454                items::BufferSearchHighlights,
20455            >()));
20456
20457        if let Some((_color, ranges)) = highlights {
20458            ranges
20459                .iter()
20460                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20461                .collect_vec()
20462        } else {
20463            vec![]
20464        }
20465    }
20466
20467    fn document_highlights_for_position<'a>(
20468        &'a self,
20469        position: Anchor,
20470        buffer: &'a MultiBufferSnapshot,
20471    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20472        let read_highlights = self
20473            .background_highlights
20474            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20475            .map(|h| &h.1);
20476        let write_highlights = self
20477            .background_highlights
20478            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20479            .map(|h| &h.1);
20480        let left_position = position.bias_left(buffer);
20481        let right_position = position.bias_right(buffer);
20482        read_highlights
20483            .into_iter()
20484            .chain(write_highlights)
20485            .flat_map(move |ranges| {
20486                let start_ix = match ranges.binary_search_by(|probe| {
20487                    let cmp = probe.end.cmp(&left_position, buffer);
20488                    if cmp.is_ge() {
20489                        Ordering::Greater
20490                    } else {
20491                        Ordering::Less
20492                    }
20493                }) {
20494                    Ok(i) | Err(i) => i,
20495                };
20496
20497                ranges[start_ix..]
20498                    .iter()
20499                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20500            })
20501    }
20502
20503    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20504        self.background_highlights
20505            .get(&HighlightKey::Type(TypeId::of::<T>()))
20506            .is_some_and(|(_, highlights)| !highlights.is_empty())
20507    }
20508
20509    /// Returns all background highlights for a given range.
20510    ///
20511    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20512    pub fn background_highlights_in_range(
20513        &self,
20514        search_range: Range<Anchor>,
20515        display_snapshot: &DisplaySnapshot,
20516        theme: &Theme,
20517    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20518        let mut results = Vec::new();
20519        for (color_fetcher, ranges) in self.background_highlights.values() {
20520            let color = color_fetcher(theme);
20521            let start_ix = match ranges.binary_search_by(|probe| {
20522                let cmp = probe
20523                    .end
20524                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20525                if cmp.is_gt() {
20526                    Ordering::Greater
20527                } else {
20528                    Ordering::Less
20529                }
20530            }) {
20531                Ok(i) | Err(i) => i,
20532            };
20533            for range in &ranges[start_ix..] {
20534                if range
20535                    .start
20536                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20537                    .is_ge()
20538                {
20539                    break;
20540                }
20541
20542                let start = range.start.to_display_point(display_snapshot);
20543                let end = range.end.to_display_point(display_snapshot);
20544                results.push((start..end, color))
20545            }
20546        }
20547        results
20548    }
20549
20550    pub fn gutter_highlights_in_range(
20551        &self,
20552        search_range: Range<Anchor>,
20553        display_snapshot: &DisplaySnapshot,
20554        cx: &App,
20555    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20556        let mut results = Vec::new();
20557        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20558            let color = color_fetcher(cx);
20559            let start_ix = match ranges.binary_search_by(|probe| {
20560                let cmp = probe
20561                    .end
20562                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20563                if cmp.is_gt() {
20564                    Ordering::Greater
20565                } else {
20566                    Ordering::Less
20567                }
20568            }) {
20569                Ok(i) | Err(i) => i,
20570            };
20571            for range in &ranges[start_ix..] {
20572                if range
20573                    .start
20574                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20575                    .is_ge()
20576                {
20577                    break;
20578                }
20579
20580                let start = range.start.to_display_point(display_snapshot);
20581                let end = range.end.to_display_point(display_snapshot);
20582                results.push((start..end, color))
20583            }
20584        }
20585        results
20586    }
20587
20588    /// Get the text ranges corresponding to the redaction query
20589    pub fn redacted_ranges(
20590        &self,
20591        search_range: Range<Anchor>,
20592        display_snapshot: &DisplaySnapshot,
20593        cx: &App,
20594    ) -> Vec<Range<DisplayPoint>> {
20595        display_snapshot
20596            .buffer_snapshot()
20597            .redacted_ranges(search_range, |file| {
20598                if let Some(file) = file {
20599                    file.is_private()
20600                        && EditorSettings::get(
20601                            Some(SettingsLocation {
20602                                worktree_id: file.worktree_id(cx),
20603                                path: file.path().as_ref(),
20604                            }),
20605                            cx,
20606                        )
20607                        .redact_private_values
20608                } else {
20609                    false
20610                }
20611            })
20612            .map(|range| {
20613                range.start.to_display_point(display_snapshot)
20614                    ..range.end.to_display_point(display_snapshot)
20615            })
20616            .collect()
20617    }
20618
20619    pub fn highlight_text_key<T: 'static>(
20620        &mut self,
20621        key: usize,
20622        ranges: Vec<Range<Anchor>>,
20623        style: HighlightStyle,
20624        cx: &mut Context<Self>,
20625    ) {
20626        self.display_map.update(cx, |map, _| {
20627            map.highlight_text(
20628                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20629                ranges,
20630                style,
20631            );
20632        });
20633        cx.notify();
20634    }
20635
20636    pub fn highlight_text<T: 'static>(
20637        &mut self,
20638        ranges: Vec<Range<Anchor>>,
20639        style: HighlightStyle,
20640        cx: &mut Context<Self>,
20641    ) {
20642        self.display_map.update(cx, |map, _| {
20643            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20644        });
20645        cx.notify();
20646    }
20647
20648    pub(crate) fn highlight_inlays<T: 'static>(
20649        &mut self,
20650        highlights: Vec<InlayHighlight>,
20651        style: HighlightStyle,
20652        cx: &mut Context<Self>,
20653    ) {
20654        self.display_map.update(cx, |map, _| {
20655            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20656        });
20657        cx.notify();
20658    }
20659
20660    pub fn text_highlights<'a, T: 'static>(
20661        &'a self,
20662        cx: &'a App,
20663    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20664        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20665    }
20666
20667    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20668        let cleared = self
20669            .display_map
20670            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20671        if cleared {
20672            cx.notify();
20673        }
20674    }
20675
20676    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20677        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20678            && self.focus_handle.is_focused(window)
20679    }
20680
20681    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20682        self.show_cursor_when_unfocused = is_enabled;
20683        cx.notify();
20684    }
20685
20686    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20687        cx.notify();
20688    }
20689
20690    fn on_debug_session_event(
20691        &mut self,
20692        _session: Entity<Session>,
20693        event: &SessionEvent,
20694        cx: &mut Context<Self>,
20695    ) {
20696        if let SessionEvent::InvalidateInlineValue = event {
20697            self.refresh_inline_values(cx);
20698        }
20699    }
20700
20701    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20702        let Some(project) = self.project.clone() else {
20703            return;
20704        };
20705
20706        if !self.inline_value_cache.enabled {
20707            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20708            self.splice_inlays(&inlays, Vec::new(), cx);
20709            return;
20710        }
20711
20712        let current_execution_position = self
20713            .highlighted_rows
20714            .get(&TypeId::of::<ActiveDebugLine>())
20715            .and_then(|lines| lines.last().map(|line| line.range.end));
20716
20717        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20718            let inline_values = editor
20719                .update(cx, |editor, cx| {
20720                    let Some(current_execution_position) = current_execution_position else {
20721                        return Some(Task::ready(Ok(Vec::new())));
20722                    };
20723
20724                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20725                        let snapshot = buffer.snapshot(cx);
20726
20727                        let excerpt = snapshot.excerpt_containing(
20728                            current_execution_position..current_execution_position,
20729                        )?;
20730
20731                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20732                    })?;
20733
20734                    let range =
20735                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20736
20737                    project.inline_values(buffer, range, cx)
20738                })
20739                .ok()
20740                .flatten()?
20741                .await
20742                .context("refreshing debugger inlays")
20743                .log_err()?;
20744
20745            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20746
20747            for (buffer_id, inline_value) in inline_values
20748                .into_iter()
20749                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20750            {
20751                buffer_inline_values
20752                    .entry(buffer_id)
20753                    .or_default()
20754                    .push(inline_value);
20755            }
20756
20757            editor
20758                .update(cx, |editor, cx| {
20759                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20760                    let mut new_inlays = Vec::default();
20761
20762                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20763                        let buffer_id = buffer_snapshot.remote_id();
20764                        buffer_inline_values
20765                            .get(&buffer_id)
20766                            .into_iter()
20767                            .flatten()
20768                            .for_each(|hint| {
20769                                let inlay = Inlay::debugger(
20770                                    post_inc(&mut editor.next_inlay_id),
20771                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20772                                    hint.text(),
20773                                );
20774                                if !inlay.text().chars().contains(&'\n') {
20775                                    new_inlays.push(inlay);
20776                                }
20777                            });
20778                    }
20779
20780                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20781                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20782
20783                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20784                })
20785                .ok()?;
20786            Some(())
20787        });
20788    }
20789
20790    fn on_buffer_event(
20791        &mut self,
20792        multibuffer: &Entity<MultiBuffer>,
20793        event: &multi_buffer::Event,
20794        window: &mut Window,
20795        cx: &mut Context<Self>,
20796    ) {
20797        match event {
20798            multi_buffer::Event::Edited {
20799                singleton_buffer_edited,
20800                edited_buffer,
20801            } => {
20802                self.scrollbar_marker_state.dirty = true;
20803                self.active_indent_guides_state.dirty = true;
20804                self.refresh_active_diagnostics(cx);
20805                self.refresh_code_actions(window, cx);
20806                self.refresh_selected_text_highlights(true, window, cx);
20807                self.refresh_single_line_folds(window, cx);
20808                refresh_matching_bracket_highlights(self, window, cx);
20809                if self.has_active_edit_prediction() {
20810                    self.update_visible_edit_prediction(window, cx);
20811                }
20812                if let Some(project) = self.project.as_ref()
20813                    && let Some(edited_buffer) = edited_buffer
20814                {
20815                    project.update(cx, |project, cx| {
20816                        self.registered_buffers
20817                            .entry(edited_buffer.read(cx).remote_id())
20818                            .or_insert_with(|| {
20819                                project.register_buffer_with_language_servers(edited_buffer, cx)
20820                            });
20821                    });
20822                }
20823                cx.emit(EditorEvent::BufferEdited);
20824                cx.emit(SearchEvent::MatchesInvalidated);
20825
20826                if let Some(buffer) = edited_buffer {
20827                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20828                }
20829
20830                if *singleton_buffer_edited {
20831                    if let Some(buffer) = edited_buffer
20832                        && buffer.read(cx).file().is_none()
20833                    {
20834                        cx.emit(EditorEvent::TitleChanged);
20835                    }
20836                    if let Some(project) = &self.project {
20837                        #[allow(clippy::mutable_key_type)]
20838                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20839                            multibuffer
20840                                .all_buffers()
20841                                .into_iter()
20842                                .filter_map(|buffer| {
20843                                    buffer.update(cx, |buffer, cx| {
20844                                        let language = buffer.language()?;
20845                                        let should_discard = project.update(cx, |project, cx| {
20846                                            project.is_local()
20847                                                && !project.has_language_servers_for(buffer, cx)
20848                                        });
20849                                        should_discard.not().then_some(language.clone())
20850                                    })
20851                                })
20852                                .collect::<HashSet<_>>()
20853                        });
20854                        if !languages_affected.is_empty() {
20855                            self.refresh_inlay_hints(
20856                                InlayHintRefreshReason::BufferEdited(languages_affected),
20857                                cx,
20858                            );
20859                        }
20860                    }
20861                }
20862
20863                let Some(project) = &self.project else { return };
20864                let (telemetry, is_via_ssh) = {
20865                    let project = project.read(cx);
20866                    let telemetry = project.client().telemetry().clone();
20867                    let is_via_ssh = project.is_via_remote_server();
20868                    (telemetry, is_via_ssh)
20869                };
20870                refresh_linked_ranges(self, window, cx);
20871                telemetry.log_edit_event("editor", is_via_ssh);
20872            }
20873            multi_buffer::Event::ExcerptsAdded {
20874                buffer,
20875                predecessor,
20876                excerpts,
20877            } => {
20878                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20879                let buffer_id = buffer.read(cx).remote_id();
20880                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20881                    && let Some(project) = &self.project
20882                {
20883                    update_uncommitted_diff_for_buffer(
20884                        cx.entity(),
20885                        project,
20886                        [buffer.clone()],
20887                        self.buffer.clone(),
20888                        cx,
20889                    )
20890                    .detach();
20891                }
20892                if self.active_diagnostics != ActiveDiagnostic::All {
20893                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20894                }
20895                cx.emit(EditorEvent::ExcerptsAdded {
20896                    buffer: buffer.clone(),
20897                    predecessor: *predecessor,
20898                    excerpts: excerpts.clone(),
20899                });
20900                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20901            }
20902            multi_buffer::Event::ExcerptsRemoved {
20903                ids,
20904                removed_buffer_ids,
20905            } => {
20906                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20907                let buffer = self.buffer.read(cx);
20908                self.registered_buffers
20909                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20910                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20911                cx.emit(EditorEvent::ExcerptsRemoved {
20912                    ids: ids.clone(),
20913                    removed_buffer_ids: removed_buffer_ids.clone(),
20914                });
20915            }
20916            multi_buffer::Event::ExcerptsEdited {
20917                excerpt_ids,
20918                buffer_ids,
20919            } => {
20920                self.display_map.update(cx, |map, cx| {
20921                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20922                });
20923                cx.emit(EditorEvent::ExcerptsEdited {
20924                    ids: excerpt_ids.clone(),
20925                });
20926            }
20927            multi_buffer::Event::ExcerptsExpanded { ids } => {
20928                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20929                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20930            }
20931            multi_buffer::Event::Reparsed(buffer_id) => {
20932                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20933                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20934
20935                cx.emit(EditorEvent::Reparsed(*buffer_id));
20936            }
20937            multi_buffer::Event::DiffHunksToggled => {
20938                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20939            }
20940            multi_buffer::Event::LanguageChanged(buffer_id) => {
20941                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20942                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20943                cx.emit(EditorEvent::Reparsed(*buffer_id));
20944                cx.notify();
20945            }
20946            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20947            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20948            multi_buffer::Event::FileHandleChanged
20949            | multi_buffer::Event::Reloaded
20950            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20951            multi_buffer::Event::DiagnosticsUpdated => {
20952                self.update_diagnostics_state(window, cx);
20953            }
20954            _ => {}
20955        };
20956    }
20957
20958    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20959        if !self.diagnostics_enabled() {
20960            return;
20961        }
20962        self.refresh_active_diagnostics(cx);
20963        self.refresh_inline_diagnostics(true, window, cx);
20964        self.scrollbar_marker_state.dirty = true;
20965        cx.notify();
20966    }
20967
20968    pub fn start_temporary_diff_override(&mut self) {
20969        self.load_diff_task.take();
20970        self.temporary_diff_override = true;
20971    }
20972
20973    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20974        self.temporary_diff_override = false;
20975        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20976        self.buffer.update(cx, |buffer, cx| {
20977            buffer.set_all_diff_hunks_collapsed(cx);
20978        });
20979
20980        if let Some(project) = self.project.clone() {
20981            self.load_diff_task = Some(
20982                update_uncommitted_diff_for_buffer(
20983                    cx.entity(),
20984                    &project,
20985                    self.buffer.read(cx).all_buffers(),
20986                    self.buffer.clone(),
20987                    cx,
20988                )
20989                .shared(),
20990            );
20991        }
20992    }
20993
20994    fn on_display_map_changed(
20995        &mut self,
20996        _: Entity<DisplayMap>,
20997        _: &mut Window,
20998        cx: &mut Context<Self>,
20999    ) {
21000        cx.notify();
21001    }
21002
21003    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21004        if self.diagnostics_enabled() {
21005            let new_severity = EditorSettings::get_global(cx)
21006                .diagnostics_max_severity
21007                .unwrap_or(DiagnosticSeverity::Hint);
21008            self.set_max_diagnostics_severity(new_severity, cx);
21009        }
21010        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21011        self.update_edit_prediction_settings(cx);
21012        self.refresh_edit_prediction(true, false, window, cx);
21013        self.refresh_inline_values(cx);
21014        self.refresh_inlay_hints(
21015            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21016                self.selections.newest_anchor().head(),
21017                &self.buffer.read(cx).snapshot(cx),
21018                cx,
21019            )),
21020            cx,
21021        );
21022
21023        let old_cursor_shape = self.cursor_shape;
21024        let old_show_breadcrumbs = self.show_breadcrumbs;
21025
21026        {
21027            let editor_settings = EditorSettings::get_global(cx);
21028            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21029            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21030            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21031            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21032        }
21033
21034        if old_cursor_shape != self.cursor_shape {
21035            cx.emit(EditorEvent::CursorShapeChanged);
21036        }
21037
21038        if old_show_breadcrumbs != self.show_breadcrumbs {
21039            cx.emit(EditorEvent::BreadcrumbsChanged);
21040        }
21041
21042        let project_settings = ProjectSettings::get_global(cx);
21043        self.serialize_dirty_buffers =
21044            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21045
21046        if self.mode.is_full() {
21047            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21048            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21049            if self.show_inline_diagnostics != show_inline_diagnostics {
21050                self.show_inline_diagnostics = show_inline_diagnostics;
21051                self.refresh_inline_diagnostics(false, window, cx);
21052            }
21053
21054            if self.git_blame_inline_enabled != inline_blame_enabled {
21055                self.toggle_git_blame_inline_internal(false, window, cx);
21056            }
21057
21058            let minimap_settings = EditorSettings::get_global(cx).minimap;
21059            if self.minimap_visibility != MinimapVisibility::Disabled {
21060                if self.minimap_visibility.settings_visibility()
21061                    != minimap_settings.minimap_enabled()
21062                {
21063                    self.set_minimap_visibility(
21064                        MinimapVisibility::for_mode(self.mode(), cx),
21065                        window,
21066                        cx,
21067                    );
21068                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21069                    minimap_entity.update(cx, |minimap_editor, cx| {
21070                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21071                    })
21072                }
21073            }
21074        }
21075
21076        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21077            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21078        }) {
21079            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21080                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21081            }
21082            self.refresh_colors(false, None, window, cx);
21083        }
21084
21085        cx.notify();
21086    }
21087
21088    pub fn set_searchable(&mut self, searchable: bool) {
21089        self.searchable = searchable;
21090    }
21091
21092    pub fn searchable(&self) -> bool {
21093        self.searchable
21094    }
21095
21096    fn open_proposed_changes_editor(
21097        &mut self,
21098        _: &OpenProposedChangesEditor,
21099        window: &mut Window,
21100        cx: &mut Context<Self>,
21101    ) {
21102        let Some(workspace) = self.workspace() else {
21103            cx.propagate();
21104            return;
21105        };
21106
21107        let selections = self.selections.all::<usize>(cx);
21108        let multi_buffer = self.buffer.read(cx);
21109        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21110        let mut new_selections_by_buffer = HashMap::default();
21111        for selection in selections {
21112            for (buffer, range, _) in
21113                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21114            {
21115                let mut range = range.to_point(buffer);
21116                range.start.column = 0;
21117                range.end.column = buffer.line_len(range.end.row);
21118                new_selections_by_buffer
21119                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21120                    .or_insert(Vec::new())
21121                    .push(range)
21122            }
21123        }
21124
21125        let proposed_changes_buffers = new_selections_by_buffer
21126            .into_iter()
21127            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21128            .collect::<Vec<_>>();
21129        let proposed_changes_editor = cx.new(|cx| {
21130            ProposedChangesEditor::new(
21131                "Proposed changes",
21132                proposed_changes_buffers,
21133                self.project.clone(),
21134                window,
21135                cx,
21136            )
21137        });
21138
21139        window.defer(cx, move |window, cx| {
21140            workspace.update(cx, |workspace, cx| {
21141                workspace.active_pane().update(cx, |pane, cx| {
21142                    pane.add_item(
21143                        Box::new(proposed_changes_editor),
21144                        true,
21145                        true,
21146                        None,
21147                        window,
21148                        cx,
21149                    );
21150                });
21151            });
21152        });
21153    }
21154
21155    pub fn open_excerpts_in_split(
21156        &mut self,
21157        _: &OpenExcerptsSplit,
21158        window: &mut Window,
21159        cx: &mut Context<Self>,
21160    ) {
21161        self.open_excerpts_common(None, true, window, cx)
21162    }
21163
21164    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21165        self.open_excerpts_common(None, false, window, cx)
21166    }
21167
21168    fn open_excerpts_common(
21169        &mut self,
21170        jump_data: Option<JumpData>,
21171        split: bool,
21172        window: &mut Window,
21173        cx: &mut Context<Self>,
21174    ) {
21175        let Some(workspace) = self.workspace() else {
21176            cx.propagate();
21177            return;
21178        };
21179
21180        if self.buffer.read(cx).is_singleton() {
21181            cx.propagate();
21182            return;
21183        }
21184
21185        let mut new_selections_by_buffer = HashMap::default();
21186        match &jump_data {
21187            Some(JumpData::MultiBufferPoint {
21188                excerpt_id,
21189                position,
21190                anchor,
21191                line_offset_from_top,
21192            }) => {
21193                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21194                if let Some(buffer) = multi_buffer_snapshot
21195                    .buffer_id_for_excerpt(*excerpt_id)
21196                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21197                {
21198                    let buffer_snapshot = buffer.read(cx).snapshot();
21199                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21200                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21201                    } else {
21202                        buffer_snapshot.clip_point(*position, Bias::Left)
21203                    };
21204                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21205                    new_selections_by_buffer.insert(
21206                        buffer,
21207                        (
21208                            vec![jump_to_offset..jump_to_offset],
21209                            Some(*line_offset_from_top),
21210                        ),
21211                    );
21212                }
21213            }
21214            Some(JumpData::MultiBufferRow {
21215                row,
21216                line_offset_from_top,
21217            }) => {
21218                let point = MultiBufferPoint::new(row.0, 0);
21219                if let Some((buffer, buffer_point, _)) =
21220                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21221                {
21222                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21223                    new_selections_by_buffer
21224                        .entry(buffer)
21225                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21226                        .0
21227                        .push(buffer_offset..buffer_offset)
21228                }
21229            }
21230            None => {
21231                let selections = self.selections.all::<usize>(cx);
21232                let multi_buffer = self.buffer.read(cx);
21233                for selection in selections {
21234                    for (snapshot, range, _, anchor) in multi_buffer
21235                        .snapshot(cx)
21236                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21237                    {
21238                        if let Some(anchor) = anchor {
21239                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21240                            else {
21241                                continue;
21242                            };
21243                            let offset = text::ToOffset::to_offset(
21244                                &anchor.text_anchor,
21245                                &buffer_handle.read(cx).snapshot(),
21246                            );
21247                            let range = offset..offset;
21248                            new_selections_by_buffer
21249                                .entry(buffer_handle)
21250                                .or_insert((Vec::new(), None))
21251                                .0
21252                                .push(range)
21253                        } else {
21254                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21255                            else {
21256                                continue;
21257                            };
21258                            new_selections_by_buffer
21259                                .entry(buffer_handle)
21260                                .or_insert((Vec::new(), None))
21261                                .0
21262                                .push(range)
21263                        }
21264                    }
21265                }
21266            }
21267        }
21268
21269        new_selections_by_buffer
21270            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21271
21272        if new_selections_by_buffer.is_empty() {
21273            return;
21274        }
21275
21276        // We defer the pane interaction because we ourselves are a workspace item
21277        // and activating a new item causes the pane to call a method on us reentrantly,
21278        // which panics if we're on the stack.
21279        window.defer(cx, move |window, cx| {
21280            workspace.update(cx, |workspace, cx| {
21281                let pane = if split {
21282                    workspace.adjacent_pane(window, cx)
21283                } else {
21284                    workspace.active_pane().clone()
21285                };
21286
21287                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21288                    let editor = buffer
21289                        .read(cx)
21290                        .file()
21291                        .is_none()
21292                        .then(|| {
21293                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21294                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21295                            // Instead, we try to activate the existing editor in the pane first.
21296                            let (editor, pane_item_index) =
21297                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21298                                    let editor = item.downcast::<Editor>()?;
21299                                    let singleton_buffer =
21300                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21301                                    if singleton_buffer == buffer {
21302                                        Some((editor, i))
21303                                    } else {
21304                                        None
21305                                    }
21306                                })?;
21307                            pane.update(cx, |pane, cx| {
21308                                pane.activate_item(pane_item_index, true, true, window, cx)
21309                            });
21310                            Some(editor)
21311                        })
21312                        .flatten()
21313                        .unwrap_or_else(|| {
21314                            workspace.open_project_item::<Self>(
21315                                pane.clone(),
21316                                buffer,
21317                                true,
21318                                true,
21319                                window,
21320                                cx,
21321                            )
21322                        });
21323
21324                    editor.update(cx, |editor, cx| {
21325                        let autoscroll = match scroll_offset {
21326                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21327                            None => Autoscroll::newest(),
21328                        };
21329                        let nav_history = editor.nav_history.take();
21330                        editor.change_selections(
21331                            SelectionEffects::scroll(autoscroll),
21332                            window,
21333                            cx,
21334                            |s| {
21335                                s.select_ranges(ranges);
21336                            },
21337                        );
21338                        editor.nav_history = nav_history;
21339                    });
21340                }
21341            })
21342        });
21343    }
21344
21345    // For now, don't allow opening excerpts in buffers that aren't backed by
21346    // regular project files.
21347    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21348        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21349    }
21350
21351    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21352        let snapshot = self.buffer.read(cx).read(cx);
21353        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21354        Some(
21355            ranges
21356                .iter()
21357                .map(move |range| {
21358                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21359                })
21360                .collect(),
21361        )
21362    }
21363
21364    fn selection_replacement_ranges(
21365        &self,
21366        range: Range<OffsetUtf16>,
21367        cx: &mut App,
21368    ) -> Vec<Range<OffsetUtf16>> {
21369        let selections = self.selections.all::<OffsetUtf16>(cx);
21370        let newest_selection = selections
21371            .iter()
21372            .max_by_key(|selection| selection.id)
21373            .unwrap();
21374        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21375        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21376        let snapshot = self.buffer.read(cx).read(cx);
21377        selections
21378            .into_iter()
21379            .map(|mut selection| {
21380                selection.start.0 =
21381                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21382                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21383                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21384                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21385            })
21386            .collect()
21387    }
21388
21389    fn report_editor_event(
21390        &self,
21391        reported_event: ReportEditorEvent,
21392        file_extension: Option<String>,
21393        cx: &App,
21394    ) {
21395        if cfg!(any(test, feature = "test-support")) {
21396            return;
21397        }
21398
21399        let Some(project) = &self.project else { return };
21400
21401        // If None, we are in a file without an extension
21402        let file = self
21403            .buffer
21404            .read(cx)
21405            .as_singleton()
21406            .and_then(|b| b.read(cx).file());
21407        let file_extension = file_extension.or(file
21408            .as_ref()
21409            .and_then(|file| Path::new(file.file_name(cx)).extension())
21410            .and_then(|e| e.to_str())
21411            .map(|a| a.to_string()));
21412
21413        let vim_mode = vim_enabled(cx);
21414
21415        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21416        let copilot_enabled = edit_predictions_provider
21417            == language::language_settings::EditPredictionProvider::Copilot;
21418        let copilot_enabled_for_language = self
21419            .buffer
21420            .read(cx)
21421            .language_settings(cx)
21422            .show_edit_predictions;
21423
21424        let project = project.read(cx);
21425        let event_type = reported_event.event_type();
21426
21427        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21428            telemetry::event!(
21429                event_type,
21430                type = if auto_saved {"autosave"} else {"manual"},
21431                file_extension,
21432                vim_mode,
21433                copilot_enabled,
21434                copilot_enabled_for_language,
21435                edit_predictions_provider,
21436                is_via_ssh = project.is_via_remote_server(),
21437            );
21438        } else {
21439            telemetry::event!(
21440                event_type,
21441                file_extension,
21442                vim_mode,
21443                copilot_enabled,
21444                copilot_enabled_for_language,
21445                edit_predictions_provider,
21446                is_via_ssh = project.is_via_remote_server(),
21447            );
21448        };
21449    }
21450
21451    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21452    /// with each line being an array of {text, highlight} objects.
21453    fn copy_highlight_json(
21454        &mut self,
21455        _: &CopyHighlightJson,
21456        window: &mut Window,
21457        cx: &mut Context<Self>,
21458    ) {
21459        #[derive(Serialize)]
21460        struct Chunk<'a> {
21461            text: String,
21462            highlight: Option<&'a str>,
21463        }
21464
21465        let snapshot = self.buffer.read(cx).snapshot(cx);
21466        let range = self
21467            .selected_text_range(false, window, cx)
21468            .and_then(|selection| {
21469                if selection.range.is_empty() {
21470                    None
21471                } else {
21472                    Some(selection.range)
21473                }
21474            })
21475            .unwrap_or_else(|| 0..snapshot.len());
21476
21477        let chunks = snapshot.chunks(range, true);
21478        let mut lines = Vec::new();
21479        let mut line: VecDeque<Chunk> = VecDeque::new();
21480
21481        let Some(style) = self.style.as_ref() else {
21482            return;
21483        };
21484
21485        for chunk in chunks {
21486            let highlight = chunk
21487                .syntax_highlight_id
21488                .and_then(|id| id.name(&style.syntax));
21489            let mut chunk_lines = chunk.text.split('\n').peekable();
21490            while let Some(text) = chunk_lines.next() {
21491                let mut merged_with_last_token = false;
21492                if let Some(last_token) = line.back_mut()
21493                    && last_token.highlight == highlight
21494                {
21495                    last_token.text.push_str(text);
21496                    merged_with_last_token = true;
21497                }
21498
21499                if !merged_with_last_token {
21500                    line.push_back(Chunk {
21501                        text: text.into(),
21502                        highlight,
21503                    });
21504                }
21505
21506                if chunk_lines.peek().is_some() {
21507                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21508                        line.pop_front();
21509                    }
21510                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21511                        line.pop_back();
21512                    }
21513
21514                    lines.push(mem::take(&mut line));
21515                }
21516            }
21517        }
21518
21519        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21520            return;
21521        };
21522        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21523    }
21524
21525    pub fn open_context_menu(
21526        &mut self,
21527        _: &OpenContextMenu,
21528        window: &mut Window,
21529        cx: &mut Context<Self>,
21530    ) {
21531        self.request_autoscroll(Autoscroll::newest(), cx);
21532        let position = self.selections.newest_display(cx).start;
21533        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21534    }
21535
21536    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21537        &self.inlay_hint_cache
21538    }
21539
21540    pub fn replay_insert_event(
21541        &mut self,
21542        text: &str,
21543        relative_utf16_range: Option<Range<isize>>,
21544        window: &mut Window,
21545        cx: &mut Context<Self>,
21546    ) {
21547        if !self.input_enabled {
21548            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21549            return;
21550        }
21551        if let Some(relative_utf16_range) = relative_utf16_range {
21552            let selections = self.selections.all::<OffsetUtf16>(cx);
21553            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21554                let new_ranges = selections.into_iter().map(|range| {
21555                    let start = OffsetUtf16(
21556                        range
21557                            .head()
21558                            .0
21559                            .saturating_add_signed(relative_utf16_range.start),
21560                    );
21561                    let end = OffsetUtf16(
21562                        range
21563                            .head()
21564                            .0
21565                            .saturating_add_signed(relative_utf16_range.end),
21566                    );
21567                    start..end
21568                });
21569                s.select_ranges(new_ranges);
21570            });
21571        }
21572
21573        self.handle_input(text, window, cx);
21574    }
21575
21576    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21577        let Some(provider) = self.semantics_provider.as_ref() else {
21578            return false;
21579        };
21580
21581        let mut supports = false;
21582        self.buffer().update(cx, |this, cx| {
21583            this.for_each_buffer(|buffer| {
21584                supports |= provider.supports_inlay_hints(buffer, cx);
21585            });
21586        });
21587
21588        supports
21589    }
21590
21591    pub fn is_focused(&self, window: &Window) -> bool {
21592        self.focus_handle.is_focused(window)
21593    }
21594
21595    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21596        cx.emit(EditorEvent::Focused);
21597
21598        if let Some(descendant) = self
21599            .last_focused_descendant
21600            .take()
21601            .and_then(|descendant| descendant.upgrade())
21602        {
21603            window.focus(&descendant);
21604        } else {
21605            if let Some(blame) = self.blame.as_ref() {
21606                blame.update(cx, GitBlame::focus)
21607            }
21608
21609            self.blink_manager.update(cx, BlinkManager::enable);
21610            self.show_cursor_names(window, cx);
21611            self.buffer.update(cx, |buffer, cx| {
21612                buffer.finalize_last_transaction(cx);
21613                if self.leader_id.is_none() {
21614                    buffer.set_active_selections(
21615                        &self.selections.disjoint_anchors_arc(),
21616                        self.selections.line_mode(),
21617                        self.cursor_shape,
21618                        cx,
21619                    );
21620                }
21621            });
21622        }
21623    }
21624
21625    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21626        cx.emit(EditorEvent::FocusedIn)
21627    }
21628
21629    fn handle_focus_out(
21630        &mut self,
21631        event: FocusOutEvent,
21632        _window: &mut Window,
21633        cx: &mut Context<Self>,
21634    ) {
21635        if event.blurred != self.focus_handle {
21636            self.last_focused_descendant = Some(event.blurred);
21637        }
21638        self.selection_drag_state = SelectionDragState::None;
21639        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21640    }
21641
21642    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21643        self.blink_manager.update(cx, BlinkManager::disable);
21644        self.buffer
21645            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21646
21647        if let Some(blame) = self.blame.as_ref() {
21648            blame.update(cx, GitBlame::blur)
21649        }
21650        if !self.hover_state.focused(window, cx) {
21651            hide_hover(self, cx);
21652        }
21653        if !self
21654            .context_menu
21655            .borrow()
21656            .as_ref()
21657            .is_some_and(|context_menu| context_menu.focused(window, cx))
21658        {
21659            self.hide_context_menu(window, cx);
21660        }
21661        self.take_active_edit_prediction(cx);
21662        cx.emit(EditorEvent::Blurred);
21663        cx.notify();
21664    }
21665
21666    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21667        let mut pending: String = window
21668            .pending_input_keystrokes()
21669            .into_iter()
21670            .flatten()
21671            .filter_map(|keystroke| {
21672                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21673                    keystroke.key_char.clone()
21674                } else {
21675                    None
21676                }
21677            })
21678            .collect();
21679
21680        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21681            pending = "".to_string();
21682        }
21683
21684        let existing_pending = self
21685            .text_highlights::<PendingInput>(cx)
21686            .map(|(_, ranges)| ranges.to_vec());
21687        if existing_pending.is_none() && pending.is_empty() {
21688            return;
21689        }
21690        let transaction =
21691            self.transact(window, cx, |this, window, cx| {
21692                let selections = this.selections.all::<usize>(cx);
21693                let edits = selections
21694                    .iter()
21695                    .map(|selection| (selection.end..selection.end, pending.clone()));
21696                this.edit(edits, cx);
21697                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21698                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21699                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21700                    }));
21701                });
21702                if let Some(existing_ranges) = existing_pending {
21703                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21704                    this.edit(edits, cx);
21705                }
21706            });
21707
21708        let snapshot = self.snapshot(window, cx);
21709        let ranges = self
21710            .selections
21711            .all::<usize>(cx)
21712            .into_iter()
21713            .map(|selection| {
21714                snapshot.buffer_snapshot().anchor_after(selection.end)
21715                    ..snapshot
21716                        .buffer_snapshot()
21717                        .anchor_before(selection.end + pending.len())
21718            })
21719            .collect();
21720
21721        if pending.is_empty() {
21722            self.clear_highlights::<PendingInput>(cx);
21723        } else {
21724            self.highlight_text::<PendingInput>(
21725                ranges,
21726                HighlightStyle {
21727                    underline: Some(UnderlineStyle {
21728                        thickness: px(1.),
21729                        color: None,
21730                        wavy: false,
21731                    }),
21732                    ..Default::default()
21733                },
21734                cx,
21735            );
21736        }
21737
21738        self.ime_transaction = self.ime_transaction.or(transaction);
21739        if let Some(transaction) = self.ime_transaction {
21740            self.buffer.update(cx, |buffer, cx| {
21741                buffer.group_until_transaction(transaction, cx);
21742            });
21743        }
21744
21745        if self.text_highlights::<PendingInput>(cx).is_none() {
21746            self.ime_transaction.take();
21747        }
21748    }
21749
21750    pub fn register_action_renderer(
21751        &mut self,
21752        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21753    ) -> Subscription {
21754        let id = self.next_editor_action_id.post_inc();
21755        self.editor_actions
21756            .borrow_mut()
21757            .insert(id, Box::new(listener));
21758
21759        let editor_actions = self.editor_actions.clone();
21760        Subscription::new(move || {
21761            editor_actions.borrow_mut().remove(&id);
21762        })
21763    }
21764
21765    pub fn register_action<A: Action>(
21766        &mut self,
21767        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21768    ) -> Subscription {
21769        let id = self.next_editor_action_id.post_inc();
21770        let listener = Arc::new(listener);
21771        self.editor_actions.borrow_mut().insert(
21772            id,
21773            Box::new(move |_, window, _| {
21774                let listener = listener.clone();
21775                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21776                    let action = action.downcast_ref().unwrap();
21777                    if phase == DispatchPhase::Bubble {
21778                        listener(action, window, cx)
21779                    }
21780                })
21781            }),
21782        );
21783
21784        let editor_actions = self.editor_actions.clone();
21785        Subscription::new(move || {
21786            editor_actions.borrow_mut().remove(&id);
21787        })
21788    }
21789
21790    pub fn file_header_size(&self) -> u32 {
21791        FILE_HEADER_HEIGHT
21792    }
21793
21794    pub fn restore(
21795        &mut self,
21796        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21797        window: &mut Window,
21798        cx: &mut Context<Self>,
21799    ) {
21800        let workspace = self.workspace();
21801        let project = self.project();
21802        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21803            let mut tasks = Vec::new();
21804            for (buffer_id, changes) in revert_changes {
21805                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21806                    buffer.update(cx, |buffer, cx| {
21807                        buffer.edit(
21808                            changes
21809                                .into_iter()
21810                                .map(|(range, text)| (range, text.to_string())),
21811                            None,
21812                            cx,
21813                        );
21814                    });
21815
21816                    if let Some(project) =
21817                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21818                    {
21819                        project.update(cx, |project, cx| {
21820                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21821                        })
21822                    }
21823                }
21824            }
21825            tasks
21826        });
21827        cx.spawn_in(window, async move |_, cx| {
21828            for (buffer, task) in save_tasks {
21829                let result = task.await;
21830                if result.is_err() {
21831                    let Some(path) = buffer
21832                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21833                        .ok()
21834                    else {
21835                        continue;
21836                    };
21837                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21838                        let Some(task) = cx
21839                            .update_window_entity(workspace, |workspace, window, cx| {
21840                                workspace
21841                                    .open_path_preview(path, None, false, false, false, window, cx)
21842                            })
21843                            .ok()
21844                        else {
21845                            continue;
21846                        };
21847                        task.await.log_err();
21848                    }
21849                }
21850            }
21851        })
21852        .detach();
21853        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21854            selections.refresh()
21855        });
21856    }
21857
21858    pub fn to_pixel_point(
21859        &self,
21860        source: multi_buffer::Anchor,
21861        editor_snapshot: &EditorSnapshot,
21862        window: &mut Window,
21863    ) -> Option<gpui::Point<Pixels>> {
21864        let source_point = source.to_display_point(editor_snapshot);
21865        self.display_to_pixel_point(source_point, editor_snapshot, window)
21866    }
21867
21868    pub fn display_to_pixel_point(
21869        &self,
21870        source: DisplayPoint,
21871        editor_snapshot: &EditorSnapshot,
21872        window: &mut Window,
21873    ) -> Option<gpui::Point<Pixels>> {
21874        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21875        let text_layout_details = self.text_layout_details(window);
21876        let scroll_top = text_layout_details
21877            .scroll_anchor
21878            .scroll_position(editor_snapshot)
21879            .y;
21880
21881        if source.row().as_f64() < scroll_top.floor() {
21882            return None;
21883        }
21884        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21885        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21886        Some(gpui::Point::new(source_x, source_y))
21887    }
21888
21889    pub fn has_visible_completions_menu(&self) -> bool {
21890        !self.edit_prediction_preview_is_active()
21891            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21892                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21893            })
21894    }
21895
21896    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21897        if self.mode.is_minimap() {
21898            return;
21899        }
21900        self.addons
21901            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21902    }
21903
21904    pub fn unregister_addon<T: Addon>(&mut self) {
21905        self.addons.remove(&std::any::TypeId::of::<T>());
21906    }
21907
21908    pub fn addon<T: Addon>(&self) -> Option<&T> {
21909        let type_id = std::any::TypeId::of::<T>();
21910        self.addons
21911            .get(&type_id)
21912            .and_then(|item| item.to_any().downcast_ref::<T>())
21913    }
21914
21915    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21916        let type_id = std::any::TypeId::of::<T>();
21917        self.addons
21918            .get_mut(&type_id)
21919            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21920    }
21921
21922    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21923        let text_layout_details = self.text_layout_details(window);
21924        let style = &text_layout_details.editor_style;
21925        let font_id = window.text_system().resolve_font(&style.text.font());
21926        let font_size = style.text.font_size.to_pixels(window.rem_size());
21927        let line_height = style.text.line_height_in_pixels(window.rem_size());
21928        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21929        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21930
21931        CharacterDimensions {
21932            em_width,
21933            em_advance,
21934            line_height,
21935        }
21936    }
21937
21938    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21939        self.load_diff_task.clone()
21940    }
21941
21942    fn read_metadata_from_db(
21943        &mut self,
21944        item_id: u64,
21945        workspace_id: WorkspaceId,
21946        window: &mut Window,
21947        cx: &mut Context<Editor>,
21948    ) {
21949        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21950            && !self.mode.is_minimap()
21951            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21952        {
21953            let buffer_snapshot = OnceCell::new();
21954
21955            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21956                && !folds.is_empty()
21957            {
21958                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21959                self.fold_ranges(
21960                    folds
21961                        .into_iter()
21962                        .map(|(start, end)| {
21963                            snapshot.clip_offset(start, Bias::Left)
21964                                ..snapshot.clip_offset(end, Bias::Right)
21965                        })
21966                        .collect(),
21967                    false,
21968                    window,
21969                    cx,
21970                );
21971            }
21972
21973            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21974                && !selections.is_empty()
21975            {
21976                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21977                // skip adding the initial selection to selection history
21978                self.selection_history.mode = SelectionHistoryMode::Skipping;
21979                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21980                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21981                        snapshot.clip_offset(start, Bias::Left)
21982                            ..snapshot.clip_offset(end, Bias::Right)
21983                    }));
21984                });
21985                self.selection_history.mode = SelectionHistoryMode::Normal;
21986            };
21987        }
21988
21989        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21990    }
21991
21992    fn update_lsp_data(
21993        &mut self,
21994        ignore_cache: bool,
21995        for_buffer: Option<BufferId>,
21996        window: &mut Window,
21997        cx: &mut Context<'_, Self>,
21998    ) {
21999        self.pull_diagnostics(for_buffer, window, cx);
22000        self.refresh_colors(ignore_cache, for_buffer, window, cx);
22001    }
22002}
22003
22004fn edit_for_markdown_paste<'a>(
22005    buffer: &MultiBufferSnapshot,
22006    range: Range<usize>,
22007    to_insert: &'a str,
22008    url: Option<url::Url>,
22009) -> (Range<usize>, Cow<'a, str>) {
22010    if url.is_none() {
22011        return (range, Cow::Borrowed(to_insert));
22012    };
22013
22014    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22015
22016    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22017        Cow::Borrowed(to_insert)
22018    } else {
22019        Cow::Owned(format!("[{old_text}]({to_insert})"))
22020    };
22021    (range, new_text)
22022}
22023
22024fn vim_enabled(cx: &App) -> bool {
22025    vim_mode_setting::VimModeSetting::try_get(cx)
22026        .map(|vim_mode| vim_mode.0)
22027        .unwrap_or(false)
22028}
22029
22030fn process_completion_for_edit(
22031    completion: &Completion,
22032    intent: CompletionIntent,
22033    buffer: &Entity<Buffer>,
22034    cursor_position: &text::Anchor,
22035    cx: &mut Context<Editor>,
22036) -> CompletionEdit {
22037    let buffer = buffer.read(cx);
22038    let buffer_snapshot = buffer.snapshot();
22039    let (snippet, new_text) = if completion.is_snippet() {
22040        let mut snippet_source = completion.new_text.clone();
22041        // Workaround for typescript language server issues so that methods don't expand within
22042        // strings and functions with type expressions. The previous point is used because the query
22043        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22044        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22045        let previous_point = if previous_point.column > 0 {
22046            cursor_position.to_previous_offset(&buffer_snapshot)
22047        } else {
22048            cursor_position.to_offset(&buffer_snapshot)
22049        };
22050        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22051            && scope.prefers_label_for_snippet_in_completion()
22052            && let Some(label) = completion.label()
22053            && matches!(
22054                completion.kind(),
22055                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22056            )
22057        {
22058            snippet_source = label;
22059        }
22060        match Snippet::parse(&snippet_source).log_err() {
22061            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22062            None => (None, completion.new_text.clone()),
22063        }
22064    } else {
22065        (None, completion.new_text.clone())
22066    };
22067
22068    let mut range_to_replace = {
22069        let replace_range = &completion.replace_range;
22070        if let CompletionSource::Lsp {
22071            insert_range: Some(insert_range),
22072            ..
22073        } = &completion.source
22074        {
22075            debug_assert_eq!(
22076                insert_range.start, replace_range.start,
22077                "insert_range and replace_range should start at the same position"
22078            );
22079            debug_assert!(
22080                insert_range
22081                    .start
22082                    .cmp(cursor_position, &buffer_snapshot)
22083                    .is_le(),
22084                "insert_range should start before or at cursor position"
22085            );
22086            debug_assert!(
22087                replace_range
22088                    .start
22089                    .cmp(cursor_position, &buffer_snapshot)
22090                    .is_le(),
22091                "replace_range should start before or at cursor position"
22092            );
22093
22094            let should_replace = match intent {
22095                CompletionIntent::CompleteWithInsert => false,
22096                CompletionIntent::CompleteWithReplace => true,
22097                CompletionIntent::Complete | CompletionIntent::Compose => {
22098                    let insert_mode =
22099                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22100                            .completions
22101                            .lsp_insert_mode;
22102                    match insert_mode {
22103                        LspInsertMode::Insert => false,
22104                        LspInsertMode::Replace => true,
22105                        LspInsertMode::ReplaceSubsequence => {
22106                            let mut text_to_replace = buffer.chars_for_range(
22107                                buffer.anchor_before(replace_range.start)
22108                                    ..buffer.anchor_after(replace_range.end),
22109                            );
22110                            let mut current_needle = text_to_replace.next();
22111                            for haystack_ch in completion.label.text.chars() {
22112                                if let Some(needle_ch) = current_needle
22113                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22114                                {
22115                                    current_needle = text_to_replace.next();
22116                                }
22117                            }
22118                            current_needle.is_none()
22119                        }
22120                        LspInsertMode::ReplaceSuffix => {
22121                            if replace_range
22122                                .end
22123                                .cmp(cursor_position, &buffer_snapshot)
22124                                .is_gt()
22125                            {
22126                                let range_after_cursor = *cursor_position..replace_range.end;
22127                                let text_after_cursor = buffer
22128                                    .text_for_range(
22129                                        buffer.anchor_before(range_after_cursor.start)
22130                                            ..buffer.anchor_after(range_after_cursor.end),
22131                                    )
22132                                    .collect::<String>()
22133                                    .to_ascii_lowercase();
22134                                completion
22135                                    .label
22136                                    .text
22137                                    .to_ascii_lowercase()
22138                                    .ends_with(&text_after_cursor)
22139                            } else {
22140                                true
22141                            }
22142                        }
22143                    }
22144                }
22145            };
22146
22147            if should_replace {
22148                replace_range.clone()
22149            } else {
22150                insert_range.clone()
22151            }
22152        } else {
22153            replace_range.clone()
22154        }
22155    };
22156
22157    if range_to_replace
22158        .end
22159        .cmp(cursor_position, &buffer_snapshot)
22160        .is_lt()
22161    {
22162        range_to_replace.end = *cursor_position;
22163    }
22164
22165    CompletionEdit {
22166        new_text,
22167        replace_range: range_to_replace.to_offset(buffer),
22168        snippet,
22169    }
22170}
22171
22172struct CompletionEdit {
22173    new_text: String,
22174    replace_range: Range<usize>,
22175    snippet: Option<Snippet>,
22176}
22177
22178fn insert_extra_newline_brackets(
22179    buffer: &MultiBufferSnapshot,
22180    range: Range<usize>,
22181    language: &language::LanguageScope,
22182) -> bool {
22183    let leading_whitespace_len = buffer
22184        .reversed_chars_at(range.start)
22185        .take_while(|c| c.is_whitespace() && *c != '\n')
22186        .map(|c| c.len_utf8())
22187        .sum::<usize>();
22188    let trailing_whitespace_len = buffer
22189        .chars_at(range.end)
22190        .take_while(|c| c.is_whitespace() && *c != '\n')
22191        .map(|c| c.len_utf8())
22192        .sum::<usize>();
22193    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22194
22195    language.brackets().any(|(pair, enabled)| {
22196        let pair_start = pair.start.trim_end();
22197        let pair_end = pair.end.trim_start();
22198
22199        enabled
22200            && pair.newline
22201            && buffer.contains_str_at(range.end, pair_end)
22202            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22203    })
22204}
22205
22206fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22207    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22208        [(buffer, range, _)] => (*buffer, range.clone()),
22209        _ => return false,
22210    };
22211    let pair = {
22212        let mut result: Option<BracketMatch> = None;
22213
22214        for pair in buffer
22215            .all_bracket_ranges(range.clone())
22216            .filter(move |pair| {
22217                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22218            })
22219        {
22220            let len = pair.close_range.end - pair.open_range.start;
22221
22222            if let Some(existing) = &result {
22223                let existing_len = existing.close_range.end - existing.open_range.start;
22224                if len > existing_len {
22225                    continue;
22226                }
22227            }
22228
22229            result = Some(pair);
22230        }
22231
22232        result
22233    };
22234    let Some(pair) = pair else {
22235        return false;
22236    };
22237    pair.newline_only
22238        && buffer
22239            .chars_for_range(pair.open_range.end..range.start)
22240            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22241            .all(|c| c.is_whitespace() && c != '\n')
22242}
22243
22244fn update_uncommitted_diff_for_buffer(
22245    editor: Entity<Editor>,
22246    project: &Entity<Project>,
22247    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22248    buffer: Entity<MultiBuffer>,
22249    cx: &mut App,
22250) -> Task<()> {
22251    let mut tasks = Vec::new();
22252    project.update(cx, |project, cx| {
22253        for buffer in buffers {
22254            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22255                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22256            }
22257        }
22258    });
22259    cx.spawn(async move |cx| {
22260        let diffs = future::join_all(tasks).await;
22261        if editor
22262            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22263            .unwrap_or(false)
22264        {
22265            return;
22266        }
22267
22268        buffer
22269            .update(cx, |buffer, cx| {
22270                for diff in diffs.into_iter().flatten() {
22271                    buffer.add_diff(diff, cx);
22272                }
22273            })
22274            .ok();
22275    })
22276}
22277
22278fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22279    let tab_size = tab_size.get() as usize;
22280    let mut width = offset;
22281
22282    for ch in text.chars() {
22283        width += if ch == '\t' {
22284            tab_size - (width % tab_size)
22285        } else {
22286            1
22287        };
22288    }
22289
22290    width - offset
22291}
22292
22293#[cfg(test)]
22294mod tests {
22295    use super::*;
22296
22297    #[test]
22298    fn test_string_size_with_expanded_tabs() {
22299        let nz = |val| NonZeroU32::new(val).unwrap();
22300        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22301        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22302        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22303        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22304        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22305        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22306        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22307        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22308    }
22309}
22310
22311/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22312struct WordBreakingTokenizer<'a> {
22313    input: &'a str,
22314}
22315
22316impl<'a> WordBreakingTokenizer<'a> {
22317    fn new(input: &'a str) -> Self {
22318        Self { input }
22319    }
22320}
22321
22322fn is_char_ideographic(ch: char) -> bool {
22323    use unicode_script::Script::*;
22324    use unicode_script::UnicodeScript;
22325    matches!(ch.script(), Han | Tangut | Yi)
22326}
22327
22328fn is_grapheme_ideographic(text: &str) -> bool {
22329    text.chars().any(is_char_ideographic)
22330}
22331
22332fn is_grapheme_whitespace(text: &str) -> bool {
22333    text.chars().any(|x| x.is_whitespace())
22334}
22335
22336fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22337    text.chars()
22338        .next()
22339        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22340}
22341
22342#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22343enum WordBreakToken<'a> {
22344    Word { token: &'a str, grapheme_len: usize },
22345    InlineWhitespace { token: &'a str, grapheme_len: usize },
22346    Newline,
22347}
22348
22349impl<'a> Iterator for WordBreakingTokenizer<'a> {
22350    /// Yields a span, the count of graphemes in the token, and whether it was
22351    /// whitespace. Note that it also breaks at word boundaries.
22352    type Item = WordBreakToken<'a>;
22353
22354    fn next(&mut self) -> Option<Self::Item> {
22355        use unicode_segmentation::UnicodeSegmentation;
22356        if self.input.is_empty() {
22357            return None;
22358        }
22359
22360        let mut iter = self.input.graphemes(true).peekable();
22361        let mut offset = 0;
22362        let mut grapheme_len = 0;
22363        if let Some(first_grapheme) = iter.next() {
22364            let is_newline = first_grapheme == "\n";
22365            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22366            offset += first_grapheme.len();
22367            grapheme_len += 1;
22368            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22369                if let Some(grapheme) = iter.peek().copied()
22370                    && should_stay_with_preceding_ideograph(grapheme)
22371                {
22372                    offset += grapheme.len();
22373                    grapheme_len += 1;
22374                }
22375            } else {
22376                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22377                let mut next_word_bound = words.peek().copied();
22378                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22379                    next_word_bound = words.next();
22380                }
22381                while let Some(grapheme) = iter.peek().copied() {
22382                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22383                        break;
22384                    };
22385                    if is_grapheme_whitespace(grapheme) != is_whitespace
22386                        || (grapheme == "\n") != is_newline
22387                    {
22388                        break;
22389                    };
22390                    offset += grapheme.len();
22391                    grapheme_len += 1;
22392                    iter.next();
22393                }
22394            }
22395            let token = &self.input[..offset];
22396            self.input = &self.input[offset..];
22397            if token == "\n" {
22398                Some(WordBreakToken::Newline)
22399            } else if is_whitespace {
22400                Some(WordBreakToken::InlineWhitespace {
22401                    token,
22402                    grapheme_len,
22403                })
22404            } else {
22405                Some(WordBreakToken::Word {
22406                    token,
22407                    grapheme_len,
22408                })
22409            }
22410        } else {
22411            None
22412        }
22413    }
22414}
22415
22416#[test]
22417fn test_word_breaking_tokenizer() {
22418    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22419        ("", &[]),
22420        ("  ", &[whitespace("  ", 2)]),
22421        ("Ʒ", &[word("Ʒ", 1)]),
22422        ("Ǽ", &[word("Ǽ", 1)]),
22423        ("", &[word("", 1)]),
22424        ("⋑⋑", &[word("⋑⋑", 2)]),
22425        (
22426            "原理,进而",
22427            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22428        ),
22429        (
22430            "hello world",
22431            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22432        ),
22433        (
22434            "hello, world",
22435            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22436        ),
22437        (
22438            "  hello world",
22439            &[
22440                whitespace("  ", 2),
22441                word("hello", 5),
22442                whitespace(" ", 1),
22443                word("world", 5),
22444            ],
22445        ),
22446        (
22447            "这是什么 \n 钢笔",
22448            &[
22449                word("", 1),
22450                word("", 1),
22451                word("", 1),
22452                word("", 1),
22453                whitespace(" ", 1),
22454                newline(),
22455                whitespace(" ", 1),
22456                word("", 1),
22457                word("", 1),
22458            ],
22459        ),
22460        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22461    ];
22462
22463    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22464        WordBreakToken::Word {
22465            token,
22466            grapheme_len,
22467        }
22468    }
22469
22470    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22471        WordBreakToken::InlineWhitespace {
22472            token,
22473            grapheme_len,
22474        }
22475    }
22476
22477    fn newline() -> WordBreakToken<'static> {
22478        WordBreakToken::Newline
22479    }
22480
22481    for (input, result) in tests {
22482        assert_eq!(
22483            WordBreakingTokenizer::new(input)
22484                .collect::<Vec<_>>()
22485                .as_slice(),
22486            *result,
22487        );
22488    }
22489}
22490
22491fn wrap_with_prefix(
22492    first_line_prefix: String,
22493    subsequent_lines_prefix: String,
22494    unwrapped_text: String,
22495    wrap_column: usize,
22496    tab_size: NonZeroU32,
22497    preserve_existing_whitespace: bool,
22498) -> String {
22499    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22500    let subsequent_lines_prefix_len =
22501        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22502    let mut wrapped_text = String::new();
22503    let mut current_line = first_line_prefix;
22504    let mut is_first_line = true;
22505
22506    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22507    let mut current_line_len = first_line_prefix_len;
22508    let mut in_whitespace = false;
22509    for token in tokenizer {
22510        let have_preceding_whitespace = in_whitespace;
22511        match token {
22512            WordBreakToken::Word {
22513                token,
22514                grapheme_len,
22515            } => {
22516                in_whitespace = false;
22517                let current_prefix_len = if is_first_line {
22518                    first_line_prefix_len
22519                } else {
22520                    subsequent_lines_prefix_len
22521                };
22522                if current_line_len + grapheme_len > wrap_column
22523                    && current_line_len != current_prefix_len
22524                {
22525                    wrapped_text.push_str(current_line.trim_end());
22526                    wrapped_text.push('\n');
22527                    is_first_line = false;
22528                    current_line = subsequent_lines_prefix.clone();
22529                    current_line_len = subsequent_lines_prefix_len;
22530                }
22531                current_line.push_str(token);
22532                current_line_len += grapheme_len;
22533            }
22534            WordBreakToken::InlineWhitespace {
22535                mut token,
22536                mut grapheme_len,
22537            } => {
22538                in_whitespace = true;
22539                if have_preceding_whitespace && !preserve_existing_whitespace {
22540                    continue;
22541                }
22542                if !preserve_existing_whitespace {
22543                    // Keep a single whitespace grapheme as-is
22544                    if let Some(first) =
22545                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22546                    {
22547                        token = first;
22548                    } else {
22549                        token = " ";
22550                    }
22551                    grapheme_len = 1;
22552                }
22553                let current_prefix_len = if is_first_line {
22554                    first_line_prefix_len
22555                } else {
22556                    subsequent_lines_prefix_len
22557                };
22558                if current_line_len + grapheme_len > wrap_column {
22559                    wrapped_text.push_str(current_line.trim_end());
22560                    wrapped_text.push('\n');
22561                    is_first_line = false;
22562                    current_line = subsequent_lines_prefix.clone();
22563                    current_line_len = subsequent_lines_prefix_len;
22564                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22565                    current_line.push_str(token);
22566                    current_line_len += grapheme_len;
22567                }
22568            }
22569            WordBreakToken::Newline => {
22570                in_whitespace = true;
22571                let current_prefix_len = if is_first_line {
22572                    first_line_prefix_len
22573                } else {
22574                    subsequent_lines_prefix_len
22575                };
22576                if preserve_existing_whitespace {
22577                    wrapped_text.push_str(current_line.trim_end());
22578                    wrapped_text.push('\n');
22579                    is_first_line = false;
22580                    current_line = subsequent_lines_prefix.clone();
22581                    current_line_len = subsequent_lines_prefix_len;
22582                } else if have_preceding_whitespace {
22583                    continue;
22584                } else if current_line_len + 1 > wrap_column
22585                    && current_line_len != current_prefix_len
22586                {
22587                    wrapped_text.push_str(current_line.trim_end());
22588                    wrapped_text.push('\n');
22589                    is_first_line = false;
22590                    current_line = subsequent_lines_prefix.clone();
22591                    current_line_len = subsequent_lines_prefix_len;
22592                } else if current_line_len != current_prefix_len {
22593                    current_line.push(' ');
22594                    current_line_len += 1;
22595                }
22596            }
22597        }
22598    }
22599
22600    if !current_line.is_empty() {
22601        wrapped_text.push_str(&current_line);
22602    }
22603    wrapped_text
22604}
22605
22606#[test]
22607fn test_wrap_with_prefix() {
22608    assert_eq!(
22609        wrap_with_prefix(
22610            "# ".to_string(),
22611            "# ".to_string(),
22612            "abcdefg".to_string(),
22613            4,
22614            NonZeroU32::new(4).unwrap(),
22615            false,
22616        ),
22617        "# abcdefg"
22618    );
22619    assert_eq!(
22620        wrap_with_prefix(
22621            "".to_string(),
22622            "".to_string(),
22623            "\thello world".to_string(),
22624            8,
22625            NonZeroU32::new(4).unwrap(),
22626            false,
22627        ),
22628        "hello\nworld"
22629    );
22630    assert_eq!(
22631        wrap_with_prefix(
22632            "// ".to_string(),
22633            "// ".to_string(),
22634            "xx \nyy zz aa bb cc".to_string(),
22635            12,
22636            NonZeroU32::new(4).unwrap(),
22637            false,
22638        ),
22639        "// xx yy zz\n// aa bb cc"
22640    );
22641    assert_eq!(
22642        wrap_with_prefix(
22643            String::new(),
22644            String::new(),
22645            "这是什么 \n 钢笔".to_string(),
22646            3,
22647            NonZeroU32::new(4).unwrap(),
22648            false,
22649        ),
22650        "这是什\n么 钢\n"
22651    );
22652    assert_eq!(
22653        wrap_with_prefix(
22654            String::new(),
22655            String::new(),
22656            format!("foo{}bar", '\u{2009}'), // thin space
22657            80,
22658            NonZeroU32::new(4).unwrap(),
22659            false,
22660        ),
22661        format!("foo{}bar", '\u{2009}')
22662    );
22663}
22664
22665pub trait CollaborationHub {
22666    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22667    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22668    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22669}
22670
22671impl CollaborationHub for Entity<Project> {
22672    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22673        self.read(cx).collaborators()
22674    }
22675
22676    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22677        self.read(cx).user_store().read(cx).participant_indices()
22678    }
22679
22680    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22681        let this = self.read(cx);
22682        let user_ids = this.collaborators().values().map(|c| c.user_id);
22683        this.user_store().read(cx).participant_names(user_ids, cx)
22684    }
22685}
22686
22687pub trait SemanticsProvider {
22688    fn hover(
22689        &self,
22690        buffer: &Entity<Buffer>,
22691        position: text::Anchor,
22692        cx: &mut App,
22693    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22694
22695    fn inline_values(
22696        &self,
22697        buffer_handle: Entity<Buffer>,
22698        range: Range<text::Anchor>,
22699        cx: &mut App,
22700    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22701
22702    fn inlay_hints(
22703        &self,
22704        buffer_handle: Entity<Buffer>,
22705        range: Range<text::Anchor>,
22706        cx: &mut App,
22707    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22708
22709    fn resolve_inlay_hint(
22710        &self,
22711        hint: InlayHint,
22712        buffer_handle: Entity<Buffer>,
22713        server_id: LanguageServerId,
22714        cx: &mut App,
22715    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22716
22717    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22718
22719    fn document_highlights(
22720        &self,
22721        buffer: &Entity<Buffer>,
22722        position: text::Anchor,
22723        cx: &mut App,
22724    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22725
22726    fn definitions(
22727        &self,
22728        buffer: &Entity<Buffer>,
22729        position: text::Anchor,
22730        kind: GotoDefinitionKind,
22731        cx: &mut App,
22732    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22733
22734    fn range_for_rename(
22735        &self,
22736        buffer: &Entity<Buffer>,
22737        position: text::Anchor,
22738        cx: &mut App,
22739    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22740
22741    fn perform_rename(
22742        &self,
22743        buffer: &Entity<Buffer>,
22744        position: text::Anchor,
22745        new_name: String,
22746        cx: &mut App,
22747    ) -> Option<Task<Result<ProjectTransaction>>>;
22748}
22749
22750pub trait CompletionProvider {
22751    fn completions(
22752        &self,
22753        excerpt_id: ExcerptId,
22754        buffer: &Entity<Buffer>,
22755        buffer_position: text::Anchor,
22756        trigger: CompletionContext,
22757        window: &mut Window,
22758        cx: &mut Context<Editor>,
22759    ) -> Task<Result<Vec<CompletionResponse>>>;
22760
22761    fn resolve_completions(
22762        &self,
22763        _buffer: Entity<Buffer>,
22764        _completion_indices: Vec<usize>,
22765        _completions: Rc<RefCell<Box<[Completion]>>>,
22766        _cx: &mut Context<Editor>,
22767    ) -> Task<Result<bool>> {
22768        Task::ready(Ok(false))
22769    }
22770
22771    fn apply_additional_edits_for_completion(
22772        &self,
22773        _buffer: Entity<Buffer>,
22774        _completions: Rc<RefCell<Box<[Completion]>>>,
22775        _completion_index: usize,
22776        _push_to_history: bool,
22777        _cx: &mut Context<Editor>,
22778    ) -> Task<Result<Option<language::Transaction>>> {
22779        Task::ready(Ok(None))
22780    }
22781
22782    fn is_completion_trigger(
22783        &self,
22784        buffer: &Entity<Buffer>,
22785        position: language::Anchor,
22786        text: &str,
22787        trigger_in_words: bool,
22788        menu_is_open: bool,
22789        cx: &mut Context<Editor>,
22790    ) -> bool;
22791
22792    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22793
22794    fn sort_completions(&self) -> bool {
22795        true
22796    }
22797
22798    fn filter_completions(&self) -> bool {
22799        true
22800    }
22801}
22802
22803pub trait CodeActionProvider {
22804    fn id(&self) -> Arc<str>;
22805
22806    fn code_actions(
22807        &self,
22808        buffer: &Entity<Buffer>,
22809        range: Range<text::Anchor>,
22810        window: &mut Window,
22811        cx: &mut App,
22812    ) -> Task<Result<Vec<CodeAction>>>;
22813
22814    fn apply_code_action(
22815        &self,
22816        buffer_handle: Entity<Buffer>,
22817        action: CodeAction,
22818        excerpt_id: ExcerptId,
22819        push_to_history: bool,
22820        window: &mut Window,
22821        cx: &mut App,
22822    ) -> Task<Result<ProjectTransaction>>;
22823}
22824
22825impl CodeActionProvider for Entity<Project> {
22826    fn id(&self) -> Arc<str> {
22827        "project".into()
22828    }
22829
22830    fn code_actions(
22831        &self,
22832        buffer: &Entity<Buffer>,
22833        range: Range<text::Anchor>,
22834        _window: &mut Window,
22835        cx: &mut App,
22836    ) -> Task<Result<Vec<CodeAction>>> {
22837        self.update(cx, |project, cx| {
22838            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22839            let code_actions = project.code_actions(buffer, range, None, cx);
22840            cx.background_spawn(async move {
22841                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22842                Ok(code_lens_actions
22843                    .context("code lens fetch")?
22844                    .into_iter()
22845                    .flatten()
22846                    .chain(
22847                        code_actions
22848                            .context("code action fetch")?
22849                            .into_iter()
22850                            .flatten(),
22851                    )
22852                    .collect())
22853            })
22854        })
22855    }
22856
22857    fn apply_code_action(
22858        &self,
22859        buffer_handle: Entity<Buffer>,
22860        action: CodeAction,
22861        _excerpt_id: ExcerptId,
22862        push_to_history: bool,
22863        _window: &mut Window,
22864        cx: &mut App,
22865    ) -> Task<Result<ProjectTransaction>> {
22866        self.update(cx, |project, cx| {
22867            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22868        })
22869    }
22870}
22871
22872fn snippet_completions(
22873    project: &Project,
22874    buffer: &Entity<Buffer>,
22875    buffer_position: text::Anchor,
22876    cx: &mut App,
22877) -> Task<Result<CompletionResponse>> {
22878    let languages = buffer.read(cx).languages_at(buffer_position);
22879    let snippet_store = project.snippets().read(cx);
22880
22881    let scopes: Vec<_> = languages
22882        .iter()
22883        .filter_map(|language| {
22884            let language_name = language.lsp_id();
22885            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22886
22887            if snippets.is_empty() {
22888                None
22889            } else {
22890                Some((language.default_scope(), snippets))
22891            }
22892        })
22893        .collect();
22894
22895    if scopes.is_empty() {
22896        return Task::ready(Ok(CompletionResponse {
22897            completions: vec![],
22898            display_options: CompletionDisplayOptions::default(),
22899            is_incomplete: false,
22900        }));
22901    }
22902
22903    let snapshot = buffer.read(cx).text_snapshot();
22904    let executor = cx.background_executor().clone();
22905
22906    cx.background_spawn(async move {
22907        let mut is_incomplete = false;
22908        let mut completions: Vec<Completion> = Vec::new();
22909        for (scope, snippets) in scopes.into_iter() {
22910            let classifier =
22911                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22912
22913            const MAX_WORD_PREFIX_LEN: usize = 128;
22914            let last_word: String = snapshot
22915                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22916                .take(MAX_WORD_PREFIX_LEN)
22917                .take_while(|c| classifier.is_word(*c))
22918                .collect::<String>()
22919                .chars()
22920                .rev()
22921                .collect();
22922
22923            if last_word.is_empty() {
22924                return Ok(CompletionResponse {
22925                    completions: vec![],
22926                    display_options: CompletionDisplayOptions::default(),
22927                    is_incomplete: true,
22928                });
22929            }
22930
22931            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22932            let to_lsp = |point: &text::Anchor| {
22933                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22934                point_to_lsp(end)
22935            };
22936            let lsp_end = to_lsp(&buffer_position);
22937
22938            let candidates = snippets
22939                .iter()
22940                .enumerate()
22941                .flat_map(|(ix, snippet)| {
22942                    snippet
22943                        .prefix
22944                        .iter()
22945                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22946                })
22947                .collect::<Vec<StringMatchCandidate>>();
22948
22949            const MAX_RESULTS: usize = 100;
22950            let mut matches = fuzzy::match_strings(
22951                &candidates,
22952                &last_word,
22953                last_word.chars().any(|c| c.is_uppercase()),
22954                true,
22955                MAX_RESULTS,
22956                &Default::default(),
22957                executor.clone(),
22958            )
22959            .await;
22960
22961            if matches.len() >= MAX_RESULTS {
22962                is_incomplete = true;
22963            }
22964
22965            // Remove all candidates where the query's start does not match the start of any word in the candidate
22966            if let Some(query_start) = last_word.chars().next() {
22967                matches.retain(|string_match| {
22968                    split_words(&string_match.string).any(|word| {
22969                        // Check that the first codepoint of the word as lowercase matches the first
22970                        // codepoint of the query as lowercase
22971                        word.chars()
22972                            .flat_map(|codepoint| codepoint.to_lowercase())
22973                            .zip(query_start.to_lowercase())
22974                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22975                    })
22976                });
22977            }
22978
22979            let matched_strings = matches
22980                .into_iter()
22981                .map(|m| m.string)
22982                .collect::<HashSet<_>>();
22983
22984            completions.extend(snippets.iter().filter_map(|snippet| {
22985                let matching_prefix = snippet
22986                    .prefix
22987                    .iter()
22988                    .find(|prefix| matched_strings.contains(*prefix))?;
22989                let start = as_offset - last_word.len();
22990                let start = snapshot.anchor_before(start);
22991                let range = start..buffer_position;
22992                let lsp_start = to_lsp(&start);
22993                let lsp_range = lsp::Range {
22994                    start: lsp_start,
22995                    end: lsp_end,
22996                };
22997                Some(Completion {
22998                    replace_range: range,
22999                    new_text: snippet.body.clone(),
23000                    source: CompletionSource::Lsp {
23001                        insert_range: None,
23002                        server_id: LanguageServerId(usize::MAX),
23003                        resolved: true,
23004                        lsp_completion: Box::new(lsp::CompletionItem {
23005                            label: snippet.prefix.first().unwrap().clone(),
23006                            kind: Some(CompletionItemKind::SNIPPET),
23007                            label_details: snippet.description.as_ref().map(|description| {
23008                                lsp::CompletionItemLabelDetails {
23009                                    detail: Some(description.clone()),
23010                                    description: None,
23011                                }
23012                            }),
23013                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23014                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23015                                lsp::InsertReplaceEdit {
23016                                    new_text: snippet.body.clone(),
23017                                    insert: lsp_range,
23018                                    replace: lsp_range,
23019                                },
23020                            )),
23021                            filter_text: Some(snippet.body.clone()),
23022                            sort_text: Some(char::MAX.to_string()),
23023                            ..lsp::CompletionItem::default()
23024                        }),
23025                        lsp_defaults: None,
23026                    },
23027                    label: CodeLabel {
23028                        text: matching_prefix.clone(),
23029                        runs: Vec::new(),
23030                        filter_range: 0..matching_prefix.len(),
23031                    },
23032                    icon_path: None,
23033                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23034                        single_line: snippet.name.clone().into(),
23035                        plain_text: snippet
23036                            .description
23037                            .clone()
23038                            .map(|description| description.into()),
23039                    }),
23040                    insert_text_mode: None,
23041                    confirm: None,
23042                })
23043            }))
23044        }
23045
23046        Ok(CompletionResponse {
23047            completions,
23048            display_options: CompletionDisplayOptions::default(),
23049            is_incomplete,
23050        })
23051    })
23052}
23053
23054impl CompletionProvider for Entity<Project> {
23055    fn completions(
23056        &self,
23057        _excerpt_id: ExcerptId,
23058        buffer: &Entity<Buffer>,
23059        buffer_position: text::Anchor,
23060        options: CompletionContext,
23061        _window: &mut Window,
23062        cx: &mut Context<Editor>,
23063    ) -> Task<Result<Vec<CompletionResponse>>> {
23064        self.update(cx, |project, cx| {
23065            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23066            let project_completions = project.completions(buffer, buffer_position, options, cx);
23067            cx.background_spawn(async move {
23068                let mut responses = project_completions.await?;
23069                let snippets = snippets.await?;
23070                if !snippets.completions.is_empty() {
23071                    responses.push(snippets);
23072                }
23073                Ok(responses)
23074            })
23075        })
23076    }
23077
23078    fn resolve_completions(
23079        &self,
23080        buffer: Entity<Buffer>,
23081        completion_indices: Vec<usize>,
23082        completions: Rc<RefCell<Box<[Completion]>>>,
23083        cx: &mut Context<Editor>,
23084    ) -> Task<Result<bool>> {
23085        self.update(cx, |project, cx| {
23086            project.lsp_store().update(cx, |lsp_store, cx| {
23087                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23088            })
23089        })
23090    }
23091
23092    fn apply_additional_edits_for_completion(
23093        &self,
23094        buffer: Entity<Buffer>,
23095        completions: Rc<RefCell<Box<[Completion]>>>,
23096        completion_index: usize,
23097        push_to_history: bool,
23098        cx: &mut Context<Editor>,
23099    ) -> Task<Result<Option<language::Transaction>>> {
23100        self.update(cx, |project, cx| {
23101            project.lsp_store().update(cx, |lsp_store, cx| {
23102                lsp_store.apply_additional_edits_for_completion(
23103                    buffer,
23104                    completions,
23105                    completion_index,
23106                    push_to_history,
23107                    cx,
23108                )
23109            })
23110        })
23111    }
23112
23113    fn is_completion_trigger(
23114        &self,
23115        buffer: &Entity<Buffer>,
23116        position: language::Anchor,
23117        text: &str,
23118        trigger_in_words: bool,
23119        menu_is_open: bool,
23120        cx: &mut Context<Editor>,
23121    ) -> bool {
23122        let mut chars = text.chars();
23123        let char = if let Some(char) = chars.next() {
23124            char
23125        } else {
23126            return false;
23127        };
23128        if chars.next().is_some() {
23129            return false;
23130        }
23131
23132        let buffer = buffer.read(cx);
23133        let snapshot = buffer.snapshot();
23134        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23135            return false;
23136        }
23137        let classifier = snapshot
23138            .char_classifier_at(position)
23139            .scope_context(Some(CharScopeContext::Completion));
23140        if trigger_in_words && classifier.is_word(char) {
23141            return true;
23142        }
23143
23144        buffer.completion_triggers().contains(text)
23145    }
23146}
23147
23148impl SemanticsProvider for Entity<Project> {
23149    fn hover(
23150        &self,
23151        buffer: &Entity<Buffer>,
23152        position: text::Anchor,
23153        cx: &mut App,
23154    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23155        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23156    }
23157
23158    fn document_highlights(
23159        &self,
23160        buffer: &Entity<Buffer>,
23161        position: text::Anchor,
23162        cx: &mut App,
23163    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23164        Some(self.update(cx, |project, cx| {
23165            project.document_highlights(buffer, position, cx)
23166        }))
23167    }
23168
23169    fn definitions(
23170        &self,
23171        buffer: &Entity<Buffer>,
23172        position: text::Anchor,
23173        kind: GotoDefinitionKind,
23174        cx: &mut App,
23175    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23176        Some(self.update(cx, |project, cx| match kind {
23177            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23178            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23179            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23180            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23181        }))
23182    }
23183
23184    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23185        self.update(cx, |project, cx| {
23186            if project
23187                .active_debug_session(cx)
23188                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23189            {
23190                return true;
23191            }
23192
23193            buffer.update(cx, |buffer, cx| {
23194                project.any_language_server_supports_inlay_hints(buffer, cx)
23195            })
23196        })
23197    }
23198
23199    fn inline_values(
23200        &self,
23201        buffer_handle: Entity<Buffer>,
23202        range: Range<text::Anchor>,
23203        cx: &mut App,
23204    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23205        self.update(cx, |project, cx| {
23206            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23207
23208            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23209        })
23210    }
23211
23212    fn inlay_hints(
23213        &self,
23214        buffer_handle: Entity<Buffer>,
23215        range: Range<text::Anchor>,
23216        cx: &mut App,
23217    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23218        Some(self.update(cx, |project, cx| {
23219            project.inlay_hints(buffer_handle, range, cx)
23220        }))
23221    }
23222
23223    fn resolve_inlay_hint(
23224        &self,
23225        hint: InlayHint,
23226        buffer_handle: Entity<Buffer>,
23227        server_id: LanguageServerId,
23228        cx: &mut App,
23229    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23230        Some(self.update(cx, |project, cx| {
23231            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23232        }))
23233    }
23234
23235    fn range_for_rename(
23236        &self,
23237        buffer: &Entity<Buffer>,
23238        position: text::Anchor,
23239        cx: &mut App,
23240    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23241        Some(self.update(cx, |project, cx| {
23242            let buffer = buffer.clone();
23243            let task = project.prepare_rename(buffer.clone(), position, cx);
23244            cx.spawn(async move |_, cx| {
23245                Ok(match task.await? {
23246                    PrepareRenameResponse::Success(range) => Some(range),
23247                    PrepareRenameResponse::InvalidPosition => None,
23248                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23249                        // Fallback on using TreeSitter info to determine identifier range
23250                        buffer.read_with(cx, |buffer, _| {
23251                            let snapshot = buffer.snapshot();
23252                            let (range, kind) = snapshot.surrounding_word(position, None);
23253                            if kind != Some(CharKind::Word) {
23254                                return None;
23255                            }
23256                            Some(
23257                                snapshot.anchor_before(range.start)
23258                                    ..snapshot.anchor_after(range.end),
23259                            )
23260                        })?
23261                    }
23262                })
23263            })
23264        }))
23265    }
23266
23267    fn perform_rename(
23268        &self,
23269        buffer: &Entity<Buffer>,
23270        position: text::Anchor,
23271        new_name: String,
23272        cx: &mut App,
23273    ) -> Option<Task<Result<ProjectTransaction>>> {
23274        Some(self.update(cx, |project, cx| {
23275            project.perform_rename(buffer.clone(), position, new_name, cx)
23276        }))
23277    }
23278}
23279
23280fn inlay_hint_settings(
23281    location: Anchor,
23282    snapshot: &MultiBufferSnapshot,
23283    cx: &mut Context<Editor>,
23284) -> InlayHintSettings {
23285    let file = snapshot.file_at(location);
23286    let language = snapshot.language_at(location).map(|l| l.name());
23287    language_settings(language, file, cx).inlay_hints
23288}
23289
23290fn consume_contiguous_rows(
23291    contiguous_row_selections: &mut Vec<Selection<Point>>,
23292    selection: &Selection<Point>,
23293    display_map: &DisplaySnapshot,
23294    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23295) -> (MultiBufferRow, MultiBufferRow) {
23296    contiguous_row_selections.push(selection.clone());
23297    let start_row = starting_row(selection, display_map);
23298    let mut end_row = ending_row(selection, display_map);
23299
23300    while let Some(next_selection) = selections.peek() {
23301        if next_selection.start.row <= end_row.0 {
23302            end_row = ending_row(next_selection, display_map);
23303            contiguous_row_selections.push(selections.next().unwrap().clone());
23304        } else {
23305            break;
23306        }
23307    }
23308    (start_row, end_row)
23309}
23310
23311fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23312    if selection.start.column > 0 {
23313        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23314    } else {
23315        MultiBufferRow(selection.start.row)
23316    }
23317}
23318
23319fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23320    if next_selection.end.column > 0 || next_selection.is_empty() {
23321        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23322    } else {
23323        MultiBufferRow(next_selection.end.row)
23324    }
23325}
23326
23327impl EditorSnapshot {
23328    pub fn remote_selections_in_range<'a>(
23329        &'a self,
23330        range: &'a Range<Anchor>,
23331        collaboration_hub: &dyn CollaborationHub,
23332        cx: &'a App,
23333    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23334        let participant_names = collaboration_hub.user_names(cx);
23335        let participant_indices = collaboration_hub.user_participant_indices(cx);
23336        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23337        let collaborators_by_replica_id = collaborators_by_peer_id
23338            .values()
23339            .map(|collaborator| (collaborator.replica_id, collaborator))
23340            .collect::<HashMap<_, _>>();
23341        self.buffer_snapshot()
23342            .selections_in_range(range, false)
23343            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23344                if replica_id == AGENT_REPLICA_ID {
23345                    Some(RemoteSelection {
23346                        replica_id,
23347                        selection,
23348                        cursor_shape,
23349                        line_mode,
23350                        collaborator_id: CollaboratorId::Agent,
23351                        user_name: Some("Agent".into()),
23352                        color: cx.theme().players().agent(),
23353                    })
23354                } else {
23355                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23356                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23357                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23358                    Some(RemoteSelection {
23359                        replica_id,
23360                        selection,
23361                        cursor_shape,
23362                        line_mode,
23363                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23364                        user_name,
23365                        color: if let Some(index) = participant_index {
23366                            cx.theme().players().color_for_participant(index.0)
23367                        } else {
23368                            cx.theme().players().absent()
23369                        },
23370                    })
23371                }
23372            })
23373    }
23374
23375    pub fn hunks_for_ranges(
23376        &self,
23377        ranges: impl IntoIterator<Item = Range<Point>>,
23378    ) -> Vec<MultiBufferDiffHunk> {
23379        let mut hunks = Vec::new();
23380        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23381            HashMap::default();
23382        for query_range in ranges {
23383            let query_rows =
23384                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23385            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23386                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23387            ) {
23388                // Include deleted hunks that are adjacent to the query range, because
23389                // otherwise they would be missed.
23390                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23391                if hunk.status().is_deleted() {
23392                    intersects_range |= hunk.row_range.start == query_rows.end;
23393                    intersects_range |= hunk.row_range.end == query_rows.start;
23394                }
23395                if intersects_range {
23396                    if !processed_buffer_rows
23397                        .entry(hunk.buffer_id)
23398                        .or_default()
23399                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23400                    {
23401                        continue;
23402                    }
23403                    hunks.push(hunk);
23404                }
23405            }
23406        }
23407
23408        hunks
23409    }
23410
23411    fn display_diff_hunks_for_rows<'a>(
23412        &'a self,
23413        display_rows: Range<DisplayRow>,
23414        folded_buffers: &'a HashSet<BufferId>,
23415    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23416        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23417        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23418
23419        self.buffer_snapshot()
23420            .diff_hunks_in_range(buffer_start..buffer_end)
23421            .filter_map(|hunk| {
23422                if folded_buffers.contains(&hunk.buffer_id) {
23423                    return None;
23424                }
23425
23426                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23427                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23428
23429                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23430                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23431
23432                let display_hunk = if hunk_display_start.column() != 0 {
23433                    DisplayDiffHunk::Folded {
23434                        display_row: hunk_display_start.row(),
23435                    }
23436                } else {
23437                    let mut end_row = hunk_display_end.row();
23438                    if hunk_display_end.column() > 0 {
23439                        end_row.0 += 1;
23440                    }
23441                    let is_created_file = hunk.is_created_file();
23442                    DisplayDiffHunk::Unfolded {
23443                        status: hunk.status(),
23444                        diff_base_byte_range: hunk.diff_base_byte_range,
23445                        display_row_range: hunk_display_start.row()..end_row,
23446                        multi_buffer_range: Anchor::range_in_buffer(
23447                            hunk.excerpt_id,
23448                            hunk.buffer_id,
23449                            hunk.buffer_range,
23450                        ),
23451                        is_created_file,
23452                    }
23453                };
23454
23455                Some(display_hunk)
23456            })
23457    }
23458
23459    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23460        self.display_snapshot
23461            .buffer_snapshot()
23462            .language_at(position)
23463    }
23464
23465    pub fn is_focused(&self) -> bool {
23466        self.is_focused
23467    }
23468
23469    pub fn placeholder_text(&self) -> Option<String> {
23470        self.placeholder_display_snapshot
23471            .as_ref()
23472            .map(|display_map| display_map.text())
23473    }
23474
23475    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23476        self.scroll_anchor.scroll_position(&self.display_snapshot)
23477    }
23478
23479    fn gutter_dimensions(
23480        &self,
23481        font_id: FontId,
23482        font_size: Pixels,
23483        max_line_number_width: Pixels,
23484        cx: &App,
23485    ) -> Option<GutterDimensions> {
23486        if !self.show_gutter {
23487            return None;
23488        }
23489
23490        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23491        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23492
23493        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23494            matches!(
23495                ProjectSettings::get_global(cx).git.git_gutter,
23496                GitGutterSetting::TrackedFiles
23497            )
23498        });
23499        let gutter_settings = EditorSettings::get_global(cx).gutter;
23500        let show_line_numbers = self
23501            .show_line_numbers
23502            .unwrap_or(gutter_settings.line_numbers);
23503        let line_gutter_width = if show_line_numbers {
23504            // Avoid flicker-like gutter resizes when the line number gains another digit by
23505            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23506            let min_width_for_number_on_gutter =
23507                ch_advance * gutter_settings.min_line_number_digits as f32;
23508            max_line_number_width.max(min_width_for_number_on_gutter)
23509        } else {
23510            0.0.into()
23511        };
23512
23513        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23514        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23515
23516        let git_blame_entries_width =
23517            self.git_blame_gutter_max_author_length
23518                .map(|max_author_length| {
23519                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23520                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23521
23522                    /// The number of characters to dedicate to gaps and margins.
23523                    const SPACING_WIDTH: usize = 4;
23524
23525                    let max_char_count = max_author_length.min(renderer.max_author_length())
23526                        + ::git::SHORT_SHA_LENGTH
23527                        + MAX_RELATIVE_TIMESTAMP.len()
23528                        + SPACING_WIDTH;
23529
23530                    ch_advance * max_char_count
23531                });
23532
23533        let is_singleton = self.buffer_snapshot().is_singleton();
23534
23535        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23536        left_padding += if !is_singleton {
23537            ch_width * 4.0
23538        } else if show_runnables || show_breakpoints {
23539            ch_width * 3.0
23540        } else if show_git_gutter && show_line_numbers {
23541            ch_width * 2.0
23542        } else if show_git_gutter || show_line_numbers {
23543            ch_width
23544        } else {
23545            px(0.)
23546        };
23547
23548        let shows_folds = is_singleton && gutter_settings.folds;
23549
23550        let right_padding = if shows_folds && show_line_numbers {
23551            ch_width * 4.0
23552        } else if shows_folds || (!is_singleton && show_line_numbers) {
23553            ch_width * 3.0
23554        } else if show_line_numbers {
23555            ch_width
23556        } else {
23557            px(0.)
23558        };
23559
23560        Some(GutterDimensions {
23561            left_padding,
23562            right_padding,
23563            width: line_gutter_width + left_padding + right_padding,
23564            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23565            git_blame_entries_width,
23566        })
23567    }
23568
23569    pub fn render_crease_toggle(
23570        &self,
23571        buffer_row: MultiBufferRow,
23572        row_contains_cursor: bool,
23573        editor: Entity<Editor>,
23574        window: &mut Window,
23575        cx: &mut App,
23576    ) -> Option<AnyElement> {
23577        let folded = self.is_line_folded(buffer_row);
23578        let mut is_foldable = false;
23579
23580        if let Some(crease) = self
23581            .crease_snapshot
23582            .query_row(buffer_row, self.buffer_snapshot())
23583        {
23584            is_foldable = true;
23585            match crease {
23586                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23587                    if let Some(render_toggle) = render_toggle {
23588                        let toggle_callback =
23589                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23590                                if folded {
23591                                    editor.update(cx, |editor, cx| {
23592                                        editor.fold_at(buffer_row, window, cx)
23593                                    });
23594                                } else {
23595                                    editor.update(cx, |editor, cx| {
23596                                        editor.unfold_at(buffer_row, window, cx)
23597                                    });
23598                                }
23599                            });
23600                        return Some((render_toggle)(
23601                            buffer_row,
23602                            folded,
23603                            toggle_callback,
23604                            window,
23605                            cx,
23606                        ));
23607                    }
23608                }
23609            }
23610        }
23611
23612        is_foldable |= self.starts_indent(buffer_row);
23613
23614        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23615            Some(
23616                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23617                    .toggle_state(folded)
23618                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23619                        if folded {
23620                            this.unfold_at(buffer_row, window, cx);
23621                        } else {
23622                            this.fold_at(buffer_row, window, cx);
23623                        }
23624                    }))
23625                    .into_any_element(),
23626            )
23627        } else {
23628            None
23629        }
23630    }
23631
23632    pub fn render_crease_trailer(
23633        &self,
23634        buffer_row: MultiBufferRow,
23635        window: &mut Window,
23636        cx: &mut App,
23637    ) -> Option<AnyElement> {
23638        let folded = self.is_line_folded(buffer_row);
23639        if let Crease::Inline { render_trailer, .. } = self
23640            .crease_snapshot
23641            .query_row(buffer_row, self.buffer_snapshot())?
23642        {
23643            let render_trailer = render_trailer.as_ref()?;
23644            Some(render_trailer(buffer_row, folded, window, cx))
23645        } else {
23646            None
23647        }
23648    }
23649}
23650
23651impl Deref for EditorSnapshot {
23652    type Target = DisplaySnapshot;
23653
23654    fn deref(&self) -> &Self::Target {
23655        &self.display_snapshot
23656    }
23657}
23658
23659#[derive(Clone, Debug, PartialEq, Eq)]
23660pub enum EditorEvent {
23661    InputIgnored {
23662        text: Arc<str>,
23663    },
23664    InputHandled {
23665        utf16_range_to_replace: Option<Range<isize>>,
23666        text: Arc<str>,
23667    },
23668    ExcerptsAdded {
23669        buffer: Entity<Buffer>,
23670        predecessor: ExcerptId,
23671        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23672    },
23673    ExcerptsRemoved {
23674        ids: Vec<ExcerptId>,
23675        removed_buffer_ids: Vec<BufferId>,
23676    },
23677    BufferFoldToggled {
23678        ids: Vec<ExcerptId>,
23679        folded: bool,
23680    },
23681    ExcerptsEdited {
23682        ids: Vec<ExcerptId>,
23683    },
23684    ExcerptsExpanded {
23685        ids: Vec<ExcerptId>,
23686    },
23687    BufferEdited,
23688    Edited {
23689        transaction_id: clock::Lamport,
23690    },
23691    Reparsed(BufferId),
23692    Focused,
23693    FocusedIn,
23694    Blurred,
23695    DirtyChanged,
23696    Saved,
23697    TitleChanged,
23698    SelectionsChanged {
23699        local: bool,
23700    },
23701    ScrollPositionChanged {
23702        local: bool,
23703        autoscroll: bool,
23704    },
23705    TransactionUndone {
23706        transaction_id: clock::Lamport,
23707    },
23708    TransactionBegun {
23709        transaction_id: clock::Lamport,
23710    },
23711    CursorShapeChanged,
23712    BreadcrumbsChanged,
23713    PushedToNavHistory {
23714        anchor: Anchor,
23715        is_deactivate: bool,
23716    },
23717}
23718
23719impl EventEmitter<EditorEvent> for Editor {}
23720
23721impl Focusable for Editor {
23722    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23723        self.focus_handle.clone()
23724    }
23725}
23726
23727impl Render for Editor {
23728    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23729        let settings = ThemeSettings::get_global(cx);
23730
23731        let mut text_style = match self.mode {
23732            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23733                color: cx.theme().colors().editor_foreground,
23734                font_family: settings.ui_font.family.clone(),
23735                font_features: settings.ui_font.features.clone(),
23736                font_fallbacks: settings.ui_font.fallbacks.clone(),
23737                font_size: rems(0.875).into(),
23738                font_weight: settings.ui_font.weight,
23739                line_height: relative(settings.buffer_line_height.value()),
23740                ..Default::default()
23741            },
23742            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23743                color: cx.theme().colors().editor_foreground,
23744                font_family: settings.buffer_font.family.clone(),
23745                font_features: settings.buffer_font.features.clone(),
23746                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23747                font_size: settings.buffer_font_size(cx).into(),
23748                font_weight: settings.buffer_font.weight,
23749                line_height: relative(settings.buffer_line_height.value()),
23750                ..Default::default()
23751            },
23752        };
23753        if let Some(text_style_refinement) = &self.text_style_refinement {
23754            text_style.refine(text_style_refinement)
23755        }
23756
23757        let background = match self.mode {
23758            EditorMode::SingleLine => cx.theme().system().transparent,
23759            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23760            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23761            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23762        };
23763
23764        EditorElement::new(
23765            &cx.entity(),
23766            EditorStyle {
23767                background,
23768                border: cx.theme().colors().border,
23769                local_player: cx.theme().players().local(),
23770                text: text_style,
23771                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23772                syntax: cx.theme().syntax().clone(),
23773                status: cx.theme().status().clone(),
23774                inlay_hints_style: make_inlay_hints_style(cx),
23775                edit_prediction_styles: make_suggestion_styles(cx),
23776                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23777                show_underlines: self.diagnostics_enabled(),
23778            },
23779        )
23780    }
23781}
23782
23783impl EntityInputHandler for Editor {
23784    fn text_for_range(
23785        &mut self,
23786        range_utf16: Range<usize>,
23787        adjusted_range: &mut Option<Range<usize>>,
23788        _: &mut Window,
23789        cx: &mut Context<Self>,
23790    ) -> Option<String> {
23791        let snapshot = self.buffer.read(cx).read(cx);
23792        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23793        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23794        if (start.0..end.0) != range_utf16 {
23795            adjusted_range.replace(start.0..end.0);
23796        }
23797        Some(snapshot.text_for_range(start..end).collect())
23798    }
23799
23800    fn selected_text_range(
23801        &mut self,
23802        ignore_disabled_input: bool,
23803        _: &mut Window,
23804        cx: &mut Context<Self>,
23805    ) -> Option<UTF16Selection> {
23806        // Prevent the IME menu from appearing when holding down an alphabetic key
23807        // while input is disabled.
23808        if !ignore_disabled_input && !self.input_enabled {
23809            return None;
23810        }
23811
23812        let selection = self.selections.newest::<OffsetUtf16>(cx);
23813        let range = selection.range();
23814
23815        Some(UTF16Selection {
23816            range: range.start.0..range.end.0,
23817            reversed: selection.reversed,
23818        })
23819    }
23820
23821    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23822        let snapshot = self.buffer.read(cx).read(cx);
23823        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23824        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23825    }
23826
23827    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23828        self.clear_highlights::<InputComposition>(cx);
23829        self.ime_transaction.take();
23830    }
23831
23832    fn replace_text_in_range(
23833        &mut self,
23834        range_utf16: Option<Range<usize>>,
23835        text: &str,
23836        window: &mut Window,
23837        cx: &mut Context<Self>,
23838    ) {
23839        if !self.input_enabled {
23840            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23841            return;
23842        }
23843
23844        self.transact(window, cx, |this, window, cx| {
23845            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23846                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23847                Some(this.selection_replacement_ranges(range_utf16, cx))
23848            } else {
23849                this.marked_text_ranges(cx)
23850            };
23851
23852            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23853                let newest_selection_id = this.selections.newest_anchor().id;
23854                this.selections
23855                    .all::<OffsetUtf16>(cx)
23856                    .iter()
23857                    .zip(ranges_to_replace.iter())
23858                    .find_map(|(selection, range)| {
23859                        if selection.id == newest_selection_id {
23860                            Some(
23861                                (range.start.0 as isize - selection.head().0 as isize)
23862                                    ..(range.end.0 as isize - selection.head().0 as isize),
23863                            )
23864                        } else {
23865                            None
23866                        }
23867                    })
23868            });
23869
23870            cx.emit(EditorEvent::InputHandled {
23871                utf16_range_to_replace: range_to_replace,
23872                text: text.into(),
23873            });
23874
23875            if let Some(new_selected_ranges) = new_selected_ranges {
23876                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23877                    selections.select_ranges(new_selected_ranges)
23878                });
23879                this.backspace(&Default::default(), window, cx);
23880            }
23881
23882            this.handle_input(text, window, cx);
23883        });
23884
23885        if let Some(transaction) = self.ime_transaction {
23886            self.buffer.update(cx, |buffer, cx| {
23887                buffer.group_until_transaction(transaction, cx);
23888            });
23889        }
23890
23891        self.unmark_text(window, cx);
23892    }
23893
23894    fn replace_and_mark_text_in_range(
23895        &mut self,
23896        range_utf16: Option<Range<usize>>,
23897        text: &str,
23898        new_selected_range_utf16: Option<Range<usize>>,
23899        window: &mut Window,
23900        cx: &mut Context<Self>,
23901    ) {
23902        if !self.input_enabled {
23903            return;
23904        }
23905
23906        let transaction = self.transact(window, cx, |this, window, cx| {
23907            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23908                let snapshot = this.buffer.read(cx).read(cx);
23909                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23910                    for marked_range in &mut marked_ranges {
23911                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23912                        marked_range.start.0 += relative_range_utf16.start;
23913                        marked_range.start =
23914                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23915                        marked_range.end =
23916                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23917                    }
23918                }
23919                Some(marked_ranges)
23920            } else if let Some(range_utf16) = range_utf16 {
23921                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23922                Some(this.selection_replacement_ranges(range_utf16, cx))
23923            } else {
23924                None
23925            };
23926
23927            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23928                let newest_selection_id = this.selections.newest_anchor().id;
23929                this.selections
23930                    .all::<OffsetUtf16>(cx)
23931                    .iter()
23932                    .zip(ranges_to_replace.iter())
23933                    .find_map(|(selection, range)| {
23934                        if selection.id == newest_selection_id {
23935                            Some(
23936                                (range.start.0 as isize - selection.head().0 as isize)
23937                                    ..(range.end.0 as isize - selection.head().0 as isize),
23938                            )
23939                        } else {
23940                            None
23941                        }
23942                    })
23943            });
23944
23945            cx.emit(EditorEvent::InputHandled {
23946                utf16_range_to_replace: range_to_replace,
23947                text: text.into(),
23948            });
23949
23950            if let Some(ranges) = ranges_to_replace {
23951                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23952                    s.select_ranges(ranges)
23953                });
23954            }
23955
23956            let marked_ranges = {
23957                let snapshot = this.buffer.read(cx).read(cx);
23958                this.selections
23959                    .disjoint_anchors_arc()
23960                    .iter()
23961                    .map(|selection| {
23962                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23963                    })
23964                    .collect::<Vec<_>>()
23965            };
23966
23967            if text.is_empty() {
23968                this.unmark_text(window, cx);
23969            } else {
23970                this.highlight_text::<InputComposition>(
23971                    marked_ranges.clone(),
23972                    HighlightStyle {
23973                        underline: Some(UnderlineStyle {
23974                            thickness: px(1.),
23975                            color: None,
23976                            wavy: false,
23977                        }),
23978                        ..Default::default()
23979                    },
23980                    cx,
23981                );
23982            }
23983
23984            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23985            let use_autoclose = this.use_autoclose;
23986            let use_auto_surround = this.use_auto_surround;
23987            this.set_use_autoclose(false);
23988            this.set_use_auto_surround(false);
23989            this.handle_input(text, window, cx);
23990            this.set_use_autoclose(use_autoclose);
23991            this.set_use_auto_surround(use_auto_surround);
23992
23993            if let Some(new_selected_range) = new_selected_range_utf16 {
23994                let snapshot = this.buffer.read(cx).read(cx);
23995                let new_selected_ranges = marked_ranges
23996                    .into_iter()
23997                    .map(|marked_range| {
23998                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23999                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24000                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24001                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24002                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24003                    })
24004                    .collect::<Vec<_>>();
24005
24006                drop(snapshot);
24007                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24008                    selections.select_ranges(new_selected_ranges)
24009                });
24010            }
24011        });
24012
24013        self.ime_transaction = self.ime_transaction.or(transaction);
24014        if let Some(transaction) = self.ime_transaction {
24015            self.buffer.update(cx, |buffer, cx| {
24016                buffer.group_until_transaction(transaction, cx);
24017            });
24018        }
24019
24020        if self.text_highlights::<InputComposition>(cx).is_none() {
24021            self.ime_transaction.take();
24022        }
24023    }
24024
24025    fn bounds_for_range(
24026        &mut self,
24027        range_utf16: Range<usize>,
24028        element_bounds: gpui::Bounds<Pixels>,
24029        window: &mut Window,
24030        cx: &mut Context<Self>,
24031    ) -> Option<gpui::Bounds<Pixels>> {
24032        let text_layout_details = self.text_layout_details(window);
24033        let CharacterDimensions {
24034            em_width,
24035            em_advance,
24036            line_height,
24037        } = self.character_dimensions(window);
24038
24039        let snapshot = self.snapshot(window, cx);
24040        let scroll_position = snapshot.scroll_position();
24041        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24042
24043        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24044        let x = Pixels::from(
24045            ScrollOffset::from(
24046                snapshot.x_for_display_point(start, &text_layout_details)
24047                    + self.gutter_dimensions.full_width(),
24048            ) - scroll_left,
24049        );
24050        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24051
24052        Some(Bounds {
24053            origin: element_bounds.origin + point(x, y),
24054            size: size(em_width, line_height),
24055        })
24056    }
24057
24058    fn character_index_for_point(
24059        &mut self,
24060        point: gpui::Point<Pixels>,
24061        _window: &mut Window,
24062        _cx: &mut Context<Self>,
24063    ) -> Option<usize> {
24064        let position_map = self.last_position_map.as_ref()?;
24065        if !position_map.text_hitbox.contains(&point) {
24066            return None;
24067        }
24068        let display_point = position_map.point_for_position(point).previous_valid;
24069        let anchor = position_map
24070            .snapshot
24071            .display_point_to_anchor(display_point, Bias::Left);
24072        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24073        Some(utf16_offset.0)
24074    }
24075}
24076
24077trait SelectionExt {
24078    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24079    fn spanned_rows(
24080        &self,
24081        include_end_if_at_line_start: bool,
24082        map: &DisplaySnapshot,
24083    ) -> Range<MultiBufferRow>;
24084}
24085
24086impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24087    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24088        let start = self
24089            .start
24090            .to_point(map.buffer_snapshot())
24091            .to_display_point(map);
24092        let end = self
24093            .end
24094            .to_point(map.buffer_snapshot())
24095            .to_display_point(map);
24096        if self.reversed {
24097            end..start
24098        } else {
24099            start..end
24100        }
24101    }
24102
24103    fn spanned_rows(
24104        &self,
24105        include_end_if_at_line_start: bool,
24106        map: &DisplaySnapshot,
24107    ) -> Range<MultiBufferRow> {
24108        let start = self.start.to_point(map.buffer_snapshot());
24109        let mut end = self.end.to_point(map.buffer_snapshot());
24110        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24111            end.row -= 1;
24112        }
24113
24114        let buffer_start = map.prev_line_boundary(start).0;
24115        let buffer_end = map.next_line_boundary(end).0;
24116        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24117    }
24118}
24119
24120impl<T: InvalidationRegion> InvalidationStack<T> {
24121    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24122    where
24123        S: Clone + ToOffset,
24124    {
24125        while let Some(region) = self.last() {
24126            let all_selections_inside_invalidation_ranges =
24127                if selections.len() == region.ranges().len() {
24128                    selections
24129                        .iter()
24130                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24131                        .all(|(selection, invalidation_range)| {
24132                            let head = selection.head().to_offset(buffer);
24133                            invalidation_range.start <= head && invalidation_range.end >= head
24134                        })
24135                } else {
24136                    false
24137                };
24138
24139            if all_selections_inside_invalidation_ranges {
24140                break;
24141            } else {
24142                self.pop();
24143            }
24144        }
24145    }
24146}
24147
24148impl<T> Default for InvalidationStack<T> {
24149    fn default() -> Self {
24150        Self(Default::default())
24151    }
24152}
24153
24154impl<T> Deref for InvalidationStack<T> {
24155    type Target = Vec<T>;
24156
24157    fn deref(&self) -> &Self::Target {
24158        &self.0
24159    }
24160}
24161
24162impl<T> DerefMut for InvalidationStack<T> {
24163    fn deref_mut(&mut self) -> &mut Self::Target {
24164        &mut self.0
24165    }
24166}
24167
24168impl InvalidationRegion for SnippetState {
24169    fn ranges(&self) -> &[Range<Anchor>] {
24170        &self.ranges[self.active_index]
24171    }
24172}
24173
24174fn edit_prediction_edit_text(
24175    current_snapshot: &BufferSnapshot,
24176    edits: &[(Range<Anchor>, String)],
24177    edit_preview: &EditPreview,
24178    include_deletions: bool,
24179    cx: &App,
24180) -> HighlightedText {
24181    let edits = edits
24182        .iter()
24183        .map(|(anchor, text)| {
24184            (
24185                anchor.start.text_anchor..anchor.end.text_anchor,
24186                text.clone(),
24187            )
24188        })
24189        .collect::<Vec<_>>();
24190
24191    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24192}
24193
24194fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24195    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24196    // Just show the raw edit text with basic styling
24197    let mut text = String::new();
24198    let mut highlights = Vec::new();
24199
24200    let insertion_highlight_style = HighlightStyle {
24201        color: Some(cx.theme().colors().text),
24202        ..Default::default()
24203    };
24204
24205    for (_, edit_text) in edits {
24206        let start_offset = text.len();
24207        text.push_str(edit_text);
24208        let end_offset = text.len();
24209
24210        if start_offset < end_offset {
24211            highlights.push((start_offset..end_offset, insertion_highlight_style));
24212        }
24213    }
24214
24215    HighlightedText {
24216        text: text.into(),
24217        highlights,
24218    }
24219}
24220
24221pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24222    match severity {
24223        lsp::DiagnosticSeverity::ERROR => colors.error,
24224        lsp::DiagnosticSeverity::WARNING => colors.warning,
24225        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24226        lsp::DiagnosticSeverity::HINT => colors.info,
24227        _ => colors.ignored,
24228    }
24229}
24230
24231pub fn styled_runs_for_code_label<'a>(
24232    label: &'a CodeLabel,
24233    syntax_theme: &'a theme::SyntaxTheme,
24234) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24235    let fade_out = HighlightStyle {
24236        fade_out: Some(0.35),
24237        ..Default::default()
24238    };
24239
24240    let mut prev_end = label.filter_range.end;
24241    label
24242        .runs
24243        .iter()
24244        .enumerate()
24245        .flat_map(move |(ix, (range, highlight_id))| {
24246            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24247                style
24248            } else {
24249                return Default::default();
24250            };
24251            let muted_style = style.highlight(fade_out);
24252
24253            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24254            if range.start >= label.filter_range.end {
24255                if range.start > prev_end {
24256                    runs.push((prev_end..range.start, fade_out));
24257                }
24258                runs.push((range.clone(), muted_style));
24259            } else if range.end <= label.filter_range.end {
24260                runs.push((range.clone(), style));
24261            } else {
24262                runs.push((range.start..label.filter_range.end, style));
24263                runs.push((label.filter_range.end..range.end, muted_style));
24264            }
24265            prev_end = cmp::max(prev_end, range.end);
24266
24267            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24268                runs.push((prev_end..label.text.len(), fade_out));
24269            }
24270
24271            runs
24272        })
24273}
24274
24275pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24276    let mut prev_index = 0;
24277    let mut prev_codepoint: Option<char> = None;
24278    text.char_indices()
24279        .chain([(text.len(), '\0')])
24280        .filter_map(move |(index, codepoint)| {
24281            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24282            let is_boundary = index == text.len()
24283                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24284                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24285            if is_boundary {
24286                let chunk = &text[prev_index..index];
24287                prev_index = index;
24288                Some(chunk)
24289            } else {
24290                None
24291            }
24292        })
24293}
24294
24295pub trait RangeToAnchorExt: Sized {
24296    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24297
24298    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24299        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24300        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24301    }
24302}
24303
24304impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24305    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24306        let start_offset = self.start.to_offset(snapshot);
24307        let end_offset = self.end.to_offset(snapshot);
24308        if start_offset == end_offset {
24309            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24310        } else {
24311            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24312        }
24313    }
24314}
24315
24316pub trait RowExt {
24317    fn as_f64(&self) -> f64;
24318
24319    fn next_row(&self) -> Self;
24320
24321    fn previous_row(&self) -> Self;
24322
24323    fn minus(&self, other: Self) -> u32;
24324}
24325
24326impl RowExt for DisplayRow {
24327    fn as_f64(&self) -> f64 {
24328        self.0 as _
24329    }
24330
24331    fn next_row(&self) -> Self {
24332        Self(self.0 + 1)
24333    }
24334
24335    fn previous_row(&self) -> Self {
24336        Self(self.0.saturating_sub(1))
24337    }
24338
24339    fn minus(&self, other: Self) -> u32 {
24340        self.0 - other.0
24341    }
24342}
24343
24344impl RowExt for MultiBufferRow {
24345    fn as_f64(&self) -> f64 {
24346        self.0 as _
24347    }
24348
24349    fn next_row(&self) -> Self {
24350        Self(self.0 + 1)
24351    }
24352
24353    fn previous_row(&self) -> Self {
24354        Self(self.0.saturating_sub(1))
24355    }
24356
24357    fn minus(&self, other: Self) -> u32 {
24358        self.0 - other.0
24359    }
24360}
24361
24362trait RowRangeExt {
24363    type Row;
24364
24365    fn len(&self) -> usize;
24366
24367    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24368}
24369
24370impl RowRangeExt for Range<MultiBufferRow> {
24371    type Row = MultiBufferRow;
24372
24373    fn len(&self) -> usize {
24374        (self.end.0 - self.start.0) as usize
24375    }
24376
24377    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24378        (self.start.0..self.end.0).map(MultiBufferRow)
24379    }
24380}
24381
24382impl RowRangeExt for Range<DisplayRow> {
24383    type Row = DisplayRow;
24384
24385    fn len(&self) -> usize {
24386        (self.end.0 - self.start.0) as usize
24387    }
24388
24389    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24390        (self.start.0..self.end.0).map(DisplayRow)
24391    }
24392}
24393
24394/// If select range has more than one line, we
24395/// just point the cursor to range.start.
24396fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24397    if range.start.row == range.end.row {
24398        range
24399    } else {
24400        range.start..range.start
24401    }
24402}
24403pub struct KillRing(ClipboardItem);
24404impl Global for KillRing {}
24405
24406const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24407
24408enum BreakpointPromptEditAction {
24409    Log,
24410    Condition,
24411    HitCondition,
24412}
24413
24414struct BreakpointPromptEditor {
24415    pub(crate) prompt: Entity<Editor>,
24416    editor: WeakEntity<Editor>,
24417    breakpoint_anchor: Anchor,
24418    breakpoint: Breakpoint,
24419    edit_action: BreakpointPromptEditAction,
24420    block_ids: HashSet<CustomBlockId>,
24421    editor_margins: Arc<Mutex<EditorMargins>>,
24422    _subscriptions: Vec<Subscription>,
24423}
24424
24425impl BreakpointPromptEditor {
24426    const MAX_LINES: u8 = 4;
24427
24428    fn new(
24429        editor: WeakEntity<Editor>,
24430        breakpoint_anchor: Anchor,
24431        breakpoint: Breakpoint,
24432        edit_action: BreakpointPromptEditAction,
24433        window: &mut Window,
24434        cx: &mut Context<Self>,
24435    ) -> Self {
24436        let base_text = match edit_action {
24437            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24438            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24439            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24440        }
24441        .map(|msg| msg.to_string())
24442        .unwrap_or_default();
24443
24444        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24445        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24446
24447        let prompt = cx.new(|cx| {
24448            let mut prompt = Editor::new(
24449                EditorMode::AutoHeight {
24450                    min_lines: 1,
24451                    max_lines: Some(Self::MAX_LINES as usize),
24452                },
24453                buffer,
24454                None,
24455                window,
24456                cx,
24457            );
24458            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24459            prompt.set_show_cursor_when_unfocused(false, cx);
24460            prompt.set_placeholder_text(
24461                match edit_action {
24462                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24463                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24464                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24465                },
24466                window,
24467                cx,
24468            );
24469
24470            prompt
24471        });
24472
24473        Self {
24474            prompt,
24475            editor,
24476            breakpoint_anchor,
24477            breakpoint,
24478            edit_action,
24479            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24480            block_ids: Default::default(),
24481            _subscriptions: vec![],
24482        }
24483    }
24484
24485    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24486        self.block_ids.extend(block_ids)
24487    }
24488
24489    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24490        if let Some(editor) = self.editor.upgrade() {
24491            let message = self
24492                .prompt
24493                .read(cx)
24494                .buffer
24495                .read(cx)
24496                .as_singleton()
24497                .expect("A multi buffer in breakpoint prompt isn't possible")
24498                .read(cx)
24499                .as_rope()
24500                .to_string();
24501
24502            editor.update(cx, |editor, cx| {
24503                editor.edit_breakpoint_at_anchor(
24504                    self.breakpoint_anchor,
24505                    self.breakpoint.clone(),
24506                    match self.edit_action {
24507                        BreakpointPromptEditAction::Log => {
24508                            BreakpointEditAction::EditLogMessage(message.into())
24509                        }
24510                        BreakpointPromptEditAction::Condition => {
24511                            BreakpointEditAction::EditCondition(message.into())
24512                        }
24513                        BreakpointPromptEditAction::HitCondition => {
24514                            BreakpointEditAction::EditHitCondition(message.into())
24515                        }
24516                    },
24517                    cx,
24518                );
24519
24520                editor.remove_blocks(self.block_ids.clone(), None, cx);
24521                cx.focus_self(window);
24522            });
24523        }
24524    }
24525
24526    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24527        self.editor
24528            .update(cx, |editor, cx| {
24529                editor.remove_blocks(self.block_ids.clone(), None, cx);
24530                window.focus(&editor.focus_handle);
24531            })
24532            .log_err();
24533    }
24534
24535    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24536        let settings = ThemeSettings::get_global(cx);
24537        let text_style = TextStyle {
24538            color: if self.prompt.read(cx).read_only(cx) {
24539                cx.theme().colors().text_disabled
24540            } else {
24541                cx.theme().colors().text
24542            },
24543            font_family: settings.buffer_font.family.clone(),
24544            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24545            font_size: settings.buffer_font_size(cx).into(),
24546            font_weight: settings.buffer_font.weight,
24547            line_height: relative(settings.buffer_line_height.value()),
24548            ..Default::default()
24549        };
24550        EditorElement::new(
24551            &self.prompt,
24552            EditorStyle {
24553                background: cx.theme().colors().editor_background,
24554                local_player: cx.theme().players().local(),
24555                text: text_style,
24556                ..Default::default()
24557            },
24558        )
24559    }
24560}
24561
24562impl Render for BreakpointPromptEditor {
24563    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24564        let editor_margins = *self.editor_margins.lock();
24565        let gutter_dimensions = editor_margins.gutter;
24566        h_flex()
24567            .key_context("Editor")
24568            .bg(cx.theme().colors().editor_background)
24569            .border_y_1()
24570            .border_color(cx.theme().status().info_border)
24571            .size_full()
24572            .py(window.line_height() / 2.5)
24573            .on_action(cx.listener(Self::confirm))
24574            .on_action(cx.listener(Self::cancel))
24575            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24576            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24577    }
24578}
24579
24580impl Focusable for BreakpointPromptEditor {
24581    fn focus_handle(&self, cx: &App) -> FocusHandle {
24582        self.prompt.focus_handle(cx)
24583    }
24584}
24585
24586fn all_edits_insertions_or_deletions(
24587    edits: &Vec<(Range<Anchor>, String)>,
24588    snapshot: &MultiBufferSnapshot,
24589) -> bool {
24590    let mut all_insertions = true;
24591    let mut all_deletions = true;
24592
24593    for (range, new_text) in edits.iter() {
24594        let range_is_empty = range.to_offset(snapshot).is_empty();
24595        let text_is_empty = new_text.is_empty();
24596
24597        if range_is_empty != text_is_empty {
24598            if range_is_empty {
24599                all_deletions = false;
24600            } else {
24601                all_insertions = false;
24602            }
24603        } else {
24604            return false;
24605        }
24606
24607        if !all_insertions && !all_deletions {
24608            return false;
24609        }
24610    }
24611    all_insertions || all_deletions
24612}
24613
24614struct MissingEditPredictionKeybindingTooltip;
24615
24616impl Render for MissingEditPredictionKeybindingTooltip {
24617    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24618        ui::tooltip_container(cx, |container, cx| {
24619            container
24620                .flex_shrink_0()
24621                .max_w_80()
24622                .min_h(rems_from_px(124.))
24623                .justify_between()
24624                .child(
24625                    v_flex()
24626                        .flex_1()
24627                        .text_ui_sm(cx)
24628                        .child(Label::new("Conflict with Accept Keybinding"))
24629                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24630                )
24631                .child(
24632                    h_flex()
24633                        .pb_1()
24634                        .gap_1()
24635                        .items_end()
24636                        .w_full()
24637                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24638                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24639                        }))
24640                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24641                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24642                        })),
24643                )
24644        })
24645    }
24646}
24647
24648#[derive(Debug, Clone, Copy, PartialEq)]
24649pub struct LineHighlight {
24650    pub background: Background,
24651    pub border: Option<gpui::Hsla>,
24652    pub include_gutter: bool,
24653    pub type_id: Option<TypeId>,
24654}
24655
24656struct LineManipulationResult {
24657    pub new_text: String,
24658    pub line_count_before: usize,
24659    pub line_count_after: usize,
24660}
24661
24662fn render_diff_hunk_controls(
24663    row: u32,
24664    status: &DiffHunkStatus,
24665    hunk_range: Range<Anchor>,
24666    is_created_file: bool,
24667    line_height: Pixels,
24668    editor: &Entity<Editor>,
24669    _window: &mut Window,
24670    cx: &mut App,
24671) -> AnyElement {
24672    h_flex()
24673        .h(line_height)
24674        .mr_1()
24675        .gap_1()
24676        .px_0p5()
24677        .pb_1()
24678        .border_x_1()
24679        .border_b_1()
24680        .border_color(cx.theme().colors().border_variant)
24681        .rounded_b_lg()
24682        .bg(cx.theme().colors().editor_background)
24683        .gap_1()
24684        .block_mouse_except_scroll()
24685        .shadow_md()
24686        .child(if status.has_secondary_hunk() {
24687            Button::new(("stage", row as u64), "Stage")
24688                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24689                .tooltip({
24690                    let focus_handle = editor.focus_handle(cx);
24691                    move |window, cx| {
24692                        Tooltip::for_action_in(
24693                            "Stage Hunk",
24694                            &::git::ToggleStaged,
24695                            &focus_handle,
24696                            window,
24697                            cx,
24698                        )
24699                    }
24700                })
24701                .on_click({
24702                    let editor = editor.clone();
24703                    move |_event, _window, cx| {
24704                        editor.update(cx, |editor, cx| {
24705                            editor.stage_or_unstage_diff_hunks(
24706                                true,
24707                                vec![hunk_range.start..hunk_range.start],
24708                                cx,
24709                            );
24710                        });
24711                    }
24712                })
24713        } else {
24714            Button::new(("unstage", row as u64), "Unstage")
24715                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24716                .tooltip({
24717                    let focus_handle = editor.focus_handle(cx);
24718                    move |window, cx| {
24719                        Tooltip::for_action_in(
24720                            "Unstage Hunk",
24721                            &::git::ToggleStaged,
24722                            &focus_handle,
24723                            window,
24724                            cx,
24725                        )
24726                    }
24727                })
24728                .on_click({
24729                    let editor = editor.clone();
24730                    move |_event, _window, cx| {
24731                        editor.update(cx, |editor, cx| {
24732                            editor.stage_or_unstage_diff_hunks(
24733                                false,
24734                                vec![hunk_range.start..hunk_range.start],
24735                                cx,
24736                            );
24737                        });
24738                    }
24739                })
24740        })
24741        .child(
24742            Button::new(("restore", row as u64), "Restore")
24743                .tooltip({
24744                    let focus_handle = editor.focus_handle(cx);
24745                    move |window, cx| {
24746                        Tooltip::for_action_in(
24747                            "Restore Hunk",
24748                            &::git::Restore,
24749                            &focus_handle,
24750                            window,
24751                            cx,
24752                        )
24753                    }
24754                })
24755                .on_click({
24756                    let editor = editor.clone();
24757                    move |_event, window, cx| {
24758                        editor.update(cx, |editor, cx| {
24759                            let snapshot = editor.snapshot(window, cx);
24760                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24761                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24762                        });
24763                    }
24764                })
24765                .disabled(is_created_file),
24766        )
24767        .when(
24768            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24769            |el| {
24770                el.child(
24771                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24772                        .shape(IconButtonShape::Square)
24773                        .icon_size(IconSize::Small)
24774                        // .disabled(!has_multiple_hunks)
24775                        .tooltip({
24776                            let focus_handle = editor.focus_handle(cx);
24777                            move |window, cx| {
24778                                Tooltip::for_action_in(
24779                                    "Next Hunk",
24780                                    &GoToHunk,
24781                                    &focus_handle,
24782                                    window,
24783                                    cx,
24784                                )
24785                            }
24786                        })
24787                        .on_click({
24788                            let editor = editor.clone();
24789                            move |_event, window, cx| {
24790                                editor.update(cx, |editor, cx| {
24791                                    let snapshot = editor.snapshot(window, cx);
24792                                    let position =
24793                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24794                                    editor.go_to_hunk_before_or_after_position(
24795                                        &snapshot,
24796                                        position,
24797                                        Direction::Next,
24798                                        window,
24799                                        cx,
24800                                    );
24801                                    editor.expand_selected_diff_hunks(cx);
24802                                });
24803                            }
24804                        }),
24805                )
24806                .child(
24807                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24808                        .shape(IconButtonShape::Square)
24809                        .icon_size(IconSize::Small)
24810                        // .disabled(!has_multiple_hunks)
24811                        .tooltip({
24812                            let focus_handle = editor.focus_handle(cx);
24813                            move |window, cx| {
24814                                Tooltip::for_action_in(
24815                                    "Previous Hunk",
24816                                    &GoToPreviousHunk,
24817                                    &focus_handle,
24818                                    window,
24819                                    cx,
24820                                )
24821                            }
24822                        })
24823                        .on_click({
24824                            let editor = editor.clone();
24825                            move |_event, window, cx| {
24826                                editor.update(cx, |editor, cx| {
24827                                    let snapshot = editor.snapshot(window, cx);
24828                                    let point =
24829                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24830                                    editor.go_to_hunk_before_or_after_position(
24831                                        &snapshot,
24832                                        point,
24833                                        Direction::Prev,
24834                                        window,
24835                                        cx,
24836                                    );
24837                                    editor.expand_selected_diff_hunks(cx);
24838                                });
24839                            }
24840                        }),
24841                )
24842            },
24843        )
24844        .into_any_element()
24845}
24846
24847pub fn multibuffer_context_lines(cx: &App) -> u32 {
24848    EditorSettings::try_get(cx)
24849        .map(|settings| settings.excerpt_context_lines)
24850        .unwrap_or(2)
24851        .min(32)
24852}