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, 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>) {
 6611        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6612            cx.background_executor()
 6613                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6614                .await;
 6615
 6616            let (start_buffer, start, _, end, newest_selection) = this
 6617                .update(cx, |this, cx| {
 6618                    let newest_selection = this.selections.newest_anchor().clone();
 6619                    if newest_selection.head().diff_base_anchor.is_some() {
 6620                        return None;
 6621                    }
 6622                    let newest_selection_adjusted = this.selections.newest_adjusted(cx);
 6623                    let buffer = this.buffer.read(cx);
 6624
 6625                    let (start_buffer, start) =
 6626                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6627                    let (end_buffer, end) =
 6628                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6629
 6630                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6631                })?
 6632                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6633                .context(
 6634                    "Expected selection to lie in a single buffer when refreshing code actions",
 6635                )?;
 6636            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6637                let providers = this.code_action_providers.clone();
 6638                let tasks = this
 6639                    .code_action_providers
 6640                    .iter()
 6641                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6642                    .collect::<Vec<_>>();
 6643                (providers, tasks)
 6644            })?;
 6645
 6646            let mut actions = Vec::new();
 6647            for (provider, provider_actions) in
 6648                providers.into_iter().zip(future::join_all(tasks).await)
 6649            {
 6650                if let Some(provider_actions) = provider_actions.log_err() {
 6651                    actions.extend(provider_actions.into_iter().map(|action| {
 6652                        AvailableCodeAction {
 6653                            excerpt_id: newest_selection.start.excerpt_id,
 6654                            action,
 6655                            provider: provider.clone(),
 6656                        }
 6657                    }));
 6658                }
 6659            }
 6660
 6661            this.update(cx, |this, cx| {
 6662                this.available_code_actions = if actions.is_empty() {
 6663                    None
 6664                } else {
 6665                    Some((
 6666                        Location {
 6667                            buffer: start_buffer,
 6668                            range: start..end,
 6669                        },
 6670                        actions.into(),
 6671                    ))
 6672                };
 6673                cx.notify();
 6674            })
 6675        }));
 6676    }
 6677
 6678    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6679        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6680            self.show_git_blame_inline = false;
 6681
 6682            self.show_git_blame_inline_delay_task =
 6683                Some(cx.spawn_in(window, async move |this, cx| {
 6684                    cx.background_executor().timer(delay).await;
 6685
 6686                    this.update(cx, |this, cx| {
 6687                        this.show_git_blame_inline = true;
 6688                        cx.notify();
 6689                    })
 6690                    .log_err();
 6691                }));
 6692        }
 6693    }
 6694
 6695    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6696        let snapshot = self.snapshot(window, cx);
 6697        let cursor = self.selections.newest::<Point>(cx).head();
 6698        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6699        else {
 6700            return;
 6701        };
 6702
 6703        let Some(blame) = self.blame.as_ref() else {
 6704            return;
 6705        };
 6706
 6707        let row_info = RowInfo {
 6708            buffer_id: Some(buffer.remote_id()),
 6709            buffer_row: Some(point.row),
 6710            ..Default::default()
 6711        };
 6712        let Some((buffer, blame_entry)) = blame
 6713            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6714            .flatten()
 6715        else {
 6716            return;
 6717        };
 6718
 6719        let anchor = self.selections.newest_anchor().head();
 6720        let position = self.to_pixel_point(anchor, &snapshot, window);
 6721        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6722            self.show_blame_popover(
 6723                buffer,
 6724                &blame_entry,
 6725                position + last_bounds.origin,
 6726                true,
 6727                cx,
 6728            );
 6729        };
 6730    }
 6731
 6732    fn show_blame_popover(
 6733        &mut self,
 6734        buffer: BufferId,
 6735        blame_entry: &BlameEntry,
 6736        position: gpui::Point<Pixels>,
 6737        ignore_timeout: bool,
 6738        cx: &mut Context<Self>,
 6739    ) {
 6740        if let Some(state) = &mut self.inline_blame_popover {
 6741            state.hide_task.take();
 6742        } else {
 6743            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6744            let blame_entry = blame_entry.clone();
 6745            let show_task = cx.spawn(async move |editor, cx| {
 6746                if !ignore_timeout {
 6747                    cx.background_executor()
 6748                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6749                        .await;
 6750                }
 6751                editor
 6752                    .update(cx, |editor, cx| {
 6753                        editor.inline_blame_popover_show_task.take();
 6754                        let Some(blame) = editor.blame.as_ref() else {
 6755                            return;
 6756                        };
 6757                        let blame = blame.read(cx);
 6758                        let details = blame.details_for_entry(buffer, &blame_entry);
 6759                        let markdown = cx.new(|cx| {
 6760                            Markdown::new(
 6761                                details
 6762                                    .as_ref()
 6763                                    .map(|message| message.message.clone())
 6764                                    .unwrap_or_default(),
 6765                                None,
 6766                                None,
 6767                                cx,
 6768                            )
 6769                        });
 6770                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6771                            position,
 6772                            hide_task: None,
 6773                            popover_bounds: None,
 6774                            popover_state: InlineBlamePopoverState {
 6775                                scroll_handle: ScrollHandle::new(),
 6776                                commit_message: details,
 6777                                markdown,
 6778                            },
 6779                            keyboard_grace: ignore_timeout,
 6780                        });
 6781                        cx.notify();
 6782                    })
 6783                    .ok();
 6784            });
 6785            self.inline_blame_popover_show_task = Some(show_task);
 6786        }
 6787    }
 6788
 6789    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6790        self.inline_blame_popover_show_task.take();
 6791        if let Some(state) = &mut self.inline_blame_popover {
 6792            let hide_task = cx.spawn(async move |editor, cx| {
 6793                cx.background_executor()
 6794                    .timer(std::time::Duration::from_millis(100))
 6795                    .await;
 6796                editor
 6797                    .update(cx, |editor, cx| {
 6798                        editor.inline_blame_popover.take();
 6799                        cx.notify();
 6800                    })
 6801                    .ok();
 6802            });
 6803            state.hide_task = Some(hide_task);
 6804        }
 6805    }
 6806
 6807    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6808        if self.pending_rename.is_some() {
 6809            return None;
 6810        }
 6811
 6812        let provider = self.semantics_provider.clone()?;
 6813        let buffer = self.buffer.read(cx);
 6814        let newest_selection = self.selections.newest_anchor().clone();
 6815        let cursor_position = newest_selection.head();
 6816        let (cursor_buffer, cursor_buffer_position) =
 6817            buffer.text_anchor_for_position(cursor_position, cx)?;
 6818        let (tail_buffer, tail_buffer_position) =
 6819            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6820        if cursor_buffer != tail_buffer {
 6821            return None;
 6822        }
 6823
 6824        let snapshot = cursor_buffer.read(cx).snapshot();
 6825        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6826        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6827        if start_word_range != end_word_range {
 6828            self.document_highlights_task.take();
 6829            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6830            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6831            return None;
 6832        }
 6833
 6834        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6835        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6836            cx.background_executor()
 6837                .timer(Duration::from_millis(debounce))
 6838                .await;
 6839
 6840            let highlights = if let Some(highlights) = cx
 6841                .update(|cx| {
 6842                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6843                })
 6844                .ok()
 6845                .flatten()
 6846            {
 6847                highlights.await.log_err()
 6848            } else {
 6849                None
 6850            };
 6851
 6852            if let Some(highlights) = highlights {
 6853                this.update(cx, |this, cx| {
 6854                    if this.pending_rename.is_some() {
 6855                        return;
 6856                    }
 6857
 6858                    let buffer = this.buffer.read(cx);
 6859                    if buffer
 6860                        .text_anchor_for_position(cursor_position, cx)
 6861                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6862                    {
 6863                        return;
 6864                    }
 6865
 6866                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6867                    let mut write_ranges = Vec::new();
 6868                    let mut read_ranges = Vec::new();
 6869                    for highlight in highlights {
 6870                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6871                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6872                        {
 6873                            let start = highlight
 6874                                .range
 6875                                .start
 6876                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6877                            let end = highlight
 6878                                .range
 6879                                .end
 6880                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6881                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6882                                continue;
 6883                            }
 6884
 6885                            let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
 6886                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6887                                write_ranges.push(range);
 6888                            } else {
 6889                                read_ranges.push(range);
 6890                            }
 6891                        }
 6892                    }
 6893
 6894                    this.highlight_background::<DocumentHighlightRead>(
 6895                        &read_ranges,
 6896                        |theme| theme.colors().editor_document_highlight_read_background,
 6897                        cx,
 6898                    );
 6899                    this.highlight_background::<DocumentHighlightWrite>(
 6900                        &write_ranges,
 6901                        |theme| theme.colors().editor_document_highlight_write_background,
 6902                        cx,
 6903                    );
 6904                    cx.notify();
 6905                })
 6906                .log_err();
 6907            }
 6908        }));
 6909        None
 6910    }
 6911
 6912    fn prepare_highlight_query_from_selection(
 6913        &mut self,
 6914        cx: &mut Context<Editor>,
 6915    ) -> Option<(String, Range<Anchor>)> {
 6916        if matches!(self.mode, EditorMode::SingleLine) {
 6917            return None;
 6918        }
 6919        if !EditorSettings::get_global(cx).selection_highlight {
 6920            return None;
 6921        }
 6922        if self.selections.count() != 1 || self.selections.line_mode() {
 6923            return None;
 6924        }
 6925        let selection = self.selections.newest_anchor();
 6926        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6927        let selection_point_range = selection.start.to_point(&multi_buffer_snapshot)
 6928            ..selection.end.to_point(&multi_buffer_snapshot);
 6929        // If the selection spans multiple rows OR it is empty
 6930        if selection_point_range.start.row != selection_point_range.end.row
 6931            || selection_point_range.start.column == selection_point_range.end.column
 6932        {
 6933            return None;
 6934        }
 6935
 6936        let query = multi_buffer_snapshot
 6937            .text_for_range(selection.range())
 6938            .collect::<String>();
 6939        if query.trim().is_empty() {
 6940            return None;
 6941        }
 6942        Some((query, selection.range()))
 6943    }
 6944
 6945    fn update_selection_occurrence_highlights(
 6946        &mut self,
 6947        query_text: String,
 6948        query_range: Range<Anchor>,
 6949        multi_buffer_range_to_query: Range<Point>,
 6950        use_debounce: bool,
 6951        window: &mut Window,
 6952        cx: &mut Context<Editor>,
 6953    ) -> Task<()> {
 6954        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6955        cx.spawn_in(window, async move |editor, cx| {
 6956            if use_debounce {
 6957                cx.background_executor()
 6958                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6959                    .await;
 6960            }
 6961            let match_task = cx.background_spawn(async move {
 6962                let buffer_ranges = multi_buffer_snapshot
 6963                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6964                    .into_iter()
 6965                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6966                let mut match_ranges = Vec::new();
 6967                let Ok(regex) = project::search::SearchQuery::text(
 6968                    query_text.clone(),
 6969                    false,
 6970                    false,
 6971                    false,
 6972                    Default::default(),
 6973                    Default::default(),
 6974                    false,
 6975                    None,
 6976                ) else {
 6977                    return Vec::default();
 6978                };
 6979                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6980                    match_ranges.extend(
 6981                        regex
 6982                            .search(buffer_snapshot, Some(search_range.clone()))
 6983                            .await
 6984                            .into_iter()
 6985                            .filter_map(|match_range| {
 6986                                let match_start = buffer_snapshot
 6987                                    .anchor_after(search_range.start + match_range.start);
 6988                                let match_end = buffer_snapshot
 6989                                    .anchor_before(search_range.start + match_range.end);
 6990                                let match_anchor_range = Anchor::range_in_buffer(
 6991                                    excerpt_id,
 6992                                    buffer_snapshot.remote_id(),
 6993                                    match_start..match_end,
 6994                                );
 6995                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6996                            }),
 6997                    );
 6998                }
 6999                match_ranges
 7000            });
 7001            let match_ranges = match_task.await;
 7002            editor
 7003                .update_in(cx, |editor, _, cx| {
 7004                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7005                    if !match_ranges.is_empty() {
 7006                        editor.highlight_background::<SelectedTextHighlight>(
 7007                            &match_ranges,
 7008                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7009                            cx,
 7010                        )
 7011                    }
 7012                })
 7013                .log_err();
 7014        })
 7015    }
 7016
 7017    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7018        struct NewlineFold;
 7019        let type_id = std::any::TypeId::of::<NewlineFold>();
 7020        if !self.mode.is_single_line() {
 7021            return;
 7022        }
 7023        let snapshot = self.snapshot(window, cx);
 7024        if snapshot.buffer_snapshot().max_point().row == 0 {
 7025            return;
 7026        }
 7027        let task = cx.background_spawn(async move {
 7028            let new_newlines = snapshot
 7029                .buffer_chars_at(0)
 7030                .filter_map(|(c, i)| {
 7031                    if c == '\n' {
 7032                        Some(
 7033                            snapshot.buffer_snapshot().anchor_after(i)
 7034                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7035                        )
 7036                    } else {
 7037                        None
 7038                    }
 7039                })
 7040                .collect::<Vec<_>>();
 7041            let existing_newlines = snapshot
 7042                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7043                .filter_map(|fold| {
 7044                    if fold.placeholder.type_tag == Some(type_id) {
 7045                        Some(fold.range.start..fold.range.end)
 7046                    } else {
 7047                        None
 7048                    }
 7049                })
 7050                .collect::<Vec<_>>();
 7051
 7052            (new_newlines, existing_newlines)
 7053        });
 7054        self.folding_newlines = cx.spawn(async move |this, cx| {
 7055            let (new_newlines, existing_newlines) = task.await;
 7056            if new_newlines == existing_newlines {
 7057                return;
 7058            }
 7059            let placeholder = FoldPlaceholder {
 7060                render: Arc::new(move |_, _, cx| {
 7061                    div()
 7062                        .bg(cx.theme().status().hint_background)
 7063                        .border_b_1()
 7064                        .size_full()
 7065                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7066                        .border_color(cx.theme().status().hint)
 7067                        .child("\\n")
 7068                        .into_any()
 7069                }),
 7070                constrain_width: false,
 7071                merge_adjacent: false,
 7072                type_tag: Some(type_id),
 7073            };
 7074            let creases = new_newlines
 7075                .into_iter()
 7076                .map(|range| Crease::simple(range, placeholder.clone()))
 7077                .collect();
 7078            this.update(cx, |this, cx| {
 7079                this.display_map.update(cx, |display_map, cx| {
 7080                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7081                    display_map.fold(creases, cx);
 7082                });
 7083            })
 7084            .ok();
 7085        });
 7086    }
 7087
 7088    fn refresh_selected_text_highlights(
 7089        &mut self,
 7090        on_buffer_edit: bool,
 7091        window: &mut Window,
 7092        cx: &mut Context<Editor>,
 7093    ) {
 7094        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7095        else {
 7096            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7097            self.quick_selection_highlight_task.take();
 7098            self.debounced_selection_highlight_task.take();
 7099            return;
 7100        };
 7101        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7102        if on_buffer_edit
 7103            || self
 7104                .quick_selection_highlight_task
 7105                .as_ref()
 7106                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7107        {
 7108            let multi_buffer_visible_start = self
 7109                .scroll_manager
 7110                .anchor()
 7111                .anchor
 7112                .to_point(&multi_buffer_snapshot);
 7113            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7114                multi_buffer_visible_start
 7115                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7116                Bias::Left,
 7117            );
 7118            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7119            self.quick_selection_highlight_task = Some((
 7120                query_range.clone(),
 7121                self.update_selection_occurrence_highlights(
 7122                    query_text.clone(),
 7123                    query_range.clone(),
 7124                    multi_buffer_visible_range,
 7125                    false,
 7126                    window,
 7127                    cx,
 7128                ),
 7129            ));
 7130        }
 7131        if on_buffer_edit
 7132            || self
 7133                .debounced_selection_highlight_task
 7134                .as_ref()
 7135                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7136        {
 7137            let multi_buffer_start = multi_buffer_snapshot
 7138                .anchor_before(0)
 7139                .to_point(&multi_buffer_snapshot);
 7140            let multi_buffer_end = multi_buffer_snapshot
 7141                .anchor_after(multi_buffer_snapshot.len())
 7142                .to_point(&multi_buffer_snapshot);
 7143            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7144            self.debounced_selection_highlight_task = Some((
 7145                query_range.clone(),
 7146                self.update_selection_occurrence_highlights(
 7147                    query_text,
 7148                    query_range,
 7149                    multi_buffer_full_range,
 7150                    true,
 7151                    window,
 7152                    cx,
 7153                ),
 7154            ));
 7155        }
 7156    }
 7157
 7158    pub fn refresh_edit_prediction(
 7159        &mut self,
 7160        debounce: bool,
 7161        user_requested: bool,
 7162        window: &mut Window,
 7163        cx: &mut Context<Self>,
 7164    ) -> Option<()> {
 7165        if DisableAiSettings::get_global(cx).disable_ai {
 7166            return None;
 7167        }
 7168
 7169        let provider = self.edit_prediction_provider()?;
 7170        let cursor = self.selections.newest_anchor().head();
 7171        let (buffer, cursor_buffer_position) =
 7172            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7173
 7174        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7175            self.discard_edit_prediction(false, cx);
 7176            return None;
 7177        }
 7178
 7179        self.update_visible_edit_prediction(window, cx);
 7180
 7181        if !user_requested
 7182            && (!self.should_show_edit_predictions()
 7183                || !self.is_focused(window)
 7184                || buffer.read(cx).is_empty())
 7185        {
 7186            self.discard_edit_prediction(false, cx);
 7187            return None;
 7188        }
 7189
 7190        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7191        Some(())
 7192    }
 7193
 7194    fn show_edit_predictions_in_menu(&self) -> bool {
 7195        match self.edit_prediction_settings {
 7196            EditPredictionSettings::Disabled => false,
 7197            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7198        }
 7199    }
 7200
 7201    pub fn edit_predictions_enabled(&self) -> bool {
 7202        match self.edit_prediction_settings {
 7203            EditPredictionSettings::Disabled => false,
 7204            EditPredictionSettings::Enabled { .. } => true,
 7205        }
 7206    }
 7207
 7208    fn edit_prediction_requires_modifier(&self) -> bool {
 7209        match self.edit_prediction_settings {
 7210            EditPredictionSettings::Disabled => false,
 7211            EditPredictionSettings::Enabled {
 7212                preview_requires_modifier,
 7213                ..
 7214            } => preview_requires_modifier,
 7215        }
 7216    }
 7217
 7218    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7219        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7220            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7221            self.discard_edit_prediction(false, cx);
 7222        } else {
 7223            let selection = self.selections.newest_anchor();
 7224            let cursor = selection.head();
 7225
 7226            if let Some((buffer, cursor_buffer_position)) =
 7227                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7228            {
 7229                self.edit_prediction_settings =
 7230                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7231            }
 7232        }
 7233    }
 7234
 7235    fn edit_prediction_settings_at_position(
 7236        &self,
 7237        buffer: &Entity<Buffer>,
 7238        buffer_position: language::Anchor,
 7239        cx: &App,
 7240    ) -> EditPredictionSettings {
 7241        if !self.mode.is_full()
 7242            || !self.show_edit_predictions_override.unwrap_or(true)
 7243            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7244        {
 7245            return EditPredictionSettings::Disabled;
 7246        }
 7247
 7248        let buffer = buffer.read(cx);
 7249
 7250        let file = buffer.file();
 7251
 7252        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7253            return EditPredictionSettings::Disabled;
 7254        };
 7255
 7256        let by_provider = matches!(
 7257            self.menu_edit_predictions_policy,
 7258            MenuEditPredictionsPolicy::ByProvider
 7259        );
 7260
 7261        let show_in_menu = by_provider
 7262            && self
 7263                .edit_prediction_provider
 7264                .as_ref()
 7265                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7266
 7267        let preview_requires_modifier =
 7268            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7269
 7270        EditPredictionSettings::Enabled {
 7271            show_in_menu,
 7272            preview_requires_modifier,
 7273        }
 7274    }
 7275
 7276    fn should_show_edit_predictions(&self) -> bool {
 7277        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7278    }
 7279
 7280    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7281        matches!(
 7282            self.edit_prediction_preview,
 7283            EditPredictionPreview::Active { .. }
 7284        )
 7285    }
 7286
 7287    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7288        let cursor = self.selections.newest_anchor().head();
 7289        if let Some((buffer, cursor_position)) =
 7290            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7291        {
 7292            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7293        } else {
 7294            false
 7295        }
 7296    }
 7297
 7298    pub fn supports_minimap(&self, cx: &App) -> bool {
 7299        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7300    }
 7301
 7302    fn edit_predictions_enabled_in_buffer(
 7303        &self,
 7304        buffer: &Entity<Buffer>,
 7305        buffer_position: language::Anchor,
 7306        cx: &App,
 7307    ) -> bool {
 7308        maybe!({
 7309            if self.read_only(cx) {
 7310                return Some(false);
 7311            }
 7312            let provider = self.edit_prediction_provider()?;
 7313            if !provider.is_enabled(buffer, buffer_position, cx) {
 7314                return Some(false);
 7315            }
 7316            let buffer = buffer.read(cx);
 7317            let Some(file) = buffer.file() else {
 7318                return Some(true);
 7319            };
 7320            let settings = all_language_settings(Some(file), cx);
 7321            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7322        })
 7323        .unwrap_or(false)
 7324    }
 7325
 7326    fn cycle_edit_prediction(
 7327        &mut self,
 7328        direction: Direction,
 7329        window: &mut Window,
 7330        cx: &mut Context<Self>,
 7331    ) -> Option<()> {
 7332        let provider = self.edit_prediction_provider()?;
 7333        let cursor = self.selections.newest_anchor().head();
 7334        let (buffer, cursor_buffer_position) =
 7335            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7336        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7337            return None;
 7338        }
 7339
 7340        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7341        self.update_visible_edit_prediction(window, cx);
 7342
 7343        Some(())
 7344    }
 7345
 7346    pub fn show_edit_prediction(
 7347        &mut self,
 7348        _: &ShowEditPrediction,
 7349        window: &mut Window,
 7350        cx: &mut Context<Self>,
 7351    ) {
 7352        if !self.has_active_edit_prediction() {
 7353            self.refresh_edit_prediction(false, true, window, cx);
 7354            return;
 7355        }
 7356
 7357        self.update_visible_edit_prediction(window, cx);
 7358    }
 7359
 7360    pub fn display_cursor_names(
 7361        &mut self,
 7362        _: &DisplayCursorNames,
 7363        window: &mut Window,
 7364        cx: &mut Context<Self>,
 7365    ) {
 7366        self.show_cursor_names(window, cx);
 7367    }
 7368
 7369    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7370        self.show_cursor_names = true;
 7371        cx.notify();
 7372        cx.spawn_in(window, async move |this, cx| {
 7373            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7374            this.update(cx, |this, cx| {
 7375                this.show_cursor_names = false;
 7376                cx.notify()
 7377            })
 7378            .ok()
 7379        })
 7380        .detach();
 7381    }
 7382
 7383    pub fn next_edit_prediction(
 7384        &mut self,
 7385        _: &NextEditPrediction,
 7386        window: &mut Window,
 7387        cx: &mut Context<Self>,
 7388    ) {
 7389        if self.has_active_edit_prediction() {
 7390            self.cycle_edit_prediction(Direction::Next, window, cx);
 7391        } else {
 7392            let is_copilot_disabled = self
 7393                .refresh_edit_prediction(false, true, window, cx)
 7394                .is_none();
 7395            if is_copilot_disabled {
 7396                cx.propagate();
 7397            }
 7398        }
 7399    }
 7400
 7401    pub fn previous_edit_prediction(
 7402        &mut self,
 7403        _: &PreviousEditPrediction,
 7404        window: &mut Window,
 7405        cx: &mut Context<Self>,
 7406    ) {
 7407        if self.has_active_edit_prediction() {
 7408            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7409        } else {
 7410            let is_copilot_disabled = self
 7411                .refresh_edit_prediction(false, true, window, cx)
 7412                .is_none();
 7413            if is_copilot_disabled {
 7414                cx.propagate();
 7415            }
 7416        }
 7417    }
 7418
 7419    pub fn accept_edit_prediction(
 7420        &mut self,
 7421        _: &AcceptEditPrediction,
 7422        window: &mut Window,
 7423        cx: &mut Context<Self>,
 7424    ) {
 7425        if self.show_edit_predictions_in_menu() {
 7426            self.hide_context_menu(window, cx);
 7427        }
 7428
 7429        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7430            return;
 7431        };
 7432
 7433        match &active_edit_prediction.completion {
 7434            EditPrediction::MoveWithin { target, .. } => {
 7435                let target = *target;
 7436
 7437                if let Some(position_map) = &self.last_position_map {
 7438                    if position_map
 7439                        .visible_row_range
 7440                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7441                        || !self.edit_prediction_requires_modifier()
 7442                    {
 7443                        self.unfold_ranges(&[target..target], true, false, cx);
 7444                        // Note that this is also done in vim's handler of the Tab action.
 7445                        self.change_selections(
 7446                            SelectionEffects::scroll(Autoscroll::newest()),
 7447                            window,
 7448                            cx,
 7449                            |selections| {
 7450                                selections.select_anchor_ranges([target..target]);
 7451                            },
 7452                        );
 7453                        self.clear_row_highlights::<EditPredictionPreview>();
 7454
 7455                        self.edit_prediction_preview
 7456                            .set_previous_scroll_position(None);
 7457                    } else {
 7458                        self.edit_prediction_preview
 7459                            .set_previous_scroll_position(Some(
 7460                                position_map.snapshot.scroll_anchor,
 7461                            ));
 7462
 7463                        self.highlight_rows::<EditPredictionPreview>(
 7464                            target..target,
 7465                            cx.theme().colors().editor_highlighted_line_background,
 7466                            RowHighlightOptions {
 7467                                autoscroll: true,
 7468                                ..Default::default()
 7469                            },
 7470                            cx,
 7471                        );
 7472                        self.request_autoscroll(Autoscroll::fit(), cx);
 7473                    }
 7474                }
 7475            }
 7476            EditPrediction::MoveOutside { snapshot, target } => {
 7477                if let Some(workspace) = self.workspace() {
 7478                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7479                        .detach_and_log_err(cx);
 7480                }
 7481            }
 7482            EditPrediction::Edit { edits, .. } => {
 7483                self.report_edit_prediction_event(
 7484                    active_edit_prediction.completion_id.clone(),
 7485                    true,
 7486                    cx,
 7487                );
 7488
 7489                if let Some(provider) = self.edit_prediction_provider() {
 7490                    provider.accept(cx);
 7491                }
 7492
 7493                // Store the transaction ID and selections before applying the edit
 7494                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7495
 7496                let snapshot = self.buffer.read(cx).snapshot(cx);
 7497                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7498
 7499                self.buffer.update(cx, |buffer, cx| {
 7500                    buffer.edit(edits.iter().cloned(), None, cx)
 7501                });
 7502
 7503                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7504                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7505                });
 7506
 7507                let selections = self.selections.disjoint_anchors_arc();
 7508                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7509                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7510                    if has_new_transaction {
 7511                        self.selection_history
 7512                            .insert_transaction(transaction_id_now, selections);
 7513                    }
 7514                }
 7515
 7516                self.update_visible_edit_prediction(window, cx);
 7517                if self.active_edit_prediction.is_none() {
 7518                    self.refresh_edit_prediction(true, true, window, cx);
 7519                }
 7520
 7521                cx.notify();
 7522            }
 7523        }
 7524
 7525        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7526    }
 7527
 7528    pub fn accept_partial_edit_prediction(
 7529        &mut self,
 7530        _: &AcceptPartialEditPrediction,
 7531        window: &mut Window,
 7532        cx: &mut Context<Self>,
 7533    ) {
 7534        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7535            return;
 7536        };
 7537        if self.selections.count() != 1 {
 7538            return;
 7539        }
 7540
 7541        match &active_edit_prediction.completion {
 7542            EditPrediction::MoveWithin { target, .. } => {
 7543                let target = *target;
 7544                self.change_selections(
 7545                    SelectionEffects::scroll(Autoscroll::newest()),
 7546                    window,
 7547                    cx,
 7548                    |selections| {
 7549                        selections.select_anchor_ranges([target..target]);
 7550                    },
 7551                );
 7552            }
 7553            EditPrediction::MoveOutside { snapshot, target } => {
 7554                if let Some(workspace) = self.workspace() {
 7555                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7556                        .detach_and_log_err(cx);
 7557                }
 7558            }
 7559            EditPrediction::Edit { edits, .. } => {
 7560                self.report_edit_prediction_event(
 7561                    active_edit_prediction.completion_id.clone(),
 7562                    true,
 7563                    cx,
 7564                );
 7565
 7566                // Find an insertion that starts at the cursor position.
 7567                let snapshot = self.buffer.read(cx).snapshot(cx);
 7568                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7569                let insertion = edits.iter().find_map(|(range, text)| {
 7570                    let range = range.to_offset(&snapshot);
 7571                    if range.is_empty() && range.start == cursor_offset {
 7572                        Some(text)
 7573                    } else {
 7574                        None
 7575                    }
 7576                });
 7577
 7578                if let Some(text) = insertion {
 7579                    let mut partial_completion = text
 7580                        .chars()
 7581                        .by_ref()
 7582                        .take_while(|c| c.is_alphabetic())
 7583                        .collect::<String>();
 7584                    if partial_completion.is_empty() {
 7585                        partial_completion = text
 7586                            .chars()
 7587                            .by_ref()
 7588                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7589                            .collect::<String>();
 7590                    }
 7591
 7592                    cx.emit(EditorEvent::InputHandled {
 7593                        utf16_range_to_replace: None,
 7594                        text: partial_completion.clone().into(),
 7595                    });
 7596
 7597                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7598
 7599                    self.refresh_edit_prediction(true, true, window, cx);
 7600                    cx.notify();
 7601                } else {
 7602                    self.accept_edit_prediction(&Default::default(), window, cx);
 7603                }
 7604            }
 7605        }
 7606    }
 7607
 7608    fn discard_edit_prediction(
 7609        &mut self,
 7610        should_report_edit_prediction_event: bool,
 7611        cx: &mut Context<Self>,
 7612    ) -> bool {
 7613        if should_report_edit_prediction_event {
 7614            let completion_id = self
 7615                .active_edit_prediction
 7616                .as_ref()
 7617                .and_then(|active_completion| active_completion.completion_id.clone());
 7618
 7619            self.report_edit_prediction_event(completion_id, false, cx);
 7620        }
 7621
 7622        if let Some(provider) = self.edit_prediction_provider() {
 7623            provider.discard(cx);
 7624        }
 7625
 7626        self.take_active_edit_prediction(cx)
 7627    }
 7628
 7629    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7630        let Some(provider) = self.edit_prediction_provider() else {
 7631            return;
 7632        };
 7633
 7634        let Some((_, buffer, _)) = self
 7635            .buffer
 7636            .read(cx)
 7637            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7638        else {
 7639            return;
 7640        };
 7641
 7642        let extension = buffer
 7643            .read(cx)
 7644            .file()
 7645            .and_then(|file| Some(file.path().extension()?.to_string()));
 7646
 7647        let event_type = match accepted {
 7648            true => "Edit Prediction Accepted",
 7649            false => "Edit Prediction Discarded",
 7650        };
 7651        telemetry::event!(
 7652            event_type,
 7653            provider = provider.name(),
 7654            prediction_id = id,
 7655            suggestion_accepted = accepted,
 7656            file_extension = extension,
 7657        );
 7658    }
 7659
 7660    fn open_editor_at_anchor(
 7661        snapshot: &language::BufferSnapshot,
 7662        target: language::Anchor,
 7663        workspace: &Entity<Workspace>,
 7664        window: &mut Window,
 7665        cx: &mut App,
 7666    ) -> Task<Result<()>> {
 7667        workspace.update(cx, |workspace, cx| {
 7668            let path = snapshot.file().map(|file| file.full_path(cx));
 7669            let Some(path) =
 7670                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7671            else {
 7672                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7673            };
 7674            let target = text::ToPoint::to_point(&target, snapshot);
 7675            let item = workspace.open_path(path, None, true, window, cx);
 7676            window.spawn(cx, async move |cx| {
 7677                let Some(editor) = item.await?.downcast::<Editor>() else {
 7678                    return Ok(());
 7679                };
 7680                editor
 7681                    .update_in(cx, |editor, window, cx| {
 7682                        editor.go_to_singleton_buffer_point(target, window, cx);
 7683                    })
 7684                    .ok();
 7685                anyhow::Ok(())
 7686            })
 7687        })
 7688    }
 7689
 7690    pub fn has_active_edit_prediction(&self) -> bool {
 7691        self.active_edit_prediction.is_some()
 7692    }
 7693
 7694    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7695        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7696            return false;
 7697        };
 7698
 7699        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7700        self.clear_highlights::<EditPredictionHighlight>(cx);
 7701        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7702        true
 7703    }
 7704
 7705    /// Returns true when we're displaying the edit prediction popover below the cursor
 7706    /// like we are not previewing and the LSP autocomplete menu is visible
 7707    /// or we are in `when_holding_modifier` mode.
 7708    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7709        if self.edit_prediction_preview_is_active()
 7710            || !self.show_edit_predictions_in_menu()
 7711            || !self.edit_predictions_enabled()
 7712        {
 7713            return false;
 7714        }
 7715
 7716        if self.has_visible_completions_menu() {
 7717            return true;
 7718        }
 7719
 7720        has_completion && self.edit_prediction_requires_modifier()
 7721    }
 7722
 7723    fn handle_modifiers_changed(
 7724        &mut self,
 7725        modifiers: Modifiers,
 7726        position_map: &PositionMap,
 7727        window: &mut Window,
 7728        cx: &mut Context<Self>,
 7729    ) {
 7730        if self.show_edit_predictions_in_menu() {
 7731            self.update_edit_prediction_preview(&modifiers, window, cx);
 7732        }
 7733
 7734        self.update_selection_mode(&modifiers, position_map, window, cx);
 7735
 7736        let mouse_position = window.mouse_position();
 7737        if !position_map.text_hitbox.is_hovered(window) {
 7738            return;
 7739        }
 7740
 7741        self.update_hovered_link(
 7742            position_map.point_for_position(mouse_position),
 7743            &position_map.snapshot,
 7744            modifiers,
 7745            window,
 7746            cx,
 7747        )
 7748    }
 7749
 7750    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7751        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7752        if invert {
 7753            match multi_cursor_setting {
 7754                MultiCursorModifier::Alt => modifiers.alt,
 7755                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7756            }
 7757        } else {
 7758            match multi_cursor_setting {
 7759                MultiCursorModifier::Alt => modifiers.secondary(),
 7760                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7761            }
 7762        }
 7763    }
 7764
 7765    fn columnar_selection_mode(
 7766        modifiers: &Modifiers,
 7767        cx: &mut Context<Self>,
 7768    ) -> Option<ColumnarMode> {
 7769        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7770            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7771                Some(ColumnarMode::FromMouse)
 7772            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7773                Some(ColumnarMode::FromSelection)
 7774            } else {
 7775                None
 7776            }
 7777        } else {
 7778            None
 7779        }
 7780    }
 7781
 7782    fn update_selection_mode(
 7783        &mut self,
 7784        modifiers: &Modifiers,
 7785        position_map: &PositionMap,
 7786        window: &mut Window,
 7787        cx: &mut Context<Self>,
 7788    ) {
 7789        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7790            return;
 7791        };
 7792        if self.selections.pending_anchor().is_none() {
 7793            return;
 7794        }
 7795
 7796        let mouse_position = window.mouse_position();
 7797        let point_for_position = position_map.point_for_position(mouse_position);
 7798        let position = point_for_position.previous_valid;
 7799
 7800        self.select(
 7801            SelectPhase::BeginColumnar {
 7802                position,
 7803                reset: false,
 7804                mode,
 7805                goal_column: point_for_position.exact_unclipped.column(),
 7806            },
 7807            window,
 7808            cx,
 7809        );
 7810    }
 7811
 7812    fn update_edit_prediction_preview(
 7813        &mut self,
 7814        modifiers: &Modifiers,
 7815        window: &mut Window,
 7816        cx: &mut Context<Self>,
 7817    ) {
 7818        let mut modifiers_held = false;
 7819        if let Some(accept_keystroke) = self
 7820            .accept_edit_prediction_keybind(false, window, cx)
 7821            .keystroke()
 7822        {
 7823            modifiers_held = modifiers_held
 7824                || (accept_keystroke.modifiers() == modifiers
 7825                    && accept_keystroke.modifiers().modified());
 7826        };
 7827        if let Some(accept_partial_keystroke) = self
 7828            .accept_edit_prediction_keybind(true, window, cx)
 7829            .keystroke()
 7830        {
 7831            modifiers_held = modifiers_held
 7832                || (accept_partial_keystroke.modifiers() == modifiers
 7833                    && accept_partial_keystroke.modifiers().modified());
 7834        }
 7835
 7836        if modifiers_held {
 7837            if matches!(
 7838                self.edit_prediction_preview,
 7839                EditPredictionPreview::Inactive { .. }
 7840            ) {
 7841                self.edit_prediction_preview = EditPredictionPreview::Active {
 7842                    previous_scroll_position: None,
 7843                    since: Instant::now(),
 7844                };
 7845
 7846                self.update_visible_edit_prediction(window, cx);
 7847                cx.notify();
 7848            }
 7849        } else if let EditPredictionPreview::Active {
 7850            previous_scroll_position,
 7851            since,
 7852        } = self.edit_prediction_preview
 7853        {
 7854            if let (Some(previous_scroll_position), Some(position_map)) =
 7855                (previous_scroll_position, self.last_position_map.as_ref())
 7856            {
 7857                self.set_scroll_position(
 7858                    previous_scroll_position
 7859                        .scroll_position(&position_map.snapshot.display_snapshot),
 7860                    window,
 7861                    cx,
 7862                );
 7863            }
 7864
 7865            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7866                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7867            };
 7868            self.clear_row_highlights::<EditPredictionPreview>();
 7869            self.update_visible_edit_prediction(window, cx);
 7870            cx.notify();
 7871        }
 7872    }
 7873
 7874    fn update_visible_edit_prediction(
 7875        &mut self,
 7876        _window: &mut Window,
 7877        cx: &mut Context<Self>,
 7878    ) -> Option<()> {
 7879        if DisableAiSettings::get_global(cx).disable_ai {
 7880            return None;
 7881        }
 7882
 7883        if self.ime_transaction.is_some() {
 7884            self.discard_edit_prediction(false, cx);
 7885            return None;
 7886        }
 7887
 7888        let selection = self.selections.newest_anchor();
 7889        let cursor = selection.head();
 7890        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7891        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7892        let excerpt_id = cursor.excerpt_id;
 7893
 7894        let show_in_menu = self.show_edit_predictions_in_menu();
 7895        let completions_menu_has_precedence = !show_in_menu
 7896            && (self.context_menu.borrow().is_some()
 7897                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7898
 7899        if completions_menu_has_precedence
 7900            || !offset_selection.is_empty()
 7901            || self
 7902                .active_edit_prediction
 7903                .as_ref()
 7904                .is_some_and(|completion| {
 7905                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7906                        return false;
 7907                    };
 7908                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7909                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7910                    !invalidation_range.contains(&offset_selection.head())
 7911                })
 7912        {
 7913            self.discard_edit_prediction(false, cx);
 7914            return None;
 7915        }
 7916
 7917        self.take_active_edit_prediction(cx);
 7918        let Some(provider) = self.edit_prediction_provider() else {
 7919            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7920            return None;
 7921        };
 7922
 7923        let (buffer, cursor_buffer_position) =
 7924            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7925
 7926        self.edit_prediction_settings =
 7927            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7928
 7929        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7930
 7931        if self.edit_prediction_indent_conflict {
 7932            let cursor_point = cursor.to_point(&multibuffer);
 7933
 7934            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7935
 7936            if let Some((_, indent)) = indents.iter().next()
 7937                && indent.len == cursor_point.column
 7938            {
 7939                self.edit_prediction_indent_conflict = false;
 7940            }
 7941        }
 7942
 7943        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7944
 7945        let (completion_id, edits, edit_preview) = match edit_prediction {
 7946            edit_prediction::EditPrediction::Local {
 7947                id,
 7948                edits,
 7949                edit_preview,
 7950            } => (id, edits, edit_preview),
 7951            edit_prediction::EditPrediction::Jump {
 7952                id,
 7953                snapshot,
 7954                target,
 7955            } => {
 7956                self.stale_edit_prediction_in_menu = None;
 7957                self.active_edit_prediction = Some(EditPredictionState {
 7958                    inlay_ids: vec![],
 7959                    completion: EditPrediction::MoveOutside { snapshot, target },
 7960                    completion_id: id,
 7961                    invalidation_range: None,
 7962                });
 7963                cx.notify();
 7964                return Some(());
 7965            }
 7966        };
 7967
 7968        let edits = edits
 7969            .into_iter()
 7970            .flat_map(|(range, new_text)| {
 7971                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7972                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7973                Some((start..end, new_text))
 7974            })
 7975            .collect::<Vec<_>>();
 7976        if edits.is_empty() {
 7977            return None;
 7978        }
 7979
 7980        let first_edit_start = edits.first().unwrap().0.start;
 7981        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7982        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7983
 7984        let last_edit_end = edits.last().unwrap().0.end;
 7985        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7986        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7987
 7988        let cursor_row = cursor.to_point(&multibuffer).row;
 7989
 7990        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7991
 7992        let mut inlay_ids = Vec::new();
 7993        let invalidation_row_range;
 7994        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7995            Some(cursor_row..edit_end_row)
 7996        } else if cursor_row > edit_end_row {
 7997            Some(edit_start_row..cursor_row)
 7998        } else {
 7999            None
 8000        };
 8001        let supports_jump = self
 8002            .edit_prediction_provider
 8003            .as_ref()
 8004            .map(|provider| provider.provider.supports_jump_to_edit())
 8005            .unwrap_or(true);
 8006
 8007        let is_move = supports_jump
 8008            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8009        let completion = if is_move {
 8010            invalidation_row_range =
 8011                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8012            let target = first_edit_start;
 8013            EditPrediction::MoveWithin { target, snapshot }
 8014        } else {
 8015            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8016                && !self.edit_predictions_hidden_for_vim_mode;
 8017
 8018            if show_completions_in_buffer {
 8019                if edits
 8020                    .iter()
 8021                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8022                {
 8023                    let mut inlays = Vec::new();
 8024                    for (range, new_text) in &edits {
 8025                        let inlay = Inlay::edit_prediction(
 8026                            post_inc(&mut self.next_inlay_id),
 8027                            range.start,
 8028                            new_text.as_str(),
 8029                        );
 8030                        inlay_ids.push(inlay.id);
 8031                        inlays.push(inlay);
 8032                    }
 8033
 8034                    self.splice_inlays(&[], inlays, cx);
 8035                } else {
 8036                    let background_color = cx.theme().status().deleted_background;
 8037                    self.highlight_text::<EditPredictionHighlight>(
 8038                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8039                        HighlightStyle {
 8040                            background_color: Some(background_color),
 8041                            ..Default::default()
 8042                        },
 8043                        cx,
 8044                    );
 8045                }
 8046            }
 8047
 8048            invalidation_row_range = edit_start_row..edit_end_row;
 8049
 8050            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8051                if provider.show_tab_accept_marker() {
 8052                    EditDisplayMode::TabAccept
 8053                } else {
 8054                    EditDisplayMode::Inline
 8055                }
 8056            } else {
 8057                EditDisplayMode::DiffPopover
 8058            };
 8059
 8060            EditPrediction::Edit {
 8061                edits,
 8062                edit_preview,
 8063                display_mode,
 8064                snapshot,
 8065            }
 8066        };
 8067
 8068        let invalidation_range = multibuffer
 8069            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8070            ..multibuffer.anchor_after(Point::new(
 8071                invalidation_row_range.end,
 8072                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8073            ));
 8074
 8075        self.stale_edit_prediction_in_menu = None;
 8076        self.active_edit_prediction = Some(EditPredictionState {
 8077            inlay_ids,
 8078            completion,
 8079            completion_id,
 8080            invalidation_range: Some(invalidation_range),
 8081        });
 8082
 8083        cx.notify();
 8084
 8085        Some(())
 8086    }
 8087
 8088    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8089        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8090    }
 8091
 8092    fn clear_tasks(&mut self) {
 8093        self.tasks.clear()
 8094    }
 8095
 8096    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8097        if self.tasks.insert(key, value).is_some() {
 8098            // This case should hopefully be rare, but just in case...
 8099            log::error!(
 8100                "multiple different run targets found on a single line, only the last target will be rendered"
 8101            )
 8102        }
 8103    }
 8104
 8105    /// Get all display points of breakpoints that will be rendered within editor
 8106    ///
 8107    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8108    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8109    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8110    fn active_breakpoints(
 8111        &self,
 8112        range: Range<DisplayRow>,
 8113        window: &mut Window,
 8114        cx: &mut Context<Self>,
 8115    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8116        let mut breakpoint_display_points = HashMap::default();
 8117
 8118        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8119            return breakpoint_display_points;
 8120        };
 8121
 8122        let snapshot = self.snapshot(window, cx);
 8123
 8124        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8125        let Some(project) = self.project() else {
 8126            return breakpoint_display_points;
 8127        };
 8128
 8129        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8130            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8131
 8132        for (buffer_snapshot, range, excerpt_id) in
 8133            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8134        {
 8135            let Some(buffer) = project
 8136                .read(cx)
 8137                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8138            else {
 8139                continue;
 8140            };
 8141            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8142                &buffer,
 8143                Some(
 8144                    buffer_snapshot.anchor_before(range.start)
 8145                        ..buffer_snapshot.anchor_after(range.end),
 8146                ),
 8147                buffer_snapshot,
 8148                cx,
 8149            );
 8150            for (breakpoint, state) in breakpoints {
 8151                let multi_buffer_anchor =
 8152                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8153                let position = multi_buffer_anchor
 8154                    .to_point(multi_buffer_snapshot)
 8155                    .to_display_point(&snapshot);
 8156
 8157                breakpoint_display_points.insert(
 8158                    position.row(),
 8159                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8160                );
 8161            }
 8162        }
 8163
 8164        breakpoint_display_points
 8165    }
 8166
 8167    fn breakpoint_context_menu(
 8168        &self,
 8169        anchor: Anchor,
 8170        window: &mut Window,
 8171        cx: &mut Context<Self>,
 8172    ) -> Entity<ui::ContextMenu> {
 8173        let weak_editor = cx.weak_entity();
 8174        let focus_handle = self.focus_handle(cx);
 8175
 8176        let row = self
 8177            .buffer
 8178            .read(cx)
 8179            .snapshot(cx)
 8180            .summary_for_anchor::<Point>(&anchor)
 8181            .row;
 8182
 8183        let breakpoint = self
 8184            .breakpoint_at_row(row, window, cx)
 8185            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8186
 8187        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8188            "Edit Log Breakpoint"
 8189        } else {
 8190            "Set Log Breakpoint"
 8191        };
 8192
 8193        let condition_breakpoint_msg = if breakpoint
 8194            .as_ref()
 8195            .is_some_and(|bp| bp.1.condition.is_some())
 8196        {
 8197            "Edit Condition Breakpoint"
 8198        } else {
 8199            "Set Condition Breakpoint"
 8200        };
 8201
 8202        let hit_condition_breakpoint_msg = if breakpoint
 8203            .as_ref()
 8204            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8205        {
 8206            "Edit Hit Condition Breakpoint"
 8207        } else {
 8208            "Set Hit Condition Breakpoint"
 8209        };
 8210
 8211        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8212            "Unset Breakpoint"
 8213        } else {
 8214            "Set Breakpoint"
 8215        };
 8216
 8217        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8218
 8219        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8220            BreakpointState::Enabled => Some("Disable"),
 8221            BreakpointState::Disabled => Some("Enable"),
 8222        });
 8223
 8224        let (anchor, breakpoint) =
 8225            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8226
 8227        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8228            menu.on_blur_subscription(Subscription::new(|| {}))
 8229                .context(focus_handle)
 8230                .when(run_to_cursor, |this| {
 8231                    let weak_editor = weak_editor.clone();
 8232                    this.entry("Run to cursor", None, move |window, cx| {
 8233                        weak_editor
 8234                            .update(cx, |editor, cx| {
 8235                                editor.change_selections(
 8236                                    SelectionEffects::no_scroll(),
 8237                                    window,
 8238                                    cx,
 8239                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8240                                );
 8241                            })
 8242                            .ok();
 8243
 8244                        window.dispatch_action(Box::new(RunToCursor), cx);
 8245                    })
 8246                    .separator()
 8247                })
 8248                .when_some(toggle_state_msg, |this, msg| {
 8249                    this.entry(msg, None, {
 8250                        let weak_editor = weak_editor.clone();
 8251                        let breakpoint = breakpoint.clone();
 8252                        move |_window, cx| {
 8253                            weak_editor
 8254                                .update(cx, |this, cx| {
 8255                                    this.edit_breakpoint_at_anchor(
 8256                                        anchor,
 8257                                        breakpoint.as_ref().clone(),
 8258                                        BreakpointEditAction::InvertState,
 8259                                        cx,
 8260                                    );
 8261                                })
 8262                                .log_err();
 8263                        }
 8264                    })
 8265                })
 8266                .entry(set_breakpoint_msg, None, {
 8267                    let weak_editor = weak_editor.clone();
 8268                    let breakpoint = breakpoint.clone();
 8269                    move |_window, cx| {
 8270                        weak_editor
 8271                            .update(cx, |this, cx| {
 8272                                this.edit_breakpoint_at_anchor(
 8273                                    anchor,
 8274                                    breakpoint.as_ref().clone(),
 8275                                    BreakpointEditAction::Toggle,
 8276                                    cx,
 8277                                );
 8278                            })
 8279                            .log_err();
 8280                    }
 8281                })
 8282                .entry(log_breakpoint_msg, None, {
 8283                    let breakpoint = breakpoint.clone();
 8284                    let weak_editor = weak_editor.clone();
 8285                    move |window, cx| {
 8286                        weak_editor
 8287                            .update(cx, |this, cx| {
 8288                                this.add_edit_breakpoint_block(
 8289                                    anchor,
 8290                                    breakpoint.as_ref(),
 8291                                    BreakpointPromptEditAction::Log,
 8292                                    window,
 8293                                    cx,
 8294                                );
 8295                            })
 8296                            .log_err();
 8297                    }
 8298                })
 8299                .entry(condition_breakpoint_msg, None, {
 8300                    let breakpoint = breakpoint.clone();
 8301                    let weak_editor = weak_editor.clone();
 8302                    move |window, cx| {
 8303                        weak_editor
 8304                            .update(cx, |this, cx| {
 8305                                this.add_edit_breakpoint_block(
 8306                                    anchor,
 8307                                    breakpoint.as_ref(),
 8308                                    BreakpointPromptEditAction::Condition,
 8309                                    window,
 8310                                    cx,
 8311                                );
 8312                            })
 8313                            .log_err();
 8314                    }
 8315                })
 8316                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8317                    weak_editor
 8318                        .update(cx, |this, cx| {
 8319                            this.add_edit_breakpoint_block(
 8320                                anchor,
 8321                                breakpoint.as_ref(),
 8322                                BreakpointPromptEditAction::HitCondition,
 8323                                window,
 8324                                cx,
 8325                            );
 8326                        })
 8327                        .log_err();
 8328                })
 8329        })
 8330    }
 8331
 8332    fn render_breakpoint(
 8333        &self,
 8334        position: Anchor,
 8335        row: DisplayRow,
 8336        breakpoint: &Breakpoint,
 8337        state: Option<BreakpointSessionState>,
 8338        cx: &mut Context<Self>,
 8339    ) -> IconButton {
 8340        let is_rejected = state.is_some_and(|s| !s.verified);
 8341        // Is it a breakpoint that shows up when hovering over gutter?
 8342        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8343            (false, false),
 8344            |PhantomBreakpointIndicator {
 8345                 is_active,
 8346                 display_row,
 8347                 collides_with_existing_breakpoint,
 8348             }| {
 8349                (
 8350                    is_active && display_row == row,
 8351                    collides_with_existing_breakpoint,
 8352                )
 8353            },
 8354        );
 8355
 8356        let (color, icon) = {
 8357            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8358                (false, false) => ui::IconName::DebugBreakpoint,
 8359                (true, false) => ui::IconName::DebugLogBreakpoint,
 8360                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8361                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8362            };
 8363
 8364            let color = if is_phantom {
 8365                Color::Hint
 8366            } else if is_rejected {
 8367                Color::Disabled
 8368            } else {
 8369                Color::Debugger
 8370            };
 8371
 8372            (color, icon)
 8373        };
 8374
 8375        let breakpoint = Arc::from(breakpoint.clone());
 8376
 8377        let alt_as_text = gpui::Keystroke {
 8378            modifiers: Modifiers::secondary_key(),
 8379            ..Default::default()
 8380        };
 8381        let primary_action_text = if breakpoint.is_disabled() {
 8382            "Enable breakpoint"
 8383        } else if is_phantom && !collides_with_existing {
 8384            "Set breakpoint"
 8385        } else {
 8386            "Unset breakpoint"
 8387        };
 8388        let focus_handle = self.focus_handle.clone();
 8389
 8390        let meta = if is_rejected {
 8391            SharedString::from("No executable code is associated with this line.")
 8392        } else if collides_with_existing && !breakpoint.is_disabled() {
 8393            SharedString::from(format!(
 8394                "{alt_as_text}-click to disable,\nright-click for more options."
 8395            ))
 8396        } else {
 8397            SharedString::from("Right-click for more options.")
 8398        };
 8399        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8400            .icon_size(IconSize::XSmall)
 8401            .size(ui::ButtonSize::None)
 8402            .when(is_rejected, |this| {
 8403                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8404            })
 8405            .icon_color(color)
 8406            .style(ButtonStyle::Transparent)
 8407            .on_click(cx.listener({
 8408                move |editor, event: &ClickEvent, window, cx| {
 8409                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8410                        BreakpointEditAction::InvertState
 8411                    } else {
 8412                        BreakpointEditAction::Toggle
 8413                    };
 8414
 8415                    window.focus(&editor.focus_handle(cx));
 8416                    editor.edit_breakpoint_at_anchor(
 8417                        position,
 8418                        breakpoint.as_ref().clone(),
 8419                        edit_action,
 8420                        cx,
 8421                    );
 8422                }
 8423            }))
 8424            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8425                editor.set_breakpoint_context_menu(
 8426                    row,
 8427                    Some(position),
 8428                    event.position(),
 8429                    window,
 8430                    cx,
 8431                );
 8432            }))
 8433            .tooltip(move |window, cx| {
 8434                Tooltip::with_meta_in(
 8435                    primary_action_text,
 8436                    Some(&ToggleBreakpoint),
 8437                    meta.clone(),
 8438                    &focus_handle,
 8439                    window,
 8440                    cx,
 8441                )
 8442            })
 8443    }
 8444
 8445    fn build_tasks_context(
 8446        project: &Entity<Project>,
 8447        buffer: &Entity<Buffer>,
 8448        buffer_row: u32,
 8449        tasks: &Arc<RunnableTasks>,
 8450        cx: &mut Context<Self>,
 8451    ) -> Task<Option<task::TaskContext>> {
 8452        let position = Point::new(buffer_row, tasks.column);
 8453        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8454        let location = Location {
 8455            buffer: buffer.clone(),
 8456            range: range_start..range_start,
 8457        };
 8458        // Fill in the environmental variables from the tree-sitter captures
 8459        let mut captured_task_variables = TaskVariables::default();
 8460        for (capture_name, value) in tasks.extra_variables.clone() {
 8461            captured_task_variables.insert(
 8462                task::VariableName::Custom(capture_name.into()),
 8463                value.clone(),
 8464            );
 8465        }
 8466        project.update(cx, |project, cx| {
 8467            project.task_store().update(cx, |task_store, cx| {
 8468                task_store.task_context_for_location(captured_task_variables, location, cx)
 8469            })
 8470        })
 8471    }
 8472
 8473    pub fn spawn_nearest_task(
 8474        &mut self,
 8475        action: &SpawnNearestTask,
 8476        window: &mut Window,
 8477        cx: &mut Context<Self>,
 8478    ) {
 8479        let Some((workspace, _)) = self.workspace.clone() else {
 8480            return;
 8481        };
 8482        let Some(project) = self.project.clone() else {
 8483            return;
 8484        };
 8485
 8486        // Try to find a closest, enclosing node using tree-sitter that has a task
 8487        let Some((buffer, buffer_row, tasks)) = self
 8488            .find_enclosing_node_task(cx)
 8489            // Or find the task that's closest in row-distance.
 8490            .or_else(|| self.find_closest_task(cx))
 8491        else {
 8492            return;
 8493        };
 8494
 8495        let reveal_strategy = action.reveal;
 8496        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8497        cx.spawn_in(window, async move |_, cx| {
 8498            let context = task_context.await?;
 8499            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8500
 8501            let resolved = &mut resolved_task.resolved;
 8502            resolved.reveal = reveal_strategy;
 8503
 8504            workspace
 8505                .update_in(cx, |workspace, window, cx| {
 8506                    workspace.schedule_resolved_task(
 8507                        task_source_kind,
 8508                        resolved_task,
 8509                        false,
 8510                        window,
 8511                        cx,
 8512                    );
 8513                })
 8514                .ok()
 8515        })
 8516        .detach();
 8517    }
 8518
 8519    fn find_closest_task(
 8520        &mut self,
 8521        cx: &mut Context<Self>,
 8522    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8523        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8524
 8525        let ((buffer_id, row), tasks) = self
 8526            .tasks
 8527            .iter()
 8528            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8529
 8530        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8531        let tasks = Arc::new(tasks.to_owned());
 8532        Some((buffer, *row, tasks))
 8533    }
 8534
 8535    fn find_enclosing_node_task(
 8536        &mut self,
 8537        cx: &mut Context<Self>,
 8538    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8539        let snapshot = self.buffer.read(cx).snapshot(cx);
 8540        let offset = self.selections.newest::<usize>(cx).head();
 8541        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8542        let buffer_id = excerpt.buffer().remote_id();
 8543
 8544        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8545        let mut cursor = layer.node().walk();
 8546
 8547        while cursor.goto_first_child_for_byte(offset).is_some() {
 8548            if cursor.node().end_byte() == offset {
 8549                cursor.goto_next_sibling();
 8550            }
 8551        }
 8552
 8553        // Ascend to the smallest ancestor that contains the range and has a task.
 8554        loop {
 8555            let node = cursor.node();
 8556            let node_range = node.byte_range();
 8557            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8558
 8559            // Check if this node contains our offset
 8560            if node_range.start <= offset && node_range.end >= offset {
 8561                // If it contains offset, check for task
 8562                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8563                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8564                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8565                }
 8566            }
 8567
 8568            if !cursor.goto_parent() {
 8569                break;
 8570            }
 8571        }
 8572        None
 8573    }
 8574
 8575    fn render_run_indicator(
 8576        &self,
 8577        _style: &EditorStyle,
 8578        is_active: bool,
 8579        row: DisplayRow,
 8580        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8581        cx: &mut Context<Self>,
 8582    ) -> IconButton {
 8583        let color = Color::Muted;
 8584        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8585
 8586        IconButton::new(
 8587            ("run_indicator", row.0 as usize),
 8588            ui::IconName::PlayOutlined,
 8589        )
 8590        .shape(ui::IconButtonShape::Square)
 8591        .icon_size(IconSize::XSmall)
 8592        .icon_color(color)
 8593        .toggle_state(is_active)
 8594        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8595            let quick_launch = match e {
 8596                ClickEvent::Keyboard(_) => true,
 8597                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8598            };
 8599
 8600            window.focus(&editor.focus_handle(cx));
 8601            editor.toggle_code_actions(
 8602                &ToggleCodeActions {
 8603                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8604                    quick_launch,
 8605                },
 8606                window,
 8607                cx,
 8608            );
 8609        }))
 8610        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8611            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8612        }))
 8613    }
 8614
 8615    pub fn context_menu_visible(&self) -> bool {
 8616        !self.edit_prediction_preview_is_active()
 8617            && self
 8618                .context_menu
 8619                .borrow()
 8620                .as_ref()
 8621                .is_some_and(|menu| menu.visible())
 8622    }
 8623
 8624    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8625        self.context_menu
 8626            .borrow()
 8627            .as_ref()
 8628            .map(|menu| menu.origin())
 8629    }
 8630
 8631    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8632        self.context_menu_options = Some(options);
 8633    }
 8634
 8635    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8636    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8637
 8638    fn render_edit_prediction_popover(
 8639        &mut self,
 8640        text_bounds: &Bounds<Pixels>,
 8641        content_origin: gpui::Point<Pixels>,
 8642        right_margin: Pixels,
 8643        editor_snapshot: &EditorSnapshot,
 8644        visible_row_range: Range<DisplayRow>,
 8645        scroll_top: ScrollOffset,
 8646        scroll_bottom: ScrollOffset,
 8647        line_layouts: &[LineWithInvisibles],
 8648        line_height: Pixels,
 8649        scroll_position: gpui::Point<ScrollOffset>,
 8650        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8651        newest_selection_head: Option<DisplayPoint>,
 8652        editor_width: Pixels,
 8653        style: &EditorStyle,
 8654        window: &mut Window,
 8655        cx: &mut App,
 8656    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8657        if self.mode().is_minimap() {
 8658            return None;
 8659        }
 8660        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8661
 8662        if self.edit_prediction_visible_in_cursor_popover(true) {
 8663            return None;
 8664        }
 8665
 8666        match &active_edit_prediction.completion {
 8667            EditPrediction::MoveWithin { target, .. } => {
 8668                let target_display_point = target.to_display_point(editor_snapshot);
 8669
 8670                if self.edit_prediction_requires_modifier() {
 8671                    if !self.edit_prediction_preview_is_active() {
 8672                        return None;
 8673                    }
 8674
 8675                    self.render_edit_prediction_modifier_jump_popover(
 8676                        text_bounds,
 8677                        content_origin,
 8678                        visible_row_range,
 8679                        line_layouts,
 8680                        line_height,
 8681                        scroll_pixel_position,
 8682                        newest_selection_head,
 8683                        target_display_point,
 8684                        window,
 8685                        cx,
 8686                    )
 8687                } else {
 8688                    self.render_edit_prediction_eager_jump_popover(
 8689                        text_bounds,
 8690                        content_origin,
 8691                        editor_snapshot,
 8692                        visible_row_range,
 8693                        scroll_top,
 8694                        scroll_bottom,
 8695                        line_height,
 8696                        scroll_pixel_position,
 8697                        target_display_point,
 8698                        editor_width,
 8699                        window,
 8700                        cx,
 8701                    )
 8702                }
 8703            }
 8704            EditPrediction::Edit {
 8705                display_mode: EditDisplayMode::Inline,
 8706                ..
 8707            } => None,
 8708            EditPrediction::Edit {
 8709                display_mode: EditDisplayMode::TabAccept,
 8710                edits,
 8711                ..
 8712            } => {
 8713                let range = &edits.first()?.0;
 8714                let target_display_point = range.end.to_display_point(editor_snapshot);
 8715
 8716                self.render_edit_prediction_end_of_line_popover(
 8717                    "Accept",
 8718                    editor_snapshot,
 8719                    visible_row_range,
 8720                    target_display_point,
 8721                    line_height,
 8722                    scroll_pixel_position,
 8723                    content_origin,
 8724                    editor_width,
 8725                    window,
 8726                    cx,
 8727                )
 8728            }
 8729            EditPrediction::Edit {
 8730                edits,
 8731                edit_preview,
 8732                display_mode: EditDisplayMode::DiffPopover,
 8733                snapshot,
 8734            } => self.render_edit_prediction_diff_popover(
 8735                text_bounds,
 8736                content_origin,
 8737                right_margin,
 8738                editor_snapshot,
 8739                visible_row_range,
 8740                line_layouts,
 8741                line_height,
 8742                scroll_position,
 8743                scroll_pixel_position,
 8744                newest_selection_head,
 8745                editor_width,
 8746                style,
 8747                edits,
 8748                edit_preview,
 8749                snapshot,
 8750                window,
 8751                cx,
 8752            ),
 8753            EditPrediction::MoveOutside { snapshot, .. } => {
 8754                let file_name = snapshot
 8755                    .file()
 8756                    .map(|file| file.file_name(cx))
 8757                    .unwrap_or("untitled");
 8758                let mut element = self
 8759                    .render_edit_prediction_line_popover(
 8760                        format!("Jump to {file_name}"),
 8761                        Some(IconName::ZedPredict),
 8762                        window,
 8763                        cx,
 8764                    )
 8765                    .into_any();
 8766
 8767                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8768                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8769                let origin_y = text_bounds.size.height - size.height - px(30.);
 8770                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8771                element.prepaint_at(origin, window, cx);
 8772
 8773                Some((element, origin))
 8774            }
 8775        }
 8776    }
 8777
 8778    fn render_edit_prediction_modifier_jump_popover(
 8779        &mut self,
 8780        text_bounds: &Bounds<Pixels>,
 8781        content_origin: gpui::Point<Pixels>,
 8782        visible_row_range: Range<DisplayRow>,
 8783        line_layouts: &[LineWithInvisibles],
 8784        line_height: Pixels,
 8785        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8786        newest_selection_head: Option<DisplayPoint>,
 8787        target_display_point: DisplayPoint,
 8788        window: &mut Window,
 8789        cx: &mut App,
 8790    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8791        let scrolled_content_origin =
 8792            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8793
 8794        const SCROLL_PADDING_Y: Pixels = px(12.);
 8795
 8796        if target_display_point.row() < visible_row_range.start {
 8797            return self.render_edit_prediction_scroll_popover(
 8798                |_| SCROLL_PADDING_Y,
 8799                IconName::ArrowUp,
 8800                visible_row_range,
 8801                line_layouts,
 8802                newest_selection_head,
 8803                scrolled_content_origin,
 8804                window,
 8805                cx,
 8806            );
 8807        } else if target_display_point.row() >= visible_row_range.end {
 8808            return self.render_edit_prediction_scroll_popover(
 8809                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8810                IconName::ArrowDown,
 8811                visible_row_range,
 8812                line_layouts,
 8813                newest_selection_head,
 8814                scrolled_content_origin,
 8815                window,
 8816                cx,
 8817            );
 8818        }
 8819
 8820        const POLE_WIDTH: Pixels = px(2.);
 8821
 8822        let line_layout =
 8823            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8824        let target_column = target_display_point.column() as usize;
 8825
 8826        let target_x = line_layout.x_for_index(target_column);
 8827        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8828            - scroll_pixel_position.y;
 8829
 8830        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8831
 8832        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8833        border_color.l += 0.001;
 8834
 8835        let mut element = v_flex()
 8836            .items_end()
 8837            .when(flag_on_right, |el| el.items_start())
 8838            .child(if flag_on_right {
 8839                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8840                    .rounded_bl(px(0.))
 8841                    .rounded_tl(px(0.))
 8842                    .border_l_2()
 8843                    .border_color(border_color)
 8844            } else {
 8845                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8846                    .rounded_br(px(0.))
 8847                    .rounded_tr(px(0.))
 8848                    .border_r_2()
 8849                    .border_color(border_color)
 8850            })
 8851            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8852            .into_any();
 8853
 8854        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8855
 8856        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8857            - point(
 8858                if flag_on_right {
 8859                    POLE_WIDTH
 8860                } else {
 8861                    size.width - POLE_WIDTH
 8862                },
 8863                size.height - line_height,
 8864            );
 8865
 8866        origin.x = origin.x.max(content_origin.x);
 8867
 8868        element.prepaint_at(origin, window, cx);
 8869
 8870        Some((element, origin))
 8871    }
 8872
 8873    fn render_edit_prediction_scroll_popover(
 8874        &mut self,
 8875        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8876        scroll_icon: IconName,
 8877        visible_row_range: Range<DisplayRow>,
 8878        line_layouts: &[LineWithInvisibles],
 8879        newest_selection_head: Option<DisplayPoint>,
 8880        scrolled_content_origin: gpui::Point<Pixels>,
 8881        window: &mut Window,
 8882        cx: &mut App,
 8883    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8884        let mut element = self
 8885            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8886            .into_any();
 8887
 8888        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8889
 8890        let cursor = newest_selection_head?;
 8891        let cursor_row_layout =
 8892            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8893        let cursor_column = cursor.column() as usize;
 8894
 8895        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8896
 8897        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8898
 8899        element.prepaint_at(origin, window, cx);
 8900        Some((element, origin))
 8901    }
 8902
 8903    fn render_edit_prediction_eager_jump_popover(
 8904        &mut self,
 8905        text_bounds: &Bounds<Pixels>,
 8906        content_origin: gpui::Point<Pixels>,
 8907        editor_snapshot: &EditorSnapshot,
 8908        visible_row_range: Range<DisplayRow>,
 8909        scroll_top: ScrollOffset,
 8910        scroll_bottom: ScrollOffset,
 8911        line_height: Pixels,
 8912        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8913        target_display_point: DisplayPoint,
 8914        editor_width: Pixels,
 8915        window: &mut Window,
 8916        cx: &mut App,
 8917    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8918        if target_display_point.row().as_f64() < scroll_top {
 8919            let mut element = self
 8920                .render_edit_prediction_line_popover(
 8921                    "Jump to Edit",
 8922                    Some(IconName::ArrowUp),
 8923                    window,
 8924                    cx,
 8925                )
 8926                .into_any();
 8927
 8928            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8929            let offset = point(
 8930                (text_bounds.size.width - size.width) / 2.,
 8931                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8932            );
 8933
 8934            let origin = text_bounds.origin + offset;
 8935            element.prepaint_at(origin, window, cx);
 8936            Some((element, origin))
 8937        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8938            let mut element = self
 8939                .render_edit_prediction_line_popover(
 8940                    "Jump to Edit",
 8941                    Some(IconName::ArrowDown),
 8942                    window,
 8943                    cx,
 8944                )
 8945                .into_any();
 8946
 8947            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8948            let offset = point(
 8949                (text_bounds.size.width - size.width) / 2.,
 8950                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8951            );
 8952
 8953            let origin = text_bounds.origin + offset;
 8954            element.prepaint_at(origin, window, cx);
 8955            Some((element, origin))
 8956        } else {
 8957            self.render_edit_prediction_end_of_line_popover(
 8958                "Jump to Edit",
 8959                editor_snapshot,
 8960                visible_row_range,
 8961                target_display_point,
 8962                line_height,
 8963                scroll_pixel_position,
 8964                content_origin,
 8965                editor_width,
 8966                window,
 8967                cx,
 8968            )
 8969        }
 8970    }
 8971
 8972    fn render_edit_prediction_end_of_line_popover(
 8973        self: &mut Editor,
 8974        label: &'static str,
 8975        editor_snapshot: &EditorSnapshot,
 8976        visible_row_range: Range<DisplayRow>,
 8977        target_display_point: DisplayPoint,
 8978        line_height: Pixels,
 8979        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8980        content_origin: gpui::Point<Pixels>,
 8981        editor_width: Pixels,
 8982        window: &mut Window,
 8983        cx: &mut App,
 8984    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8985        let target_line_end = DisplayPoint::new(
 8986            target_display_point.row(),
 8987            editor_snapshot.line_len(target_display_point.row()),
 8988        );
 8989
 8990        let mut element = self
 8991            .render_edit_prediction_line_popover(label, None, window, cx)
 8992            .into_any();
 8993
 8994        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8995
 8996        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8997
 8998        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8999        let mut origin = start_point
 9000            + line_origin
 9001            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9002        origin.x = origin.x.max(content_origin.x);
 9003
 9004        let max_x = content_origin.x + editor_width - size.width;
 9005
 9006        if origin.x > max_x {
 9007            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9008
 9009            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9010                origin.y += offset;
 9011                IconName::ArrowUp
 9012            } else {
 9013                origin.y -= offset;
 9014                IconName::ArrowDown
 9015            };
 9016
 9017            element = self
 9018                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9019                .into_any();
 9020
 9021            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9022
 9023            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9024        }
 9025
 9026        element.prepaint_at(origin, window, cx);
 9027        Some((element, origin))
 9028    }
 9029
 9030    fn render_edit_prediction_diff_popover(
 9031        self: &Editor,
 9032        text_bounds: &Bounds<Pixels>,
 9033        content_origin: gpui::Point<Pixels>,
 9034        right_margin: Pixels,
 9035        editor_snapshot: &EditorSnapshot,
 9036        visible_row_range: Range<DisplayRow>,
 9037        line_layouts: &[LineWithInvisibles],
 9038        line_height: Pixels,
 9039        scroll_position: gpui::Point<ScrollOffset>,
 9040        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9041        newest_selection_head: Option<DisplayPoint>,
 9042        editor_width: Pixels,
 9043        style: &EditorStyle,
 9044        edits: &Vec<(Range<Anchor>, String)>,
 9045        edit_preview: &Option<language::EditPreview>,
 9046        snapshot: &language::BufferSnapshot,
 9047        window: &mut Window,
 9048        cx: &mut App,
 9049    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9050        let edit_start = edits
 9051            .first()
 9052            .unwrap()
 9053            .0
 9054            .start
 9055            .to_display_point(editor_snapshot);
 9056        let edit_end = edits
 9057            .last()
 9058            .unwrap()
 9059            .0
 9060            .end
 9061            .to_display_point(editor_snapshot);
 9062
 9063        let is_visible = visible_row_range.contains(&edit_start.row())
 9064            || visible_row_range.contains(&edit_end.row());
 9065        if !is_visible {
 9066            return None;
 9067        }
 9068
 9069        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9070            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9071        } else {
 9072            // Fallback for providers without edit_preview
 9073            crate::edit_prediction_fallback_text(edits, cx)
 9074        };
 9075
 9076        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9077        let line_count = highlighted_edits.text.lines().count();
 9078
 9079        const BORDER_WIDTH: Pixels = px(1.);
 9080
 9081        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9082        let has_keybind = keybind.is_some();
 9083
 9084        let mut element = h_flex()
 9085            .items_start()
 9086            .child(
 9087                h_flex()
 9088                    .bg(cx.theme().colors().editor_background)
 9089                    .border(BORDER_WIDTH)
 9090                    .shadow_xs()
 9091                    .border_color(cx.theme().colors().border)
 9092                    .rounded_l_lg()
 9093                    .when(line_count > 1, |el| el.rounded_br_lg())
 9094                    .pr_1()
 9095                    .child(styled_text),
 9096            )
 9097            .child(
 9098                h_flex()
 9099                    .h(line_height + BORDER_WIDTH * 2.)
 9100                    .px_1p5()
 9101                    .gap_1()
 9102                    // Workaround: For some reason, there's a gap if we don't do this
 9103                    .ml(-BORDER_WIDTH)
 9104                    .shadow(vec![gpui::BoxShadow {
 9105                        color: gpui::black().opacity(0.05),
 9106                        offset: point(px(1.), px(1.)),
 9107                        blur_radius: px(2.),
 9108                        spread_radius: px(0.),
 9109                    }])
 9110                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9111                    .border(BORDER_WIDTH)
 9112                    .border_color(cx.theme().colors().border)
 9113                    .rounded_r_lg()
 9114                    .id("edit_prediction_diff_popover_keybind")
 9115                    .when(!has_keybind, |el| {
 9116                        let status_colors = cx.theme().status();
 9117
 9118                        el.bg(status_colors.error_background)
 9119                            .border_color(status_colors.error.opacity(0.6))
 9120                            .child(Icon::new(IconName::Info).color(Color::Error))
 9121                            .cursor_default()
 9122                            .hoverable_tooltip(move |_window, cx| {
 9123                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9124                            })
 9125                    })
 9126                    .children(keybind),
 9127            )
 9128            .into_any();
 9129
 9130        let longest_row =
 9131            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9132        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9133            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9134        } else {
 9135            layout_line(
 9136                longest_row,
 9137                editor_snapshot,
 9138                style,
 9139                editor_width,
 9140                |_| false,
 9141                window,
 9142                cx,
 9143            )
 9144            .width
 9145        };
 9146
 9147        let viewport_bounds =
 9148            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9149                right: -right_margin,
 9150                ..Default::default()
 9151            });
 9152
 9153        let x_after_longest = Pixels::from(
 9154            ScrollPixelOffset::from(
 9155                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9156            ) - scroll_pixel_position.x,
 9157        );
 9158
 9159        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9160
 9161        // Fully visible if it can be displayed within the window (allow overlapping other
 9162        // panes). However, this is only allowed if the popover starts within text_bounds.
 9163        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9164            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9165
 9166        let mut origin = if can_position_to_the_right {
 9167            point(
 9168                x_after_longest,
 9169                text_bounds.origin.y
 9170                    + Pixels::from(
 9171                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9172                            - scroll_pixel_position.y,
 9173                    ),
 9174            )
 9175        } else {
 9176            let cursor_row = newest_selection_head.map(|head| head.row());
 9177            let above_edit = edit_start
 9178                .row()
 9179                .0
 9180                .checked_sub(line_count as u32)
 9181                .map(DisplayRow);
 9182            let below_edit = Some(edit_end.row() + 1);
 9183            let above_cursor =
 9184                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9185            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9186
 9187            // Place the edit popover adjacent to the edit if there is a location
 9188            // available that is onscreen and does not obscure the cursor. Otherwise,
 9189            // place it adjacent to the cursor.
 9190            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9191                .into_iter()
 9192                .flatten()
 9193                .find(|&start_row| {
 9194                    let end_row = start_row + line_count as u32;
 9195                    visible_row_range.contains(&start_row)
 9196                        && visible_row_range.contains(&end_row)
 9197                        && cursor_row
 9198                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9199                })?;
 9200
 9201            content_origin
 9202                + point(
 9203                    Pixels::from(-scroll_pixel_position.x),
 9204                    Pixels::from(
 9205                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9206                    ),
 9207                )
 9208        };
 9209
 9210        origin.x -= BORDER_WIDTH;
 9211
 9212        window.defer_draw(element, origin, 1);
 9213
 9214        // Do not return an element, since it will already be drawn due to defer_draw.
 9215        None
 9216    }
 9217
 9218    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9219        px(30.)
 9220    }
 9221
 9222    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9223        if self.read_only(cx) {
 9224            cx.theme().players().read_only()
 9225        } else {
 9226            self.style.as_ref().unwrap().local_player
 9227        }
 9228    }
 9229
 9230    fn render_edit_prediction_accept_keybind(
 9231        &self,
 9232        window: &mut Window,
 9233        cx: &App,
 9234    ) -> Option<AnyElement> {
 9235        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9236        let accept_keystroke = accept_binding.keystroke()?;
 9237
 9238        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9239
 9240        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9241            Color::Accent
 9242        } else {
 9243            Color::Muted
 9244        };
 9245
 9246        h_flex()
 9247            .px_0p5()
 9248            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9249            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9250            .text_size(TextSize::XSmall.rems(cx))
 9251            .child(h_flex().children(ui::render_modifiers(
 9252                accept_keystroke.modifiers(),
 9253                PlatformStyle::platform(),
 9254                Some(modifiers_color),
 9255                Some(IconSize::XSmall.rems().into()),
 9256                true,
 9257            )))
 9258            .when(is_platform_style_mac, |parent| {
 9259                parent.child(accept_keystroke.key().to_string())
 9260            })
 9261            .when(!is_platform_style_mac, |parent| {
 9262                parent.child(
 9263                    Key::new(
 9264                        util::capitalize(accept_keystroke.key()),
 9265                        Some(Color::Default),
 9266                    )
 9267                    .size(Some(IconSize::XSmall.rems().into())),
 9268                )
 9269            })
 9270            .into_any()
 9271            .into()
 9272    }
 9273
 9274    fn render_edit_prediction_line_popover(
 9275        &self,
 9276        label: impl Into<SharedString>,
 9277        icon: Option<IconName>,
 9278        window: &mut Window,
 9279        cx: &App,
 9280    ) -> Stateful<Div> {
 9281        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9282
 9283        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9284        let has_keybind = keybind.is_some();
 9285
 9286        h_flex()
 9287            .id("ep-line-popover")
 9288            .py_0p5()
 9289            .pl_1()
 9290            .pr(padding_right)
 9291            .gap_1()
 9292            .rounded_md()
 9293            .border_1()
 9294            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9295            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9296            .shadow_xs()
 9297            .when(!has_keybind, |el| {
 9298                let status_colors = cx.theme().status();
 9299
 9300                el.bg(status_colors.error_background)
 9301                    .border_color(status_colors.error.opacity(0.6))
 9302                    .pl_2()
 9303                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9304                    .cursor_default()
 9305                    .hoverable_tooltip(move |_window, cx| {
 9306                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9307                    })
 9308            })
 9309            .children(keybind)
 9310            .child(
 9311                Label::new(label)
 9312                    .size(LabelSize::Small)
 9313                    .when(!has_keybind, |el| {
 9314                        el.color(cx.theme().status().error.into()).strikethrough()
 9315                    }),
 9316            )
 9317            .when(!has_keybind, |el| {
 9318                el.child(
 9319                    h_flex().ml_1().child(
 9320                        Icon::new(IconName::Info)
 9321                            .size(IconSize::Small)
 9322                            .color(cx.theme().status().error.into()),
 9323                    ),
 9324                )
 9325            })
 9326            .when_some(icon, |element, icon| {
 9327                element.child(
 9328                    div()
 9329                        .mt(px(1.5))
 9330                        .child(Icon::new(icon).size(IconSize::Small)),
 9331                )
 9332            })
 9333    }
 9334
 9335    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9336        let accent_color = cx.theme().colors().text_accent;
 9337        let editor_bg_color = cx.theme().colors().editor_background;
 9338        editor_bg_color.blend(accent_color.opacity(0.1))
 9339    }
 9340
 9341    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9342        let accent_color = cx.theme().colors().text_accent;
 9343        let editor_bg_color = cx.theme().colors().editor_background;
 9344        editor_bg_color.blend(accent_color.opacity(0.6))
 9345    }
 9346    fn get_prediction_provider_icon_name(
 9347        provider: &Option<RegisteredEditPredictionProvider>,
 9348    ) -> IconName {
 9349        match provider {
 9350            Some(provider) => match provider.provider.name() {
 9351                "copilot" => IconName::Copilot,
 9352                "supermaven" => IconName::Supermaven,
 9353                _ => IconName::ZedPredict,
 9354            },
 9355            None => IconName::ZedPredict,
 9356        }
 9357    }
 9358
 9359    fn render_edit_prediction_cursor_popover(
 9360        &self,
 9361        min_width: Pixels,
 9362        max_width: Pixels,
 9363        cursor_point: Point,
 9364        style: &EditorStyle,
 9365        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9366        _window: &Window,
 9367        cx: &mut Context<Editor>,
 9368    ) -> Option<AnyElement> {
 9369        let provider = self.edit_prediction_provider.as_ref()?;
 9370        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9371
 9372        let is_refreshing = provider.provider.is_refreshing(cx);
 9373
 9374        fn pending_completion_container(icon: IconName) -> Div {
 9375            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9376        }
 9377
 9378        let completion = match &self.active_edit_prediction {
 9379            Some(prediction) => {
 9380                if !self.has_visible_completions_menu() {
 9381                    const RADIUS: Pixels = px(6.);
 9382                    const BORDER_WIDTH: Pixels = px(1.);
 9383
 9384                    return Some(
 9385                        h_flex()
 9386                            .elevation_2(cx)
 9387                            .border(BORDER_WIDTH)
 9388                            .border_color(cx.theme().colors().border)
 9389                            .when(accept_keystroke.is_none(), |el| {
 9390                                el.border_color(cx.theme().status().error)
 9391                            })
 9392                            .rounded(RADIUS)
 9393                            .rounded_tl(px(0.))
 9394                            .overflow_hidden()
 9395                            .child(div().px_1p5().child(match &prediction.completion {
 9396                                EditPrediction::MoveWithin { target, snapshot } => {
 9397                                    use text::ToPoint as _;
 9398                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9399                                    {
 9400                                        Icon::new(IconName::ZedPredictDown)
 9401                                    } else {
 9402                                        Icon::new(IconName::ZedPredictUp)
 9403                                    }
 9404                                }
 9405                                EditPrediction::MoveOutside { .. } => {
 9406                                    // TODO [zeta2] custom icon for external jump?
 9407                                    Icon::new(provider_icon)
 9408                                }
 9409                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9410                            }))
 9411                            .child(
 9412                                h_flex()
 9413                                    .gap_1()
 9414                                    .py_1()
 9415                                    .px_2()
 9416                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9417                                    .border_l_1()
 9418                                    .border_color(cx.theme().colors().border)
 9419                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9420                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9421                                        el.child(
 9422                                            Label::new("Hold")
 9423                                                .size(LabelSize::Small)
 9424                                                .when(accept_keystroke.is_none(), |el| {
 9425                                                    el.strikethrough()
 9426                                                })
 9427                                                .line_height_style(LineHeightStyle::UiLabel),
 9428                                        )
 9429                                    })
 9430                                    .id("edit_prediction_cursor_popover_keybind")
 9431                                    .when(accept_keystroke.is_none(), |el| {
 9432                                        let status_colors = cx.theme().status();
 9433
 9434                                        el.bg(status_colors.error_background)
 9435                                            .border_color(status_colors.error.opacity(0.6))
 9436                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9437                                            .cursor_default()
 9438                                            .hoverable_tooltip(move |_window, cx| {
 9439                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9440                                                    .into()
 9441                                            })
 9442                                    })
 9443                                    .when_some(
 9444                                        accept_keystroke.as_ref(),
 9445                                        |el, accept_keystroke| {
 9446                                            el.child(h_flex().children(ui::render_modifiers(
 9447                                                accept_keystroke.modifiers(),
 9448                                                PlatformStyle::platform(),
 9449                                                Some(Color::Default),
 9450                                                Some(IconSize::XSmall.rems().into()),
 9451                                                false,
 9452                                            )))
 9453                                        },
 9454                                    ),
 9455                            )
 9456                            .into_any(),
 9457                    );
 9458                }
 9459
 9460                self.render_edit_prediction_cursor_popover_preview(
 9461                    prediction,
 9462                    cursor_point,
 9463                    style,
 9464                    cx,
 9465                )?
 9466            }
 9467
 9468            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9469                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9470                    stale_completion,
 9471                    cursor_point,
 9472                    style,
 9473                    cx,
 9474                )?,
 9475
 9476                None => pending_completion_container(provider_icon)
 9477                    .child(Label::new("...").size(LabelSize::Small)),
 9478            },
 9479
 9480            None => pending_completion_container(provider_icon)
 9481                .child(Label::new("...").size(LabelSize::Small)),
 9482        };
 9483
 9484        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9485            completion
 9486                .with_animation(
 9487                    "loading-completion",
 9488                    Animation::new(Duration::from_secs(2))
 9489                        .repeat()
 9490                        .with_easing(pulsating_between(0.4, 0.8)),
 9491                    |label, delta| label.opacity(delta),
 9492                )
 9493                .into_any_element()
 9494        } else {
 9495            completion.into_any_element()
 9496        };
 9497
 9498        let has_completion = self.active_edit_prediction.is_some();
 9499
 9500        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9501        Some(
 9502            h_flex()
 9503                .min_w(min_width)
 9504                .max_w(max_width)
 9505                .flex_1()
 9506                .elevation_2(cx)
 9507                .border_color(cx.theme().colors().border)
 9508                .child(
 9509                    div()
 9510                        .flex_1()
 9511                        .py_1()
 9512                        .px_2()
 9513                        .overflow_hidden()
 9514                        .child(completion),
 9515                )
 9516                .when_some(accept_keystroke, |el, accept_keystroke| {
 9517                    if !accept_keystroke.modifiers().modified() {
 9518                        return el;
 9519                    }
 9520
 9521                    el.child(
 9522                        h_flex()
 9523                            .h_full()
 9524                            .border_l_1()
 9525                            .rounded_r_lg()
 9526                            .border_color(cx.theme().colors().border)
 9527                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9528                            .gap_1()
 9529                            .py_1()
 9530                            .px_2()
 9531                            .child(
 9532                                h_flex()
 9533                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9534                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9535                                    .child(h_flex().children(ui::render_modifiers(
 9536                                        accept_keystroke.modifiers(),
 9537                                        PlatformStyle::platform(),
 9538                                        Some(if !has_completion {
 9539                                            Color::Muted
 9540                                        } else {
 9541                                            Color::Default
 9542                                        }),
 9543                                        None,
 9544                                        false,
 9545                                    ))),
 9546                            )
 9547                            .child(Label::new("Preview").into_any_element())
 9548                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9549                    )
 9550                })
 9551                .into_any(),
 9552        )
 9553    }
 9554
 9555    fn render_edit_prediction_cursor_popover_preview(
 9556        &self,
 9557        completion: &EditPredictionState,
 9558        cursor_point: Point,
 9559        style: &EditorStyle,
 9560        cx: &mut Context<Editor>,
 9561    ) -> Option<Div> {
 9562        use text::ToPoint as _;
 9563
 9564        fn render_relative_row_jump(
 9565            prefix: impl Into<String>,
 9566            current_row: u32,
 9567            target_row: u32,
 9568        ) -> Div {
 9569            let (row_diff, arrow) = if target_row < current_row {
 9570                (current_row - target_row, IconName::ArrowUp)
 9571            } else {
 9572                (target_row - current_row, IconName::ArrowDown)
 9573            };
 9574
 9575            h_flex()
 9576                .child(
 9577                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9578                        .color(Color::Muted)
 9579                        .size(LabelSize::Small),
 9580                )
 9581                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9582        }
 9583
 9584        let supports_jump = self
 9585            .edit_prediction_provider
 9586            .as_ref()
 9587            .map(|provider| provider.provider.supports_jump_to_edit())
 9588            .unwrap_or(true);
 9589
 9590        match &completion.completion {
 9591            EditPrediction::MoveWithin {
 9592                target, snapshot, ..
 9593            } => {
 9594                if !supports_jump {
 9595                    return None;
 9596                }
 9597
 9598                Some(
 9599                    h_flex()
 9600                        .px_2()
 9601                        .gap_2()
 9602                        .flex_1()
 9603                        .child(
 9604                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9605                                Icon::new(IconName::ZedPredictDown)
 9606                            } else {
 9607                                Icon::new(IconName::ZedPredictUp)
 9608                            },
 9609                        )
 9610                        .child(Label::new("Jump to Edit")),
 9611                )
 9612            }
 9613            EditPrediction::MoveOutside { snapshot, .. } => {
 9614                let file_name = snapshot
 9615                    .file()
 9616                    .map(|file| file.file_name(cx))
 9617                    .unwrap_or("untitled");
 9618                Some(
 9619                    h_flex()
 9620                        .px_2()
 9621                        .gap_2()
 9622                        .flex_1()
 9623                        .child(Icon::new(IconName::ZedPredict))
 9624                        .child(Label::new(format!("Jump to {file_name}"))),
 9625                )
 9626            }
 9627            EditPrediction::Edit {
 9628                edits,
 9629                edit_preview,
 9630                snapshot,
 9631                display_mode: _,
 9632            } => {
 9633                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9634
 9635                let (highlighted_edits, has_more_lines) =
 9636                    if let Some(edit_preview) = edit_preview.as_ref() {
 9637                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9638                            .first_line_preview()
 9639                    } else {
 9640                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9641                    };
 9642
 9643                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9644                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9645
 9646                let preview = h_flex()
 9647                    .gap_1()
 9648                    .min_w_16()
 9649                    .child(styled_text)
 9650                    .when(has_more_lines, |parent| parent.child(""));
 9651
 9652                let left = if supports_jump && first_edit_row != cursor_point.row {
 9653                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9654                        .into_any_element()
 9655                } else {
 9656                    let icon_name =
 9657                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9658                    Icon::new(icon_name).into_any_element()
 9659                };
 9660
 9661                Some(
 9662                    h_flex()
 9663                        .h_full()
 9664                        .flex_1()
 9665                        .gap_2()
 9666                        .pr_1()
 9667                        .overflow_x_hidden()
 9668                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9669                        .child(left)
 9670                        .child(preview),
 9671                )
 9672            }
 9673        }
 9674    }
 9675
 9676    pub fn render_context_menu(
 9677        &self,
 9678        style: &EditorStyle,
 9679        max_height_in_lines: u32,
 9680        window: &mut Window,
 9681        cx: &mut Context<Editor>,
 9682    ) -> Option<AnyElement> {
 9683        let menu = self.context_menu.borrow();
 9684        let menu = menu.as_ref()?;
 9685        if !menu.visible() {
 9686            return None;
 9687        };
 9688        Some(menu.render(style, max_height_in_lines, window, cx))
 9689    }
 9690
 9691    fn render_context_menu_aside(
 9692        &mut self,
 9693        max_size: Size<Pixels>,
 9694        window: &mut Window,
 9695        cx: &mut Context<Editor>,
 9696    ) -> Option<AnyElement> {
 9697        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9698            if menu.visible() {
 9699                menu.render_aside(max_size, window, cx)
 9700            } else {
 9701                None
 9702            }
 9703        })
 9704    }
 9705
 9706    fn hide_context_menu(
 9707        &mut self,
 9708        window: &mut Window,
 9709        cx: &mut Context<Self>,
 9710    ) -> Option<CodeContextMenu> {
 9711        cx.notify();
 9712        self.completion_tasks.clear();
 9713        let context_menu = self.context_menu.borrow_mut().take();
 9714        self.stale_edit_prediction_in_menu.take();
 9715        self.update_visible_edit_prediction(window, cx);
 9716        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9717            && let Some(completion_provider) = &self.completion_provider
 9718        {
 9719            completion_provider.selection_changed(None, window, cx);
 9720        }
 9721        context_menu
 9722    }
 9723
 9724    fn show_snippet_choices(
 9725        &mut self,
 9726        choices: &Vec<String>,
 9727        selection: Range<Anchor>,
 9728        cx: &mut Context<Self>,
 9729    ) {
 9730        let Some((_, buffer, _)) = self
 9731            .buffer()
 9732            .read(cx)
 9733            .excerpt_containing(selection.start, cx)
 9734        else {
 9735            return;
 9736        };
 9737        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9738        else {
 9739            return;
 9740        };
 9741        if buffer != end_buffer {
 9742            log::error!("expected anchor range to have matching buffer IDs");
 9743            return;
 9744        }
 9745
 9746        let id = post_inc(&mut self.next_completion_id);
 9747        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9748        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9749            CompletionsMenu::new_snippet_choices(
 9750                id,
 9751                true,
 9752                choices,
 9753                selection,
 9754                buffer,
 9755                snippet_sort_order,
 9756            ),
 9757        ));
 9758    }
 9759
 9760    pub fn insert_snippet(
 9761        &mut self,
 9762        insertion_ranges: &[Range<usize>],
 9763        snippet: Snippet,
 9764        window: &mut Window,
 9765        cx: &mut Context<Self>,
 9766    ) -> Result<()> {
 9767        struct Tabstop<T> {
 9768            is_end_tabstop: bool,
 9769            ranges: Vec<Range<T>>,
 9770            choices: Option<Vec<String>>,
 9771        }
 9772
 9773        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9774            let snippet_text: Arc<str> = snippet.text.clone().into();
 9775            let edits = insertion_ranges
 9776                .iter()
 9777                .cloned()
 9778                .map(|range| (range, snippet_text.clone()));
 9779            let autoindent_mode = AutoindentMode::Block {
 9780                original_indent_columns: Vec::new(),
 9781            };
 9782            buffer.edit(edits, Some(autoindent_mode), cx);
 9783
 9784            let snapshot = &*buffer.read(cx);
 9785            let snippet = &snippet;
 9786            snippet
 9787                .tabstops
 9788                .iter()
 9789                .map(|tabstop| {
 9790                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9791                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9792                    });
 9793                    let mut tabstop_ranges = tabstop
 9794                        .ranges
 9795                        .iter()
 9796                        .flat_map(|tabstop_range| {
 9797                            let mut delta = 0_isize;
 9798                            insertion_ranges.iter().map(move |insertion_range| {
 9799                                let insertion_start = insertion_range.start as isize + delta;
 9800                                delta +=
 9801                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9802
 9803                                let start = ((insertion_start + tabstop_range.start) as usize)
 9804                                    .min(snapshot.len());
 9805                                let end = ((insertion_start + tabstop_range.end) as usize)
 9806                                    .min(snapshot.len());
 9807                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9808                            })
 9809                        })
 9810                        .collect::<Vec<_>>();
 9811                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9812
 9813                    Tabstop {
 9814                        is_end_tabstop,
 9815                        ranges: tabstop_ranges,
 9816                        choices: tabstop.choices.clone(),
 9817                    }
 9818                })
 9819                .collect::<Vec<_>>()
 9820        });
 9821        if let Some(tabstop) = tabstops.first() {
 9822            self.change_selections(Default::default(), window, cx, |s| {
 9823                // Reverse order so that the first range is the newest created selection.
 9824                // Completions will use it and autoscroll will prioritize it.
 9825                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9826            });
 9827
 9828            if let Some(choices) = &tabstop.choices
 9829                && let Some(selection) = tabstop.ranges.first()
 9830            {
 9831                self.show_snippet_choices(choices, selection.clone(), cx)
 9832            }
 9833
 9834            // If we're already at the last tabstop and it's at the end of the snippet,
 9835            // we're done, we don't need to keep the state around.
 9836            if !tabstop.is_end_tabstop {
 9837                let choices = tabstops
 9838                    .iter()
 9839                    .map(|tabstop| tabstop.choices.clone())
 9840                    .collect();
 9841
 9842                let ranges = tabstops
 9843                    .into_iter()
 9844                    .map(|tabstop| tabstop.ranges)
 9845                    .collect::<Vec<_>>();
 9846
 9847                self.snippet_stack.push(SnippetState {
 9848                    active_index: 0,
 9849                    ranges,
 9850                    choices,
 9851                });
 9852            }
 9853
 9854            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9855            if self.autoclose_regions.is_empty() {
 9856                let snapshot = self.buffer.read(cx).snapshot(cx);
 9857                let mut all_selections = self.selections.all::<Point>(cx);
 9858                for selection in &mut all_selections {
 9859                    let selection_head = selection.head();
 9860                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9861                        continue;
 9862                    };
 9863
 9864                    let mut bracket_pair = None;
 9865                    let max_lookup_length = scope
 9866                        .brackets()
 9867                        .map(|(pair, _)| {
 9868                            pair.start
 9869                                .as_str()
 9870                                .chars()
 9871                                .count()
 9872                                .max(pair.end.as_str().chars().count())
 9873                        })
 9874                        .max();
 9875                    if let Some(max_lookup_length) = max_lookup_length {
 9876                        let next_text = snapshot
 9877                            .chars_at(selection_head)
 9878                            .take(max_lookup_length)
 9879                            .collect::<String>();
 9880                        let prev_text = snapshot
 9881                            .reversed_chars_at(selection_head)
 9882                            .take(max_lookup_length)
 9883                            .collect::<String>();
 9884
 9885                        for (pair, enabled) in scope.brackets() {
 9886                            if enabled
 9887                                && pair.close
 9888                                && prev_text.starts_with(pair.start.as_str())
 9889                                && next_text.starts_with(pair.end.as_str())
 9890                            {
 9891                                bracket_pair = Some(pair.clone());
 9892                                break;
 9893                            }
 9894                        }
 9895                    }
 9896
 9897                    if let Some(pair) = bracket_pair {
 9898                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9899                        let autoclose_enabled =
 9900                            self.use_autoclose && snapshot_settings.use_autoclose;
 9901                        if autoclose_enabled {
 9902                            let start = snapshot.anchor_after(selection_head);
 9903                            let end = snapshot.anchor_after(selection_head);
 9904                            self.autoclose_regions.push(AutocloseRegion {
 9905                                selection_id: selection.id,
 9906                                range: start..end,
 9907                                pair,
 9908                            });
 9909                        }
 9910                    }
 9911                }
 9912            }
 9913        }
 9914        Ok(())
 9915    }
 9916
 9917    pub fn move_to_next_snippet_tabstop(
 9918        &mut self,
 9919        window: &mut Window,
 9920        cx: &mut Context<Self>,
 9921    ) -> bool {
 9922        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9923    }
 9924
 9925    pub fn move_to_prev_snippet_tabstop(
 9926        &mut self,
 9927        window: &mut Window,
 9928        cx: &mut Context<Self>,
 9929    ) -> bool {
 9930        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9931    }
 9932
 9933    pub fn move_to_snippet_tabstop(
 9934        &mut self,
 9935        bias: Bias,
 9936        window: &mut Window,
 9937        cx: &mut Context<Self>,
 9938    ) -> bool {
 9939        if let Some(mut snippet) = self.snippet_stack.pop() {
 9940            match bias {
 9941                Bias::Left => {
 9942                    if snippet.active_index > 0 {
 9943                        snippet.active_index -= 1;
 9944                    } else {
 9945                        self.snippet_stack.push(snippet);
 9946                        return false;
 9947                    }
 9948                }
 9949                Bias::Right => {
 9950                    if snippet.active_index + 1 < snippet.ranges.len() {
 9951                        snippet.active_index += 1;
 9952                    } else {
 9953                        self.snippet_stack.push(snippet);
 9954                        return false;
 9955                    }
 9956                }
 9957            }
 9958            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9959                self.change_selections(Default::default(), window, cx, |s| {
 9960                    // Reverse order so that the first range is the newest created selection.
 9961                    // Completions will use it and autoscroll will prioritize it.
 9962                    s.select_ranges(current_ranges.iter().rev().cloned())
 9963                });
 9964
 9965                if let Some(choices) = &snippet.choices[snippet.active_index]
 9966                    && let Some(selection) = current_ranges.first()
 9967                {
 9968                    self.show_snippet_choices(choices, selection.clone(), cx);
 9969                }
 9970
 9971                // If snippet state is not at the last tabstop, push it back on the stack
 9972                if snippet.active_index + 1 < snippet.ranges.len() {
 9973                    self.snippet_stack.push(snippet);
 9974                }
 9975                return true;
 9976            }
 9977        }
 9978
 9979        false
 9980    }
 9981
 9982    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9983        self.transact(window, cx, |this, window, cx| {
 9984            this.select_all(&SelectAll, window, cx);
 9985            this.insert("", window, cx);
 9986        });
 9987    }
 9988
 9989    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9990        if self.read_only(cx) {
 9991            return;
 9992        }
 9993        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9994        self.transact(window, cx, |this, window, cx| {
 9995            this.select_autoclose_pair(window, cx);
 9996            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9997            if !this.linked_edit_ranges.is_empty() {
 9998                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9999                let snapshot = this.buffer.read(cx).snapshot(cx);
10000
10001                for selection in selections.iter() {
10002                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10003                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10004                    if selection_start.buffer_id != selection_end.buffer_id {
10005                        continue;
10006                    }
10007                    if let Some(ranges) =
10008                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10009                    {
10010                        for (buffer, entries) in ranges {
10011                            linked_ranges.entry(buffer).or_default().extend(entries);
10012                        }
10013                    }
10014                }
10015            }
10016
10017            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10018            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10019            for selection in &mut selections {
10020                if selection.is_empty() {
10021                    let old_head = selection.head();
10022                    let mut new_head =
10023                        movement::left(&display_map, old_head.to_display_point(&display_map))
10024                            .to_point(&display_map);
10025                    if let Some((buffer, line_buffer_range)) = display_map
10026                        .buffer_snapshot()
10027                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10028                    {
10029                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10030                        let indent_len = match indent_size.kind {
10031                            IndentKind::Space => {
10032                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10033                            }
10034                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10035                        };
10036                        if old_head.column <= indent_size.len && old_head.column > 0 {
10037                            let indent_len = indent_len.get();
10038                            new_head = cmp::min(
10039                                new_head,
10040                                MultiBufferPoint::new(
10041                                    old_head.row,
10042                                    ((old_head.column - 1) / indent_len) * indent_len,
10043                                ),
10044                            );
10045                        }
10046                    }
10047
10048                    selection.set_head(new_head, SelectionGoal::None);
10049                }
10050            }
10051
10052            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10053            this.insert("", window, cx);
10054            let empty_str: Arc<str> = Arc::from("");
10055            for (buffer, edits) in linked_ranges {
10056                let snapshot = buffer.read(cx).snapshot();
10057                use text::ToPoint as TP;
10058
10059                let edits = edits
10060                    .into_iter()
10061                    .map(|range| {
10062                        let end_point = TP::to_point(&range.end, &snapshot);
10063                        let mut start_point = TP::to_point(&range.start, &snapshot);
10064
10065                        if end_point == start_point {
10066                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10067                                .saturating_sub(1);
10068                            start_point =
10069                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10070                        };
10071
10072                        (start_point..end_point, empty_str.clone())
10073                    })
10074                    .sorted_by_key(|(range, _)| range.start)
10075                    .collect::<Vec<_>>();
10076                buffer.update(cx, |this, cx| {
10077                    this.edit(edits, None, cx);
10078                })
10079            }
10080            this.refresh_edit_prediction(true, false, window, cx);
10081            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
10082        });
10083    }
10084
10085    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10086        if self.read_only(cx) {
10087            return;
10088        }
10089        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10090        self.transact(window, cx, |this, window, cx| {
10091            this.change_selections(Default::default(), window, cx, |s| {
10092                s.move_with(|map, selection| {
10093                    if selection.is_empty() {
10094                        let cursor = movement::right(map, selection.head());
10095                        selection.end = cursor;
10096                        selection.reversed = true;
10097                        selection.goal = SelectionGoal::None;
10098                    }
10099                })
10100            });
10101            this.insert("", window, cx);
10102            this.refresh_edit_prediction(true, false, window, cx);
10103        });
10104    }
10105
10106    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10107        if self.mode.is_single_line() {
10108            cx.propagate();
10109            return;
10110        }
10111
10112        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10113        if self.move_to_prev_snippet_tabstop(window, cx) {
10114            return;
10115        }
10116        self.outdent(&Outdent, window, cx);
10117    }
10118
10119    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10120        if self.mode.is_single_line() {
10121            cx.propagate();
10122            return;
10123        }
10124
10125        if self.move_to_next_snippet_tabstop(window, cx) {
10126            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10127            return;
10128        }
10129        if self.read_only(cx) {
10130            return;
10131        }
10132        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10133        let mut selections = self.selections.all_adjusted(cx);
10134        let buffer = self.buffer.read(cx);
10135        let snapshot = buffer.snapshot(cx);
10136        let rows_iter = selections.iter().map(|s| s.head().row);
10137        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10138
10139        let has_some_cursor_in_whitespace = selections
10140            .iter()
10141            .filter(|selection| selection.is_empty())
10142            .any(|selection| {
10143                let cursor = selection.head();
10144                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10145                cursor.column < current_indent.len
10146            });
10147
10148        let mut edits = Vec::new();
10149        let mut prev_edited_row = 0;
10150        let mut row_delta = 0;
10151        for selection in &mut selections {
10152            if selection.start.row != prev_edited_row {
10153                row_delta = 0;
10154            }
10155            prev_edited_row = selection.end.row;
10156
10157            // If the selection is non-empty, then increase the indentation of the selected lines.
10158            if !selection.is_empty() {
10159                row_delta =
10160                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10161                continue;
10162            }
10163
10164            let cursor = selection.head();
10165            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10166            if let Some(suggested_indent) =
10167                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10168            {
10169                // Don't do anything if already at suggested indent
10170                // and there is any other cursor which is not
10171                if has_some_cursor_in_whitespace
10172                    && cursor.column == current_indent.len
10173                    && current_indent.len == suggested_indent.len
10174                {
10175                    continue;
10176                }
10177
10178                // Adjust line and move cursor to suggested indent
10179                // if cursor is not at suggested indent
10180                if cursor.column < suggested_indent.len
10181                    && cursor.column <= current_indent.len
10182                    && current_indent.len <= suggested_indent.len
10183                {
10184                    selection.start = Point::new(cursor.row, suggested_indent.len);
10185                    selection.end = selection.start;
10186                    if row_delta == 0 {
10187                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10188                            cursor.row,
10189                            current_indent,
10190                            suggested_indent,
10191                        ));
10192                        row_delta = suggested_indent.len - current_indent.len;
10193                    }
10194                    continue;
10195                }
10196
10197                // If current indent is more than suggested indent
10198                // only move cursor to current indent and skip indent
10199                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10200                    selection.start = Point::new(cursor.row, current_indent.len);
10201                    selection.end = selection.start;
10202                    continue;
10203                }
10204            }
10205
10206            // Otherwise, insert a hard or soft tab.
10207            let settings = buffer.language_settings_at(cursor, cx);
10208            let tab_size = if settings.hard_tabs {
10209                IndentSize::tab()
10210            } else {
10211                let tab_size = settings.tab_size.get();
10212                let indent_remainder = snapshot
10213                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10214                    .flat_map(str::chars)
10215                    .fold(row_delta % tab_size, |counter: u32, c| {
10216                        if c == '\t' {
10217                            0
10218                        } else {
10219                            (counter + 1) % tab_size
10220                        }
10221                    });
10222
10223                let chars_to_next_tab_stop = tab_size - indent_remainder;
10224                IndentSize::spaces(chars_to_next_tab_stop)
10225            };
10226            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10227            selection.end = selection.start;
10228            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10229            row_delta += tab_size.len;
10230        }
10231
10232        self.transact(window, cx, |this, window, cx| {
10233            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10234            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10235            this.refresh_edit_prediction(true, false, window, cx);
10236        });
10237    }
10238
10239    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10240        if self.read_only(cx) {
10241            return;
10242        }
10243        if self.mode.is_single_line() {
10244            cx.propagate();
10245            return;
10246        }
10247
10248        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10249        let mut selections = self.selections.all::<Point>(cx);
10250        let mut prev_edited_row = 0;
10251        let mut row_delta = 0;
10252        let mut edits = Vec::new();
10253        let buffer = self.buffer.read(cx);
10254        let snapshot = buffer.snapshot(cx);
10255        for selection in &mut selections {
10256            if selection.start.row != prev_edited_row {
10257                row_delta = 0;
10258            }
10259            prev_edited_row = selection.end.row;
10260
10261            row_delta =
10262                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10263        }
10264
10265        self.transact(window, cx, |this, window, cx| {
10266            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10267            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10268        });
10269    }
10270
10271    fn indent_selection(
10272        buffer: &MultiBuffer,
10273        snapshot: &MultiBufferSnapshot,
10274        selection: &mut Selection<Point>,
10275        edits: &mut Vec<(Range<Point>, String)>,
10276        delta_for_start_row: u32,
10277        cx: &App,
10278    ) -> u32 {
10279        let settings = buffer.language_settings_at(selection.start, cx);
10280        let tab_size = settings.tab_size.get();
10281        let indent_kind = if settings.hard_tabs {
10282            IndentKind::Tab
10283        } else {
10284            IndentKind::Space
10285        };
10286        let mut start_row = selection.start.row;
10287        let mut end_row = selection.end.row + 1;
10288
10289        // If a selection ends at the beginning of a line, don't indent
10290        // that last line.
10291        if selection.end.column == 0 && selection.end.row > selection.start.row {
10292            end_row -= 1;
10293        }
10294
10295        // Avoid re-indenting a row that has already been indented by a
10296        // previous selection, but still update this selection's column
10297        // to reflect that indentation.
10298        if delta_for_start_row > 0 {
10299            start_row += 1;
10300            selection.start.column += delta_for_start_row;
10301            if selection.end.row == selection.start.row {
10302                selection.end.column += delta_for_start_row;
10303            }
10304        }
10305
10306        let mut delta_for_end_row = 0;
10307        let has_multiple_rows = start_row + 1 != end_row;
10308        for row in start_row..end_row {
10309            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10310            let indent_delta = match (current_indent.kind, indent_kind) {
10311                (IndentKind::Space, IndentKind::Space) => {
10312                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10313                    IndentSize::spaces(columns_to_next_tab_stop)
10314                }
10315                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10316                (_, IndentKind::Tab) => IndentSize::tab(),
10317            };
10318
10319            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10320                0
10321            } else {
10322                selection.start.column
10323            };
10324            let row_start = Point::new(row, start);
10325            edits.push((
10326                row_start..row_start,
10327                indent_delta.chars().collect::<String>(),
10328            ));
10329
10330            // Update this selection's endpoints to reflect the indentation.
10331            if row == selection.start.row {
10332                selection.start.column += indent_delta.len;
10333            }
10334            if row == selection.end.row {
10335                selection.end.column += indent_delta.len;
10336                delta_for_end_row = indent_delta.len;
10337            }
10338        }
10339
10340        if selection.start.row == selection.end.row {
10341            delta_for_start_row + delta_for_end_row
10342        } else {
10343            delta_for_end_row
10344        }
10345    }
10346
10347    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10348        if self.read_only(cx) {
10349            return;
10350        }
10351        if self.mode.is_single_line() {
10352            cx.propagate();
10353            return;
10354        }
10355
10356        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10357        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10358        let selections = self.selections.all::<Point>(cx);
10359        let mut deletion_ranges = Vec::new();
10360        let mut last_outdent = None;
10361        {
10362            let buffer = self.buffer.read(cx);
10363            let snapshot = buffer.snapshot(cx);
10364            for selection in &selections {
10365                let settings = buffer.language_settings_at(selection.start, cx);
10366                let tab_size = settings.tab_size.get();
10367                let mut rows = selection.spanned_rows(false, &display_map);
10368
10369                // Avoid re-outdenting a row that has already been outdented by a
10370                // previous selection.
10371                if let Some(last_row) = last_outdent
10372                    && last_row == rows.start
10373                {
10374                    rows.start = rows.start.next_row();
10375                }
10376                let has_multiple_rows = rows.len() > 1;
10377                for row in rows.iter_rows() {
10378                    let indent_size = snapshot.indent_size_for_line(row);
10379                    if indent_size.len > 0 {
10380                        let deletion_len = match indent_size.kind {
10381                            IndentKind::Space => {
10382                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10383                                if columns_to_prev_tab_stop == 0 {
10384                                    tab_size
10385                                } else {
10386                                    columns_to_prev_tab_stop
10387                                }
10388                            }
10389                            IndentKind::Tab => 1,
10390                        };
10391                        let start = if has_multiple_rows
10392                            || deletion_len > selection.start.column
10393                            || indent_size.len < selection.start.column
10394                        {
10395                            0
10396                        } else {
10397                            selection.start.column - deletion_len
10398                        };
10399                        deletion_ranges.push(
10400                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10401                        );
10402                        last_outdent = Some(row);
10403                    }
10404                }
10405            }
10406        }
10407
10408        self.transact(window, cx, |this, window, cx| {
10409            this.buffer.update(cx, |buffer, cx| {
10410                let empty_str: Arc<str> = Arc::default();
10411                buffer.edit(
10412                    deletion_ranges
10413                        .into_iter()
10414                        .map(|range| (range, empty_str.clone())),
10415                    None,
10416                    cx,
10417                );
10418            });
10419            let selections = this.selections.all::<usize>(cx);
10420            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10421        });
10422    }
10423
10424    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10425        if self.read_only(cx) {
10426            return;
10427        }
10428        if self.mode.is_single_line() {
10429            cx.propagate();
10430            return;
10431        }
10432
10433        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10434        let selections = self
10435            .selections
10436            .all::<usize>(cx)
10437            .into_iter()
10438            .map(|s| s.range());
10439
10440        self.transact(window, cx, |this, window, cx| {
10441            this.buffer.update(cx, |buffer, cx| {
10442                buffer.autoindent_ranges(selections, cx);
10443            });
10444            let selections = this.selections.all::<usize>(cx);
10445            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10446        });
10447    }
10448
10449    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10450        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10451        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10452        let selections = self.selections.all::<Point>(cx);
10453
10454        let mut new_cursors = Vec::new();
10455        let mut edit_ranges = Vec::new();
10456        let mut selections = selections.iter().peekable();
10457        while let Some(selection) = selections.next() {
10458            let mut rows = selection.spanned_rows(false, &display_map);
10459
10460            // Accumulate contiguous regions of rows that we want to delete.
10461            while let Some(next_selection) = selections.peek() {
10462                let next_rows = next_selection.spanned_rows(false, &display_map);
10463                if next_rows.start <= rows.end {
10464                    rows.end = next_rows.end;
10465                    selections.next().unwrap();
10466                } else {
10467                    break;
10468                }
10469            }
10470
10471            let buffer = display_map.buffer_snapshot();
10472            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10473            let edit_end = if buffer.max_point().row >= rows.end.0 {
10474                // If there's a line after the range, delete the \n from the end of the row range
10475                ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer)
10476            } else {
10477                // If there isn't a line after the range, delete the \n from the line before the
10478                // start of the row range
10479                edit_start = edit_start.saturating_sub(1);
10480                buffer.len()
10481            };
10482
10483            let (cursor, goal) = movement::down_by_rows(
10484                &display_map,
10485                selection.head().to_display_point(&display_map),
10486                rows.len() as u32,
10487                selection.goal,
10488                false,
10489                &self.text_layout_details(window),
10490            );
10491
10492            new_cursors.push((
10493                selection.id,
10494                buffer.anchor_after(cursor.to_point(&display_map)),
10495                goal,
10496            ));
10497            edit_ranges.push(edit_start..edit_end);
10498        }
10499
10500        self.transact(window, cx, |this, window, cx| {
10501            let buffer = this.buffer.update(cx, |buffer, cx| {
10502                let empty_str: Arc<str> = Arc::default();
10503                buffer.edit(
10504                    edit_ranges
10505                        .into_iter()
10506                        .map(|range| (range, empty_str.clone())),
10507                    None,
10508                    cx,
10509                );
10510                buffer.snapshot(cx)
10511            });
10512            let new_selections = new_cursors
10513                .into_iter()
10514                .map(|(id, cursor, goal)| {
10515                    let cursor = cursor.to_point(&buffer);
10516                    Selection {
10517                        id,
10518                        start: cursor,
10519                        end: cursor,
10520                        reversed: false,
10521                        goal,
10522                    }
10523                })
10524                .collect();
10525
10526            this.change_selections(Default::default(), window, cx, |s| {
10527                s.select(new_selections);
10528            });
10529        });
10530    }
10531
10532    pub fn join_lines_impl(
10533        &mut self,
10534        insert_whitespace: bool,
10535        window: &mut Window,
10536        cx: &mut Context<Self>,
10537    ) {
10538        if self.read_only(cx) {
10539            return;
10540        }
10541        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10542        for selection in self.selections.all::<Point>(cx) {
10543            let start = MultiBufferRow(selection.start.row);
10544            // Treat single line selections as if they include the next line. Otherwise this action
10545            // would do nothing for single line selections individual cursors.
10546            let end = if selection.start.row == selection.end.row {
10547                MultiBufferRow(selection.start.row + 1)
10548            } else {
10549                MultiBufferRow(selection.end.row)
10550            };
10551
10552            if let Some(last_row_range) = row_ranges.last_mut()
10553                && start <= last_row_range.end
10554            {
10555                last_row_range.end = end;
10556                continue;
10557            }
10558            row_ranges.push(start..end);
10559        }
10560
10561        let snapshot = self.buffer.read(cx).snapshot(cx);
10562        let mut cursor_positions = Vec::new();
10563        for row_range in &row_ranges {
10564            let anchor = snapshot.anchor_before(Point::new(
10565                row_range.end.previous_row().0,
10566                snapshot.line_len(row_range.end.previous_row()),
10567            ));
10568            cursor_positions.push(anchor..anchor);
10569        }
10570
10571        self.transact(window, cx, |this, window, cx| {
10572            for row_range in row_ranges.into_iter().rev() {
10573                for row in row_range.iter_rows().rev() {
10574                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10575                    let next_line_row = row.next_row();
10576                    let indent = snapshot.indent_size_for_line(next_line_row);
10577                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10578
10579                    let replace =
10580                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10581                            " "
10582                        } else {
10583                            ""
10584                        };
10585
10586                    this.buffer.update(cx, |buffer, cx| {
10587                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10588                    });
10589                }
10590            }
10591
10592            this.change_selections(Default::default(), window, cx, |s| {
10593                s.select_anchor_ranges(cursor_positions)
10594            });
10595        });
10596    }
10597
10598    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10599        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10600        self.join_lines_impl(true, window, cx);
10601    }
10602
10603    pub fn sort_lines_case_sensitive(
10604        &mut self,
10605        _: &SortLinesCaseSensitive,
10606        window: &mut Window,
10607        cx: &mut Context<Self>,
10608    ) {
10609        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10610    }
10611
10612    pub fn sort_lines_by_length(
10613        &mut self,
10614        _: &SortLinesByLength,
10615        window: &mut Window,
10616        cx: &mut Context<Self>,
10617    ) {
10618        self.manipulate_immutable_lines(window, cx, |lines| {
10619            lines.sort_by_key(|&line| line.chars().count())
10620        })
10621    }
10622
10623    pub fn sort_lines_case_insensitive(
10624        &mut self,
10625        _: &SortLinesCaseInsensitive,
10626        window: &mut Window,
10627        cx: &mut Context<Self>,
10628    ) {
10629        self.manipulate_immutable_lines(window, cx, |lines| {
10630            lines.sort_by_key(|line| line.to_lowercase())
10631        })
10632    }
10633
10634    pub fn unique_lines_case_insensitive(
10635        &mut self,
10636        _: &UniqueLinesCaseInsensitive,
10637        window: &mut Window,
10638        cx: &mut Context<Self>,
10639    ) {
10640        self.manipulate_immutable_lines(window, cx, |lines| {
10641            let mut seen = HashSet::default();
10642            lines.retain(|line| seen.insert(line.to_lowercase()));
10643        })
10644    }
10645
10646    pub fn unique_lines_case_sensitive(
10647        &mut self,
10648        _: &UniqueLinesCaseSensitive,
10649        window: &mut Window,
10650        cx: &mut Context<Self>,
10651    ) {
10652        self.manipulate_immutable_lines(window, cx, |lines| {
10653            let mut seen = HashSet::default();
10654            lines.retain(|line| seen.insert(*line));
10655        })
10656    }
10657
10658    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10659        let snapshot = self.buffer.read(cx).snapshot(cx);
10660        for selection in self.selections.disjoint_anchors_arc().iter() {
10661            if snapshot
10662                .language_at(selection.start)
10663                .and_then(|lang| lang.config().wrap_characters.as_ref())
10664                .is_some()
10665            {
10666                return true;
10667            }
10668        }
10669        false
10670    }
10671
10672    fn wrap_selections_in_tag(
10673        &mut self,
10674        _: &WrapSelectionsInTag,
10675        window: &mut Window,
10676        cx: &mut Context<Self>,
10677    ) {
10678        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10679
10680        let snapshot = self.buffer.read(cx).snapshot(cx);
10681
10682        let mut edits = Vec::new();
10683        let mut boundaries = Vec::new();
10684
10685        for selection in self.selections.all::<Point>(cx).iter() {
10686            let Some(wrap_config) = snapshot
10687                .language_at(selection.start)
10688                .and_then(|lang| lang.config().wrap_characters.clone())
10689            else {
10690                continue;
10691            };
10692
10693            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10694            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10695
10696            let start_before = snapshot.anchor_before(selection.start);
10697            let end_after = snapshot.anchor_after(selection.end);
10698
10699            edits.push((start_before..start_before, open_tag));
10700            edits.push((end_after..end_after, close_tag));
10701
10702            boundaries.push((
10703                start_before,
10704                end_after,
10705                wrap_config.start_prefix.len(),
10706                wrap_config.end_suffix.len(),
10707            ));
10708        }
10709
10710        if edits.is_empty() {
10711            return;
10712        }
10713
10714        self.transact(window, cx, |this, window, cx| {
10715            let buffer = this.buffer.update(cx, |buffer, cx| {
10716                buffer.edit(edits, None, cx);
10717                buffer.snapshot(cx)
10718            });
10719
10720            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10721            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10722                boundaries.into_iter()
10723            {
10724                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10725                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10726                new_selections.push(open_offset..open_offset);
10727                new_selections.push(close_offset..close_offset);
10728            }
10729
10730            this.change_selections(Default::default(), window, cx, |s| {
10731                s.select_ranges(new_selections);
10732            });
10733
10734            this.request_autoscroll(Autoscroll::fit(), cx);
10735        });
10736    }
10737
10738    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10739        let Some(project) = self.project.clone() else {
10740            return;
10741        };
10742        self.reload(project, window, cx)
10743            .detach_and_notify_err(window, cx);
10744    }
10745
10746    pub fn restore_file(
10747        &mut self,
10748        _: &::git::RestoreFile,
10749        window: &mut Window,
10750        cx: &mut Context<Self>,
10751    ) {
10752        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10753        let mut buffer_ids = HashSet::default();
10754        let snapshot = self.buffer().read(cx).snapshot(cx);
10755        for selection in self.selections.all::<usize>(cx) {
10756            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10757        }
10758
10759        let buffer = self.buffer().read(cx);
10760        let ranges = buffer_ids
10761            .into_iter()
10762            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10763            .collect::<Vec<_>>();
10764
10765        self.restore_hunks_in_ranges(ranges, window, cx);
10766    }
10767
10768    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10769        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10770        let selections = self
10771            .selections
10772            .all(cx)
10773            .into_iter()
10774            .map(|s| s.range())
10775            .collect();
10776        self.restore_hunks_in_ranges(selections, window, cx);
10777    }
10778
10779    pub fn restore_hunks_in_ranges(
10780        &mut self,
10781        ranges: Vec<Range<Point>>,
10782        window: &mut Window,
10783        cx: &mut Context<Editor>,
10784    ) {
10785        let mut revert_changes = HashMap::default();
10786        let chunk_by = self
10787            .snapshot(window, cx)
10788            .hunks_for_ranges(ranges)
10789            .into_iter()
10790            .chunk_by(|hunk| hunk.buffer_id);
10791        for (buffer_id, hunks) in &chunk_by {
10792            let hunks = hunks.collect::<Vec<_>>();
10793            for hunk in &hunks {
10794                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10795            }
10796            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10797        }
10798        drop(chunk_by);
10799        if !revert_changes.is_empty() {
10800            self.transact(window, cx, |editor, window, cx| {
10801                editor.restore(revert_changes, window, cx);
10802            });
10803        }
10804    }
10805
10806    pub fn open_active_item_in_terminal(
10807        &mut self,
10808        _: &OpenInTerminal,
10809        window: &mut Window,
10810        cx: &mut Context<Self>,
10811    ) {
10812        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10813            let project_path = buffer.read(cx).project_path(cx)?;
10814            let project = self.project()?.read(cx);
10815            let entry = project.entry_for_path(&project_path, cx)?;
10816            let parent = match &entry.canonical_path {
10817                Some(canonical_path) => canonical_path.to_path_buf(),
10818                None => project.absolute_path(&project_path, cx)?,
10819            }
10820            .parent()?
10821            .to_path_buf();
10822            Some(parent)
10823        }) {
10824            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10825        }
10826    }
10827
10828    fn set_breakpoint_context_menu(
10829        &mut self,
10830        display_row: DisplayRow,
10831        position: Option<Anchor>,
10832        clicked_point: gpui::Point<Pixels>,
10833        window: &mut Window,
10834        cx: &mut Context<Self>,
10835    ) {
10836        let source = self
10837            .buffer
10838            .read(cx)
10839            .snapshot(cx)
10840            .anchor_before(Point::new(display_row.0, 0u32));
10841
10842        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10843
10844        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10845            self,
10846            source,
10847            clicked_point,
10848            context_menu,
10849            window,
10850            cx,
10851        );
10852    }
10853
10854    fn add_edit_breakpoint_block(
10855        &mut self,
10856        anchor: Anchor,
10857        breakpoint: &Breakpoint,
10858        edit_action: BreakpointPromptEditAction,
10859        window: &mut Window,
10860        cx: &mut Context<Self>,
10861    ) {
10862        let weak_editor = cx.weak_entity();
10863        let bp_prompt = cx.new(|cx| {
10864            BreakpointPromptEditor::new(
10865                weak_editor,
10866                anchor,
10867                breakpoint.clone(),
10868                edit_action,
10869                window,
10870                cx,
10871            )
10872        });
10873
10874        let height = bp_prompt.update(cx, |this, cx| {
10875            this.prompt
10876                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10877        });
10878        let cloned_prompt = bp_prompt.clone();
10879        let blocks = vec![BlockProperties {
10880            style: BlockStyle::Sticky,
10881            placement: BlockPlacement::Above(anchor),
10882            height: Some(height),
10883            render: Arc::new(move |cx| {
10884                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10885                cloned_prompt.clone().into_any_element()
10886            }),
10887            priority: 0,
10888        }];
10889
10890        let focus_handle = bp_prompt.focus_handle(cx);
10891        window.focus(&focus_handle);
10892
10893        let block_ids = self.insert_blocks(blocks, None, cx);
10894        bp_prompt.update(cx, |prompt, _| {
10895            prompt.add_block_ids(block_ids);
10896        });
10897    }
10898
10899    pub(crate) fn breakpoint_at_row(
10900        &self,
10901        row: u32,
10902        window: &mut Window,
10903        cx: &mut Context<Self>,
10904    ) -> Option<(Anchor, Breakpoint)> {
10905        let snapshot = self.snapshot(window, cx);
10906        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10907
10908        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10909    }
10910
10911    pub(crate) fn breakpoint_at_anchor(
10912        &self,
10913        breakpoint_position: Anchor,
10914        snapshot: &EditorSnapshot,
10915        cx: &mut Context<Self>,
10916    ) -> Option<(Anchor, Breakpoint)> {
10917        let buffer = self
10918            .buffer
10919            .read(cx)
10920            .buffer_for_anchor(breakpoint_position, cx)?;
10921
10922        let enclosing_excerpt = breakpoint_position.excerpt_id;
10923        let buffer_snapshot = buffer.read(cx).snapshot();
10924
10925        let row = buffer_snapshot
10926            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10927            .row;
10928
10929        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10930        let anchor_end = snapshot
10931            .buffer_snapshot()
10932            .anchor_after(Point::new(row, line_len));
10933
10934        self.breakpoint_store
10935            .as_ref()?
10936            .read_with(cx, |breakpoint_store, cx| {
10937                breakpoint_store
10938                    .breakpoints(
10939                        &buffer,
10940                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10941                        &buffer_snapshot,
10942                        cx,
10943                    )
10944                    .next()
10945                    .and_then(|(bp, _)| {
10946                        let breakpoint_row = buffer_snapshot
10947                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10948                            .row;
10949
10950                        if breakpoint_row == row {
10951                            snapshot
10952                                .buffer_snapshot()
10953                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10954                                .map(|position| (position, bp.bp.clone()))
10955                        } else {
10956                            None
10957                        }
10958                    })
10959            })
10960    }
10961
10962    pub fn edit_log_breakpoint(
10963        &mut self,
10964        _: &EditLogBreakpoint,
10965        window: &mut Window,
10966        cx: &mut Context<Self>,
10967    ) {
10968        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10969            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10970                message: None,
10971                state: BreakpointState::Enabled,
10972                condition: None,
10973                hit_condition: None,
10974            });
10975
10976            self.add_edit_breakpoint_block(
10977                anchor,
10978                &breakpoint,
10979                BreakpointPromptEditAction::Log,
10980                window,
10981                cx,
10982            );
10983        }
10984    }
10985
10986    fn breakpoints_at_cursors(
10987        &self,
10988        window: &mut Window,
10989        cx: &mut Context<Self>,
10990    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10991        let snapshot = self.snapshot(window, cx);
10992        let cursors = self
10993            .selections
10994            .disjoint_anchors_arc()
10995            .iter()
10996            .map(|selection| {
10997                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10998
10999                let breakpoint_position = self
11000                    .breakpoint_at_row(cursor_position.row, window, cx)
11001                    .map(|bp| bp.0)
11002                    .unwrap_or_else(|| {
11003                        snapshot
11004                            .display_snapshot
11005                            .buffer_snapshot()
11006                            .anchor_after(Point::new(cursor_position.row, 0))
11007                    });
11008
11009                let breakpoint = self
11010                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11011                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11012
11013                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11014            })
11015            // 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.
11016            .collect::<HashMap<Anchor, _>>();
11017
11018        cursors.into_iter().collect()
11019    }
11020
11021    pub fn enable_breakpoint(
11022        &mut self,
11023        _: &crate::actions::EnableBreakpoint,
11024        window: &mut Window,
11025        cx: &mut Context<Self>,
11026    ) {
11027        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11028            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11029                continue;
11030            };
11031            self.edit_breakpoint_at_anchor(
11032                anchor,
11033                breakpoint,
11034                BreakpointEditAction::InvertState,
11035                cx,
11036            );
11037        }
11038    }
11039
11040    pub fn disable_breakpoint(
11041        &mut self,
11042        _: &crate::actions::DisableBreakpoint,
11043        window: &mut Window,
11044        cx: &mut Context<Self>,
11045    ) {
11046        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11047            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11048                continue;
11049            };
11050            self.edit_breakpoint_at_anchor(
11051                anchor,
11052                breakpoint,
11053                BreakpointEditAction::InvertState,
11054                cx,
11055            );
11056        }
11057    }
11058
11059    pub fn toggle_breakpoint(
11060        &mut self,
11061        _: &crate::actions::ToggleBreakpoint,
11062        window: &mut Window,
11063        cx: &mut Context<Self>,
11064    ) {
11065        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11066            if let Some(breakpoint) = breakpoint {
11067                self.edit_breakpoint_at_anchor(
11068                    anchor,
11069                    breakpoint,
11070                    BreakpointEditAction::Toggle,
11071                    cx,
11072                );
11073            } else {
11074                self.edit_breakpoint_at_anchor(
11075                    anchor,
11076                    Breakpoint::new_standard(),
11077                    BreakpointEditAction::Toggle,
11078                    cx,
11079                );
11080            }
11081        }
11082    }
11083
11084    pub fn edit_breakpoint_at_anchor(
11085        &mut self,
11086        breakpoint_position: Anchor,
11087        breakpoint: Breakpoint,
11088        edit_action: BreakpointEditAction,
11089        cx: &mut Context<Self>,
11090    ) {
11091        let Some(breakpoint_store) = &self.breakpoint_store else {
11092            return;
11093        };
11094
11095        let Some(buffer) = self
11096            .buffer
11097            .read(cx)
11098            .buffer_for_anchor(breakpoint_position, cx)
11099        else {
11100            return;
11101        };
11102
11103        breakpoint_store.update(cx, |breakpoint_store, cx| {
11104            breakpoint_store.toggle_breakpoint(
11105                buffer,
11106                BreakpointWithPosition {
11107                    position: breakpoint_position.text_anchor,
11108                    bp: breakpoint,
11109                },
11110                edit_action,
11111                cx,
11112            );
11113        });
11114
11115        cx.notify();
11116    }
11117
11118    #[cfg(any(test, feature = "test-support"))]
11119    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11120        self.breakpoint_store.clone()
11121    }
11122
11123    pub fn prepare_restore_change(
11124        &self,
11125        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11126        hunk: &MultiBufferDiffHunk,
11127        cx: &mut App,
11128    ) -> Option<()> {
11129        if hunk.is_created_file() {
11130            return None;
11131        }
11132        let buffer = self.buffer.read(cx);
11133        let diff = buffer.diff_for(hunk.buffer_id)?;
11134        let buffer = buffer.buffer(hunk.buffer_id)?;
11135        let buffer = buffer.read(cx);
11136        let original_text = diff
11137            .read(cx)
11138            .base_text()
11139            .as_rope()
11140            .slice(hunk.diff_base_byte_range.clone());
11141        let buffer_snapshot = buffer.snapshot();
11142        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11143        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11144            probe
11145                .0
11146                .start
11147                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11148                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11149        }) {
11150            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11151            Some(())
11152        } else {
11153            None
11154        }
11155    }
11156
11157    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11158        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11159    }
11160
11161    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11162        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11163    }
11164
11165    fn manipulate_lines<M>(
11166        &mut self,
11167        window: &mut Window,
11168        cx: &mut Context<Self>,
11169        mut manipulate: M,
11170    ) where
11171        M: FnMut(&str) -> LineManipulationResult,
11172    {
11173        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11174
11175        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11176        let buffer = self.buffer.read(cx).snapshot(cx);
11177
11178        let mut edits = Vec::new();
11179
11180        let selections = self.selections.all::<Point>(cx);
11181        let mut selections = selections.iter().peekable();
11182        let mut contiguous_row_selections = Vec::new();
11183        let mut new_selections = Vec::new();
11184        let mut added_lines = 0;
11185        let mut removed_lines = 0;
11186
11187        while let Some(selection) = selections.next() {
11188            let (start_row, end_row) = consume_contiguous_rows(
11189                &mut contiguous_row_selections,
11190                selection,
11191                &display_map,
11192                &mut selections,
11193            );
11194
11195            let start_point = Point::new(start_row.0, 0);
11196            let end_point = Point::new(
11197                end_row.previous_row().0,
11198                buffer.line_len(end_row.previous_row()),
11199            );
11200            let text = buffer
11201                .text_for_range(start_point..end_point)
11202                .collect::<String>();
11203
11204            let LineManipulationResult {
11205                new_text,
11206                line_count_before,
11207                line_count_after,
11208            } = manipulate(&text);
11209
11210            edits.push((start_point..end_point, new_text));
11211
11212            // Selections must change based on added and removed line count
11213            let start_row =
11214                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11215            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11216            new_selections.push(Selection {
11217                id: selection.id,
11218                start: start_row,
11219                end: end_row,
11220                goal: SelectionGoal::None,
11221                reversed: selection.reversed,
11222            });
11223
11224            if line_count_after > line_count_before {
11225                added_lines += line_count_after - line_count_before;
11226            } else if line_count_before > line_count_after {
11227                removed_lines += line_count_before - line_count_after;
11228            }
11229        }
11230
11231        self.transact(window, cx, |this, window, cx| {
11232            let buffer = this.buffer.update(cx, |buffer, cx| {
11233                buffer.edit(edits, None, cx);
11234                buffer.snapshot(cx)
11235            });
11236
11237            // Recalculate offsets on newly edited buffer
11238            let new_selections = new_selections
11239                .iter()
11240                .map(|s| {
11241                    let start_point = Point::new(s.start.0, 0);
11242                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11243                    Selection {
11244                        id: s.id,
11245                        start: buffer.point_to_offset(start_point),
11246                        end: buffer.point_to_offset(end_point),
11247                        goal: s.goal,
11248                        reversed: s.reversed,
11249                    }
11250                })
11251                .collect();
11252
11253            this.change_selections(Default::default(), window, cx, |s| {
11254                s.select(new_selections);
11255            });
11256
11257            this.request_autoscroll(Autoscroll::fit(), cx);
11258        });
11259    }
11260
11261    fn manipulate_immutable_lines<Fn>(
11262        &mut self,
11263        window: &mut Window,
11264        cx: &mut Context<Self>,
11265        mut callback: Fn,
11266    ) where
11267        Fn: FnMut(&mut Vec<&str>),
11268    {
11269        self.manipulate_lines(window, cx, |text| {
11270            let mut lines: Vec<&str> = text.split('\n').collect();
11271            let line_count_before = lines.len();
11272
11273            callback(&mut lines);
11274
11275            LineManipulationResult {
11276                new_text: lines.join("\n"),
11277                line_count_before,
11278                line_count_after: lines.len(),
11279            }
11280        });
11281    }
11282
11283    fn manipulate_mutable_lines<Fn>(
11284        &mut self,
11285        window: &mut Window,
11286        cx: &mut Context<Self>,
11287        mut callback: Fn,
11288    ) where
11289        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11290    {
11291        self.manipulate_lines(window, cx, |text| {
11292            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11293            let line_count_before = lines.len();
11294
11295            callback(&mut lines);
11296
11297            LineManipulationResult {
11298                new_text: lines.join("\n"),
11299                line_count_before,
11300                line_count_after: lines.len(),
11301            }
11302        });
11303    }
11304
11305    pub fn convert_indentation_to_spaces(
11306        &mut self,
11307        _: &ConvertIndentationToSpaces,
11308        window: &mut Window,
11309        cx: &mut Context<Self>,
11310    ) {
11311        let settings = self.buffer.read(cx).language_settings(cx);
11312        let tab_size = settings.tab_size.get() as usize;
11313
11314        self.manipulate_mutable_lines(window, cx, |lines| {
11315            // Allocates a reasonably sized scratch buffer once for the whole loop
11316            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11317            // Avoids recomputing spaces that could be inserted many times
11318            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11319                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11320                .collect();
11321
11322            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11323                let mut chars = line.as_ref().chars();
11324                let mut col = 0;
11325                let mut changed = false;
11326
11327                for ch in chars.by_ref() {
11328                    match ch {
11329                        ' ' => {
11330                            reindented_line.push(' ');
11331                            col += 1;
11332                        }
11333                        '\t' => {
11334                            // \t are converted to spaces depending on the current column
11335                            let spaces_len = tab_size - (col % tab_size);
11336                            reindented_line.extend(&space_cache[spaces_len - 1]);
11337                            col += spaces_len;
11338                            changed = true;
11339                        }
11340                        _ => {
11341                            // If we dont append before break, the character is consumed
11342                            reindented_line.push(ch);
11343                            break;
11344                        }
11345                    }
11346                }
11347
11348                if !changed {
11349                    reindented_line.clear();
11350                    continue;
11351                }
11352                // Append the rest of the line and replace old reference with new one
11353                reindented_line.extend(chars);
11354                *line = Cow::Owned(reindented_line.clone());
11355                reindented_line.clear();
11356            }
11357        });
11358    }
11359
11360    pub fn convert_indentation_to_tabs(
11361        &mut self,
11362        _: &ConvertIndentationToTabs,
11363        window: &mut Window,
11364        cx: &mut Context<Self>,
11365    ) {
11366        let settings = self.buffer.read(cx).language_settings(cx);
11367        let tab_size = settings.tab_size.get() as usize;
11368
11369        self.manipulate_mutable_lines(window, cx, |lines| {
11370            // Allocates a reasonably sized buffer once for the whole loop
11371            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11372            // Avoids recomputing spaces that could be inserted many times
11373            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11374                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11375                .collect();
11376
11377            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11378                let mut chars = line.chars();
11379                let mut spaces_count = 0;
11380                let mut first_non_indent_char = None;
11381                let mut changed = false;
11382
11383                for ch in chars.by_ref() {
11384                    match ch {
11385                        ' ' => {
11386                            // Keep track of spaces. Append \t when we reach tab_size
11387                            spaces_count += 1;
11388                            changed = true;
11389                            if spaces_count == tab_size {
11390                                reindented_line.push('\t');
11391                                spaces_count = 0;
11392                            }
11393                        }
11394                        '\t' => {
11395                            reindented_line.push('\t');
11396                            spaces_count = 0;
11397                        }
11398                        _ => {
11399                            // Dont append it yet, we might have remaining spaces
11400                            first_non_indent_char = Some(ch);
11401                            break;
11402                        }
11403                    }
11404                }
11405
11406                if !changed {
11407                    reindented_line.clear();
11408                    continue;
11409                }
11410                // Remaining spaces that didn't make a full tab stop
11411                if spaces_count > 0 {
11412                    reindented_line.extend(&space_cache[spaces_count - 1]);
11413                }
11414                // If we consume an extra character that was not indentation, add it back
11415                if let Some(extra_char) = first_non_indent_char {
11416                    reindented_line.push(extra_char);
11417                }
11418                // Append the rest of the line and replace old reference with new one
11419                reindented_line.extend(chars);
11420                *line = Cow::Owned(reindented_line.clone());
11421                reindented_line.clear();
11422            }
11423        });
11424    }
11425
11426    pub fn convert_to_upper_case(
11427        &mut self,
11428        _: &ConvertToUpperCase,
11429        window: &mut Window,
11430        cx: &mut Context<Self>,
11431    ) {
11432        self.manipulate_text(window, cx, |text| text.to_uppercase())
11433    }
11434
11435    pub fn convert_to_lower_case(
11436        &mut self,
11437        _: &ConvertToLowerCase,
11438        window: &mut Window,
11439        cx: &mut Context<Self>,
11440    ) {
11441        self.manipulate_text(window, cx, |text| text.to_lowercase())
11442    }
11443
11444    pub fn convert_to_title_case(
11445        &mut self,
11446        _: &ConvertToTitleCase,
11447        window: &mut Window,
11448        cx: &mut Context<Self>,
11449    ) {
11450        self.manipulate_text(window, cx, |text| {
11451            text.split('\n')
11452                .map(|line| line.to_case(Case::Title))
11453                .join("\n")
11454        })
11455    }
11456
11457    pub fn convert_to_snake_case(
11458        &mut self,
11459        _: &ConvertToSnakeCase,
11460        window: &mut Window,
11461        cx: &mut Context<Self>,
11462    ) {
11463        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11464    }
11465
11466    pub fn convert_to_kebab_case(
11467        &mut self,
11468        _: &ConvertToKebabCase,
11469        window: &mut Window,
11470        cx: &mut Context<Self>,
11471    ) {
11472        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11473    }
11474
11475    pub fn convert_to_upper_camel_case(
11476        &mut self,
11477        _: &ConvertToUpperCamelCase,
11478        window: &mut Window,
11479        cx: &mut Context<Self>,
11480    ) {
11481        self.manipulate_text(window, cx, |text| {
11482            text.split('\n')
11483                .map(|line| line.to_case(Case::UpperCamel))
11484                .join("\n")
11485        })
11486    }
11487
11488    pub fn convert_to_lower_camel_case(
11489        &mut self,
11490        _: &ConvertToLowerCamelCase,
11491        window: &mut Window,
11492        cx: &mut Context<Self>,
11493    ) {
11494        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11495    }
11496
11497    pub fn convert_to_opposite_case(
11498        &mut self,
11499        _: &ConvertToOppositeCase,
11500        window: &mut Window,
11501        cx: &mut Context<Self>,
11502    ) {
11503        self.manipulate_text(window, cx, |text| {
11504            text.chars()
11505                .fold(String::with_capacity(text.len()), |mut t, c| {
11506                    if c.is_uppercase() {
11507                        t.extend(c.to_lowercase());
11508                    } else {
11509                        t.extend(c.to_uppercase());
11510                    }
11511                    t
11512                })
11513        })
11514    }
11515
11516    pub fn convert_to_sentence_case(
11517        &mut self,
11518        _: &ConvertToSentenceCase,
11519        window: &mut Window,
11520        cx: &mut Context<Self>,
11521    ) {
11522        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11523    }
11524
11525    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11526        self.manipulate_text(window, cx, |text| {
11527            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11528            if has_upper_case_characters {
11529                text.to_lowercase()
11530            } else {
11531                text.to_uppercase()
11532            }
11533        })
11534    }
11535
11536    pub fn convert_to_rot13(
11537        &mut self,
11538        _: &ConvertToRot13,
11539        window: &mut Window,
11540        cx: &mut Context<Self>,
11541    ) {
11542        self.manipulate_text(window, cx, |text| {
11543            text.chars()
11544                .map(|c| match c {
11545                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11546                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11547                    _ => c,
11548                })
11549                .collect()
11550        })
11551    }
11552
11553    pub fn convert_to_rot47(
11554        &mut self,
11555        _: &ConvertToRot47,
11556        window: &mut Window,
11557        cx: &mut Context<Self>,
11558    ) {
11559        self.manipulate_text(window, cx, |text| {
11560            text.chars()
11561                .map(|c| {
11562                    let code_point = c as u32;
11563                    if code_point >= 33 && code_point <= 126 {
11564                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11565                    }
11566                    c
11567                })
11568                .collect()
11569        })
11570    }
11571
11572    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11573    where
11574        Fn: FnMut(&str) -> String,
11575    {
11576        let buffer = self.buffer.read(cx).snapshot(cx);
11577
11578        let mut new_selections = Vec::new();
11579        let mut edits = Vec::new();
11580        let mut selection_adjustment = 0i32;
11581
11582        for selection in self.selections.all_adjusted(cx) {
11583            let selection_is_empty = selection.is_empty();
11584
11585            let (start, end) = if selection_is_empty {
11586                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11587                (word_range.start, word_range.end)
11588            } else {
11589                (
11590                    buffer.point_to_offset(selection.start),
11591                    buffer.point_to_offset(selection.end),
11592                )
11593            };
11594
11595            let text = buffer.text_for_range(start..end).collect::<String>();
11596            let old_length = text.len() as i32;
11597            let text = callback(&text);
11598
11599            new_selections.push(Selection {
11600                start: (start as i32 - selection_adjustment) as usize,
11601                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11602                goal: SelectionGoal::None,
11603                id: selection.id,
11604                reversed: selection.reversed,
11605            });
11606
11607            selection_adjustment += old_length - text.len() as i32;
11608
11609            edits.push((start..end, text));
11610        }
11611
11612        self.transact(window, cx, |this, window, cx| {
11613            this.buffer.update(cx, |buffer, cx| {
11614                buffer.edit(edits, None, cx);
11615            });
11616
11617            this.change_selections(Default::default(), window, cx, |s| {
11618                s.select(new_selections);
11619            });
11620
11621            this.request_autoscroll(Autoscroll::fit(), cx);
11622        });
11623    }
11624
11625    pub fn move_selection_on_drop(
11626        &mut self,
11627        selection: &Selection<Anchor>,
11628        target: DisplayPoint,
11629        is_cut: bool,
11630        window: &mut Window,
11631        cx: &mut Context<Self>,
11632    ) {
11633        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11634        let buffer = display_map.buffer_snapshot();
11635        let mut edits = Vec::new();
11636        let insert_point = display_map
11637            .clip_point(target, Bias::Left)
11638            .to_point(&display_map);
11639        let text = buffer
11640            .text_for_range(selection.start..selection.end)
11641            .collect::<String>();
11642        if is_cut {
11643            edits.push(((selection.start..selection.end), String::new()));
11644        }
11645        let insert_anchor = buffer.anchor_before(insert_point);
11646        edits.push(((insert_anchor..insert_anchor), text));
11647        let last_edit_start = insert_anchor.bias_left(buffer);
11648        let last_edit_end = insert_anchor.bias_right(buffer);
11649        self.transact(window, cx, |this, window, cx| {
11650            this.buffer.update(cx, |buffer, cx| {
11651                buffer.edit(edits, None, cx);
11652            });
11653            this.change_selections(Default::default(), window, cx, |s| {
11654                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11655            });
11656        });
11657    }
11658
11659    pub fn clear_selection_drag_state(&mut self) {
11660        self.selection_drag_state = SelectionDragState::None;
11661    }
11662
11663    pub fn duplicate(
11664        &mut self,
11665        upwards: bool,
11666        whole_lines: bool,
11667        window: &mut Window,
11668        cx: &mut Context<Self>,
11669    ) {
11670        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11671
11672        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11673        let buffer = display_map.buffer_snapshot();
11674        let selections = self.selections.all::<Point>(cx);
11675
11676        let mut edits = Vec::new();
11677        let mut selections_iter = selections.iter().peekable();
11678        while let Some(selection) = selections_iter.next() {
11679            let mut rows = selection.spanned_rows(false, &display_map);
11680            // duplicate line-wise
11681            if whole_lines || selection.start == selection.end {
11682                // Avoid duplicating the same lines twice.
11683                while let Some(next_selection) = selections_iter.peek() {
11684                    let next_rows = next_selection.spanned_rows(false, &display_map);
11685                    if next_rows.start < rows.end {
11686                        rows.end = next_rows.end;
11687                        selections_iter.next().unwrap();
11688                    } else {
11689                        break;
11690                    }
11691                }
11692
11693                // Copy the text from the selected row region and splice it either at the start
11694                // or end of the region.
11695                let start = Point::new(rows.start.0, 0);
11696                let end = Point::new(
11697                    rows.end.previous_row().0,
11698                    buffer.line_len(rows.end.previous_row()),
11699                );
11700
11701                let mut text = buffer.text_for_range(start..end).collect::<String>();
11702
11703                let insert_location = if upwards {
11704                    // When duplicating upward, we need to insert before the current line.
11705                    // If we're on the last line and it doesn't end with a newline,
11706                    // we need to add a newline before the duplicated content.
11707                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11708                        && buffer.max_point().column > 0
11709                        && !text.ends_with('\n');
11710
11711                    if needs_leading_newline {
11712                        text.insert(0, '\n');
11713                        end
11714                    } else {
11715                        text.push('\n');
11716                        Point::new(rows.end.0, 0)
11717                    }
11718                } else {
11719                    text.push('\n');
11720                    start
11721                };
11722                edits.push((insert_location..insert_location, text));
11723            } else {
11724                // duplicate character-wise
11725                let start = selection.start;
11726                let end = selection.end;
11727                let text = buffer.text_for_range(start..end).collect::<String>();
11728                edits.push((selection.end..selection.end, text));
11729            }
11730        }
11731
11732        self.transact(window, cx, |this, _, cx| {
11733            this.buffer.update(cx, |buffer, cx| {
11734                buffer.edit(edits, None, cx);
11735            });
11736
11737            this.request_autoscroll(Autoscroll::fit(), cx);
11738        });
11739    }
11740
11741    pub fn duplicate_line_up(
11742        &mut self,
11743        _: &DuplicateLineUp,
11744        window: &mut Window,
11745        cx: &mut Context<Self>,
11746    ) {
11747        self.duplicate(true, true, window, cx);
11748    }
11749
11750    pub fn duplicate_line_down(
11751        &mut self,
11752        _: &DuplicateLineDown,
11753        window: &mut Window,
11754        cx: &mut Context<Self>,
11755    ) {
11756        self.duplicate(false, true, window, cx);
11757    }
11758
11759    pub fn duplicate_selection(
11760        &mut self,
11761        _: &DuplicateSelection,
11762        window: &mut Window,
11763        cx: &mut Context<Self>,
11764    ) {
11765        self.duplicate(false, false, window, cx);
11766    }
11767
11768    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11769        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11770        if self.mode.is_single_line() {
11771            cx.propagate();
11772            return;
11773        }
11774
11775        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11776        let buffer = self.buffer.read(cx).snapshot(cx);
11777
11778        let mut edits = Vec::new();
11779        let mut unfold_ranges = Vec::new();
11780        let mut refold_creases = Vec::new();
11781
11782        let selections = self.selections.all::<Point>(cx);
11783        let mut selections = selections.iter().peekable();
11784        let mut contiguous_row_selections = Vec::new();
11785        let mut new_selections = Vec::new();
11786
11787        while let Some(selection) = selections.next() {
11788            // Find all the selections that span a contiguous row range
11789            let (start_row, end_row) = consume_contiguous_rows(
11790                &mut contiguous_row_selections,
11791                selection,
11792                &display_map,
11793                &mut selections,
11794            );
11795
11796            // Move the text spanned by the row range to be before the line preceding the row range
11797            if start_row.0 > 0 {
11798                let range_to_move = Point::new(
11799                    start_row.previous_row().0,
11800                    buffer.line_len(start_row.previous_row()),
11801                )
11802                    ..Point::new(
11803                        end_row.previous_row().0,
11804                        buffer.line_len(end_row.previous_row()),
11805                    );
11806                let insertion_point = display_map
11807                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11808                    .0;
11809
11810                // Don't move lines across excerpts
11811                if buffer
11812                    .excerpt_containing(insertion_point..range_to_move.end)
11813                    .is_some()
11814                {
11815                    let text = buffer
11816                        .text_for_range(range_to_move.clone())
11817                        .flat_map(|s| s.chars())
11818                        .skip(1)
11819                        .chain(['\n'])
11820                        .collect::<String>();
11821
11822                    edits.push((
11823                        buffer.anchor_after(range_to_move.start)
11824                            ..buffer.anchor_before(range_to_move.end),
11825                        String::new(),
11826                    ));
11827                    let insertion_anchor = buffer.anchor_after(insertion_point);
11828                    edits.push((insertion_anchor..insertion_anchor, text));
11829
11830                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11831
11832                    // Move selections up
11833                    new_selections.extend(contiguous_row_selections.drain(..).map(
11834                        |mut selection| {
11835                            selection.start.row -= row_delta;
11836                            selection.end.row -= row_delta;
11837                            selection
11838                        },
11839                    ));
11840
11841                    // Move folds up
11842                    unfold_ranges.push(range_to_move.clone());
11843                    for fold in display_map.folds_in_range(
11844                        buffer.anchor_before(range_to_move.start)
11845                            ..buffer.anchor_after(range_to_move.end),
11846                    ) {
11847                        let mut start = fold.range.start.to_point(&buffer);
11848                        let mut end = fold.range.end.to_point(&buffer);
11849                        start.row -= row_delta;
11850                        end.row -= row_delta;
11851                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11852                    }
11853                }
11854            }
11855
11856            // If we didn't move line(s), preserve the existing selections
11857            new_selections.append(&mut contiguous_row_selections);
11858        }
11859
11860        self.transact(window, cx, |this, window, cx| {
11861            this.unfold_ranges(&unfold_ranges, true, true, cx);
11862            this.buffer.update(cx, |buffer, cx| {
11863                for (range, text) in edits {
11864                    buffer.edit([(range, text)], None, cx);
11865                }
11866            });
11867            this.fold_creases(refold_creases, true, window, cx);
11868            this.change_selections(Default::default(), window, cx, |s| {
11869                s.select(new_selections);
11870            })
11871        });
11872    }
11873
11874    pub fn move_line_down(
11875        &mut self,
11876        _: &MoveLineDown,
11877        window: &mut Window,
11878        cx: &mut Context<Self>,
11879    ) {
11880        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11881        if self.mode.is_single_line() {
11882            cx.propagate();
11883            return;
11884        }
11885
11886        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11887        let buffer = self.buffer.read(cx).snapshot(cx);
11888
11889        let mut edits = Vec::new();
11890        let mut unfold_ranges = Vec::new();
11891        let mut refold_creases = Vec::new();
11892
11893        let selections = self.selections.all::<Point>(cx);
11894        let mut selections = selections.iter().peekable();
11895        let mut contiguous_row_selections = Vec::new();
11896        let mut new_selections = Vec::new();
11897
11898        while let Some(selection) = selections.next() {
11899            // Find all the selections that span a contiguous row range
11900            let (start_row, end_row) = consume_contiguous_rows(
11901                &mut contiguous_row_selections,
11902                selection,
11903                &display_map,
11904                &mut selections,
11905            );
11906
11907            // Move the text spanned by the row range to be after the last line of the row range
11908            if end_row.0 <= buffer.max_point().row {
11909                let range_to_move =
11910                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11911                let insertion_point = display_map
11912                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11913                    .0;
11914
11915                // Don't move lines across excerpt boundaries
11916                if buffer
11917                    .excerpt_containing(range_to_move.start..insertion_point)
11918                    .is_some()
11919                {
11920                    let mut text = String::from("\n");
11921                    text.extend(buffer.text_for_range(range_to_move.clone()));
11922                    text.pop(); // Drop trailing newline
11923                    edits.push((
11924                        buffer.anchor_after(range_to_move.start)
11925                            ..buffer.anchor_before(range_to_move.end),
11926                        String::new(),
11927                    ));
11928                    let insertion_anchor = buffer.anchor_after(insertion_point);
11929                    edits.push((insertion_anchor..insertion_anchor, text));
11930
11931                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11932
11933                    // Move selections down
11934                    new_selections.extend(contiguous_row_selections.drain(..).map(
11935                        |mut selection| {
11936                            selection.start.row += row_delta;
11937                            selection.end.row += row_delta;
11938                            selection
11939                        },
11940                    ));
11941
11942                    // Move folds down
11943                    unfold_ranges.push(range_to_move.clone());
11944                    for fold in display_map.folds_in_range(
11945                        buffer.anchor_before(range_to_move.start)
11946                            ..buffer.anchor_after(range_to_move.end),
11947                    ) {
11948                        let mut start = fold.range.start.to_point(&buffer);
11949                        let mut end = fold.range.end.to_point(&buffer);
11950                        start.row += row_delta;
11951                        end.row += row_delta;
11952                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11953                    }
11954                }
11955            }
11956
11957            // If we didn't move line(s), preserve the existing selections
11958            new_selections.append(&mut contiguous_row_selections);
11959        }
11960
11961        self.transact(window, cx, |this, window, cx| {
11962            this.unfold_ranges(&unfold_ranges, true, true, cx);
11963            this.buffer.update(cx, |buffer, cx| {
11964                for (range, text) in edits {
11965                    buffer.edit([(range, text)], None, cx);
11966                }
11967            });
11968            this.fold_creases(refold_creases, true, window, cx);
11969            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11970        });
11971    }
11972
11973    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11974        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11975        let text_layout_details = &self.text_layout_details(window);
11976        self.transact(window, cx, |this, window, cx| {
11977            let edits = this.change_selections(Default::default(), window, cx, |s| {
11978                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11979                s.move_with(|display_map, selection| {
11980                    if !selection.is_empty() {
11981                        return;
11982                    }
11983
11984                    let mut head = selection.head();
11985                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11986                    if head.column() == display_map.line_len(head.row()) {
11987                        transpose_offset = display_map
11988                            .buffer_snapshot()
11989                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11990                    }
11991
11992                    if transpose_offset == 0 {
11993                        return;
11994                    }
11995
11996                    *head.column_mut() += 1;
11997                    head = display_map.clip_point(head, Bias::Right);
11998                    let goal = SelectionGoal::HorizontalPosition(
11999                        display_map
12000                            .x_for_display_point(head, text_layout_details)
12001                            .into(),
12002                    );
12003                    selection.collapse_to(head, goal);
12004
12005                    let transpose_start = display_map
12006                        .buffer_snapshot()
12007                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12008                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12009                        let transpose_end = display_map
12010                            .buffer_snapshot()
12011                            .clip_offset(transpose_offset + 1, Bias::Right);
12012                        if let Some(ch) = display_map
12013                            .buffer_snapshot()
12014                            .chars_at(transpose_start)
12015                            .next()
12016                        {
12017                            edits.push((transpose_start..transpose_offset, String::new()));
12018                            edits.push((transpose_end..transpose_end, ch.to_string()));
12019                        }
12020                    }
12021                });
12022                edits
12023            });
12024            this.buffer
12025                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12026            let selections = this.selections.all::<usize>(cx);
12027            this.change_selections(Default::default(), window, cx, |s| {
12028                s.select(selections);
12029            });
12030        });
12031    }
12032
12033    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12034        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12035        if self.mode.is_single_line() {
12036            cx.propagate();
12037            return;
12038        }
12039
12040        self.rewrap_impl(RewrapOptions::default(), cx)
12041    }
12042
12043    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12044        let buffer = self.buffer.read(cx).snapshot(cx);
12045        let selections = self.selections.all::<Point>(cx);
12046
12047        #[derive(Clone, Debug, PartialEq)]
12048        enum CommentFormat {
12049            /// single line comment, with prefix for line
12050            Line(String),
12051            /// single line within a block comment, with prefix for line
12052            BlockLine(String),
12053            /// a single line of a block comment that includes the initial delimiter
12054            BlockCommentWithStart(BlockCommentConfig),
12055            /// a single line of a block comment that includes the ending delimiter
12056            BlockCommentWithEnd(BlockCommentConfig),
12057        }
12058
12059        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12060        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12061            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12062                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12063                .peekable();
12064
12065            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12066                row
12067            } else {
12068                return Vec::new();
12069            };
12070
12071            let language_settings = buffer.language_settings_at(selection.head(), cx);
12072            let language_scope = buffer.language_scope_at(selection.head());
12073
12074            let indent_and_prefix_for_row =
12075                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12076                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12077                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12078                        &language_scope
12079                    {
12080                        let indent_end = Point::new(row, indent.len);
12081                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12082                        let line_text_after_indent = buffer
12083                            .text_for_range(indent_end..line_end)
12084                            .collect::<String>();
12085
12086                        let is_within_comment_override = buffer
12087                            .language_scope_at(indent_end)
12088                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12089                        let comment_delimiters = if is_within_comment_override {
12090                            // we are within a comment syntax node, but we don't
12091                            // yet know what kind of comment: block, doc or line
12092                            match (
12093                                language_scope.documentation_comment(),
12094                                language_scope.block_comment(),
12095                            ) {
12096                                (Some(config), _) | (_, Some(config))
12097                                    if buffer.contains_str_at(indent_end, &config.start) =>
12098                                {
12099                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12100                                }
12101                                (Some(config), _) | (_, Some(config))
12102                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12103                                {
12104                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12105                                }
12106                                (Some(config), _) | (_, Some(config))
12107                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12108                                {
12109                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12110                                }
12111                                (_, _) => language_scope
12112                                    .line_comment_prefixes()
12113                                    .iter()
12114                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12115                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12116                            }
12117                        } else {
12118                            // we not in an overridden comment node, but we may
12119                            // be within a non-overridden line comment node
12120                            language_scope
12121                                .line_comment_prefixes()
12122                                .iter()
12123                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12124                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12125                        };
12126
12127                        let rewrap_prefix = language_scope
12128                            .rewrap_prefixes()
12129                            .iter()
12130                            .find_map(|prefix_regex| {
12131                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12132                                    if mat.start() == 0 {
12133                                        Some(mat.as_str().to_string())
12134                                    } else {
12135                                        None
12136                                    }
12137                                })
12138                            })
12139                            .flatten();
12140                        (comment_delimiters, rewrap_prefix)
12141                    } else {
12142                        (None, None)
12143                    };
12144                    (indent, comment_prefix, rewrap_prefix)
12145                };
12146
12147            let mut ranges = Vec::new();
12148            let from_empty_selection = selection.is_empty();
12149
12150            let mut current_range_start = first_row;
12151            let mut prev_row = first_row;
12152            let (
12153                mut current_range_indent,
12154                mut current_range_comment_delimiters,
12155                mut current_range_rewrap_prefix,
12156            ) = indent_and_prefix_for_row(first_row);
12157
12158            for row in non_blank_rows_iter.skip(1) {
12159                let has_paragraph_break = row > prev_row + 1;
12160
12161                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12162                    indent_and_prefix_for_row(row);
12163
12164                let has_indent_change = row_indent != current_range_indent;
12165                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12166
12167                let has_boundary_change = has_comment_change
12168                    || row_rewrap_prefix.is_some()
12169                    || (has_indent_change && current_range_comment_delimiters.is_some());
12170
12171                if has_paragraph_break || has_boundary_change {
12172                    ranges.push((
12173                        language_settings.clone(),
12174                        Point::new(current_range_start, 0)
12175                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12176                        current_range_indent,
12177                        current_range_comment_delimiters.clone(),
12178                        current_range_rewrap_prefix.clone(),
12179                        from_empty_selection,
12180                    ));
12181                    current_range_start = row;
12182                    current_range_indent = row_indent;
12183                    current_range_comment_delimiters = row_comment_delimiters;
12184                    current_range_rewrap_prefix = row_rewrap_prefix;
12185                }
12186                prev_row = row;
12187            }
12188
12189            ranges.push((
12190                language_settings.clone(),
12191                Point::new(current_range_start, 0)
12192                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12193                current_range_indent,
12194                current_range_comment_delimiters,
12195                current_range_rewrap_prefix,
12196                from_empty_selection,
12197            ));
12198
12199            ranges
12200        });
12201
12202        let mut edits = Vec::new();
12203        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12204
12205        for (
12206            language_settings,
12207            wrap_range,
12208            mut indent_size,
12209            comment_prefix,
12210            rewrap_prefix,
12211            from_empty_selection,
12212        ) in wrap_ranges
12213        {
12214            let mut start_row = wrap_range.start.row;
12215            let mut end_row = wrap_range.end.row;
12216
12217            // Skip selections that overlap with a range that has already been rewrapped.
12218            let selection_range = start_row..end_row;
12219            if rewrapped_row_ranges
12220                .iter()
12221                .any(|range| range.overlaps(&selection_range))
12222            {
12223                continue;
12224            }
12225
12226            let tab_size = language_settings.tab_size;
12227
12228            let (line_prefix, inside_comment) = match &comment_prefix {
12229                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12230                    (Some(prefix.as_str()), true)
12231                }
12232                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12233                    (Some(prefix.as_ref()), true)
12234                }
12235                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12236                    start: _,
12237                    end: _,
12238                    prefix,
12239                    tab_size,
12240                })) => {
12241                    indent_size.len += tab_size;
12242                    (Some(prefix.as_ref()), true)
12243                }
12244                None => (None, false),
12245            };
12246            let indent_prefix = indent_size.chars().collect::<String>();
12247            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12248
12249            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12250                RewrapBehavior::InComments => inside_comment,
12251                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12252                RewrapBehavior::Anywhere => true,
12253            };
12254
12255            let should_rewrap = options.override_language_settings
12256                || allow_rewrap_based_on_language
12257                || self.hard_wrap.is_some();
12258            if !should_rewrap {
12259                continue;
12260            }
12261
12262            if from_empty_selection {
12263                'expand_upwards: while start_row > 0 {
12264                    let prev_row = start_row - 1;
12265                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12266                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12267                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12268                    {
12269                        start_row = prev_row;
12270                    } else {
12271                        break 'expand_upwards;
12272                    }
12273                }
12274
12275                'expand_downwards: while end_row < buffer.max_point().row {
12276                    let next_row = end_row + 1;
12277                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12278                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12279                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12280                    {
12281                        end_row = next_row;
12282                    } else {
12283                        break 'expand_downwards;
12284                    }
12285                }
12286            }
12287
12288            let start = Point::new(start_row, 0);
12289            let start_offset = ToOffset::to_offset(&start, &buffer);
12290            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12291            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12292            let mut first_line_delimiter = None;
12293            let mut last_line_delimiter = None;
12294            let Some(lines_without_prefixes) = selection_text
12295                .lines()
12296                .enumerate()
12297                .map(|(ix, line)| {
12298                    let line_trimmed = line.trim_start();
12299                    if rewrap_prefix.is_some() && ix > 0 {
12300                        Ok(line_trimmed)
12301                    } else if let Some(
12302                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12303                            start,
12304                            prefix,
12305                            end,
12306                            tab_size,
12307                        })
12308                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12309                            start,
12310                            prefix,
12311                            end,
12312                            tab_size,
12313                        }),
12314                    ) = &comment_prefix
12315                    {
12316                        let line_trimmed = line_trimmed
12317                            .strip_prefix(start.as_ref())
12318                            .map(|s| {
12319                                let mut indent_size = indent_size;
12320                                indent_size.len -= tab_size;
12321                                let indent_prefix: String = indent_size.chars().collect();
12322                                first_line_delimiter = Some((indent_prefix, start));
12323                                s.trim_start()
12324                            })
12325                            .unwrap_or(line_trimmed);
12326                        let line_trimmed = line_trimmed
12327                            .strip_suffix(end.as_ref())
12328                            .map(|s| {
12329                                last_line_delimiter = Some(end);
12330                                s.trim_end()
12331                            })
12332                            .unwrap_or(line_trimmed);
12333                        let line_trimmed = line_trimmed
12334                            .strip_prefix(prefix.as_ref())
12335                            .unwrap_or(line_trimmed);
12336                        Ok(line_trimmed)
12337                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12338                        line_trimmed.strip_prefix(prefix).with_context(|| {
12339                            format!("line did not start with prefix {prefix:?}: {line:?}")
12340                        })
12341                    } else {
12342                        line_trimmed
12343                            .strip_prefix(&line_prefix.trim_start())
12344                            .with_context(|| {
12345                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12346                            })
12347                    }
12348                })
12349                .collect::<Result<Vec<_>, _>>()
12350                .log_err()
12351            else {
12352                continue;
12353            };
12354
12355            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12356                buffer
12357                    .language_settings_at(Point::new(start_row, 0), cx)
12358                    .preferred_line_length as usize
12359            });
12360
12361            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12362                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12363            } else {
12364                line_prefix.clone()
12365            };
12366
12367            let wrapped_text = {
12368                let mut wrapped_text = wrap_with_prefix(
12369                    line_prefix,
12370                    subsequent_lines_prefix,
12371                    lines_without_prefixes.join("\n"),
12372                    wrap_column,
12373                    tab_size,
12374                    options.preserve_existing_whitespace,
12375                );
12376
12377                if let Some((indent, delimiter)) = first_line_delimiter {
12378                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12379                }
12380                if let Some(last_line) = last_line_delimiter {
12381                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12382                }
12383
12384                wrapped_text
12385            };
12386
12387            // TODO: should always use char-based diff while still supporting cursor behavior that
12388            // matches vim.
12389            let mut diff_options = DiffOptions::default();
12390            if options.override_language_settings {
12391                diff_options.max_word_diff_len = 0;
12392                diff_options.max_word_diff_line_count = 0;
12393            } else {
12394                diff_options.max_word_diff_len = usize::MAX;
12395                diff_options.max_word_diff_line_count = usize::MAX;
12396            }
12397
12398            for (old_range, new_text) in
12399                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12400            {
12401                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12402                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12403                edits.push((edit_start..edit_end, new_text));
12404            }
12405
12406            rewrapped_row_ranges.push(start_row..=end_row);
12407        }
12408
12409        self.buffer
12410            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12411    }
12412
12413    pub fn cut_common(
12414        &mut self,
12415        cut_no_selection_line: bool,
12416        window: &mut Window,
12417        cx: &mut Context<Self>,
12418    ) -> ClipboardItem {
12419        let mut text = String::new();
12420        let buffer = self.buffer.read(cx).snapshot(cx);
12421        let mut selections = self.selections.all::<Point>(cx);
12422        let mut clipboard_selections = Vec::with_capacity(selections.len());
12423        {
12424            let max_point = buffer.max_point();
12425            let mut is_first = true;
12426            for selection in &mut selections {
12427                let is_entire_line =
12428                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12429                if is_entire_line {
12430                    selection.start = Point::new(selection.start.row, 0);
12431                    if !selection.is_empty() && selection.end.column == 0 {
12432                        selection.end = cmp::min(max_point, selection.end);
12433                    } else {
12434                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12435                    }
12436                    selection.goal = SelectionGoal::None;
12437                }
12438                if is_first {
12439                    is_first = false;
12440                } else {
12441                    text += "\n";
12442                }
12443                let mut len = 0;
12444                for chunk in buffer.text_for_range(selection.start..selection.end) {
12445                    text.push_str(chunk);
12446                    len += chunk.len();
12447                }
12448                clipboard_selections.push(ClipboardSelection {
12449                    len,
12450                    is_entire_line,
12451                    first_line_indent: buffer
12452                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12453                        .len,
12454                });
12455            }
12456        }
12457
12458        self.transact(window, cx, |this, window, cx| {
12459            this.change_selections(Default::default(), window, cx, |s| {
12460                s.select(selections);
12461            });
12462            this.insert("", window, cx);
12463        });
12464        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12465    }
12466
12467    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12468        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12469        let item = self.cut_common(true, window, cx);
12470        cx.write_to_clipboard(item);
12471    }
12472
12473    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12474        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12475        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12476            s.move_with(|snapshot, sel| {
12477                if sel.is_empty() {
12478                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12479                }
12480                if sel.is_empty() {
12481                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12482                }
12483            });
12484        });
12485        let item = self.cut_common(false, window, cx);
12486        cx.set_global(KillRing(item))
12487    }
12488
12489    pub fn kill_ring_yank(
12490        &mut self,
12491        _: &KillRingYank,
12492        window: &mut Window,
12493        cx: &mut Context<Self>,
12494    ) {
12495        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12496        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12497            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12498                (kill_ring.text().to_string(), kill_ring.metadata_json())
12499            } else {
12500                return;
12501            }
12502        } else {
12503            return;
12504        };
12505        self.do_paste(&text, metadata, false, window, cx);
12506    }
12507
12508    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12509        self.do_copy(true, cx);
12510    }
12511
12512    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12513        self.do_copy(false, cx);
12514    }
12515
12516    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12517        let selections = self.selections.all::<Point>(cx);
12518        let buffer = self.buffer.read(cx).read(cx);
12519        let mut text = String::new();
12520
12521        let mut clipboard_selections = Vec::with_capacity(selections.len());
12522        {
12523            let max_point = buffer.max_point();
12524            let mut is_first = true;
12525            for selection in &selections {
12526                let mut start = selection.start;
12527                let mut end = selection.end;
12528                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12529                let mut add_trailing_newline = false;
12530                if is_entire_line {
12531                    start = Point::new(start.row, 0);
12532                    let next_line_start = Point::new(end.row + 1, 0);
12533                    if next_line_start <= max_point {
12534                        end = next_line_start;
12535                    } else {
12536                        // We're on the last line without a trailing newline.
12537                        // Copy to the end of the line and add a newline afterwards.
12538                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12539                        add_trailing_newline = true;
12540                    }
12541                }
12542
12543                let mut trimmed_selections = Vec::new();
12544                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12545                    let row = MultiBufferRow(start.row);
12546                    let first_indent = buffer.indent_size_for_line(row);
12547                    if first_indent.len == 0 || start.column > first_indent.len {
12548                        trimmed_selections.push(start..end);
12549                    } else {
12550                        trimmed_selections.push(
12551                            Point::new(row.0, first_indent.len)
12552                                ..Point::new(row.0, buffer.line_len(row)),
12553                        );
12554                        for row in start.row + 1..=end.row {
12555                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12556                            if row == end.row {
12557                                line_len = end.column;
12558                            }
12559                            if line_len == 0 {
12560                                trimmed_selections
12561                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12562                                continue;
12563                            }
12564                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12565                            if row_indent_size.len >= first_indent.len {
12566                                trimmed_selections.push(
12567                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12568                                );
12569                            } else {
12570                                trimmed_selections.clear();
12571                                trimmed_selections.push(start..end);
12572                                break;
12573                            }
12574                        }
12575                    }
12576                } else {
12577                    trimmed_selections.push(start..end);
12578                }
12579
12580                for trimmed_range in trimmed_selections {
12581                    if is_first {
12582                        is_first = false;
12583                    } else {
12584                        text += "\n";
12585                    }
12586                    let mut len = 0;
12587                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12588                        text.push_str(chunk);
12589                        len += chunk.len();
12590                    }
12591                    if add_trailing_newline {
12592                        text.push('\n');
12593                        len += 1;
12594                    }
12595                    clipboard_selections.push(ClipboardSelection {
12596                        len,
12597                        is_entire_line,
12598                        first_line_indent: buffer
12599                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12600                            .len,
12601                    });
12602                }
12603            }
12604        }
12605
12606        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12607            text,
12608            clipboard_selections,
12609        ));
12610    }
12611
12612    pub fn do_paste(
12613        &mut self,
12614        text: &String,
12615        clipboard_selections: Option<Vec<ClipboardSelection>>,
12616        handle_entire_lines: bool,
12617        window: &mut Window,
12618        cx: &mut Context<Self>,
12619    ) {
12620        if self.read_only(cx) {
12621            return;
12622        }
12623
12624        let clipboard_text = Cow::Borrowed(text.as_str());
12625
12626        self.transact(window, cx, |this, window, cx| {
12627            let had_active_edit_prediction = this.has_active_edit_prediction();
12628            let old_selections = this.selections.all::<usize>(cx);
12629            let cursor_offset = this.selections.last::<usize>(cx).head();
12630
12631            if let Some(mut clipboard_selections) = clipboard_selections {
12632                let all_selections_were_entire_line =
12633                    clipboard_selections.iter().all(|s| s.is_entire_line);
12634                let first_selection_indent_column =
12635                    clipboard_selections.first().map(|s| s.first_line_indent);
12636                if clipboard_selections.len() != old_selections.len() {
12637                    clipboard_selections.drain(..);
12638                }
12639                let mut auto_indent_on_paste = true;
12640
12641                this.buffer.update(cx, |buffer, cx| {
12642                    let snapshot = buffer.read(cx);
12643                    auto_indent_on_paste = snapshot
12644                        .language_settings_at(cursor_offset, cx)
12645                        .auto_indent_on_paste;
12646
12647                    let mut start_offset = 0;
12648                    let mut edits = Vec::new();
12649                    let mut original_indent_columns = Vec::new();
12650                    for (ix, selection) in old_selections.iter().enumerate() {
12651                        let to_insert;
12652                        let entire_line;
12653                        let original_indent_column;
12654                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12655                            let end_offset = start_offset + clipboard_selection.len;
12656                            to_insert = &clipboard_text[start_offset..end_offset];
12657                            entire_line = clipboard_selection.is_entire_line;
12658                            start_offset = end_offset + 1;
12659                            original_indent_column = Some(clipboard_selection.first_line_indent);
12660                        } else {
12661                            to_insert = &*clipboard_text;
12662                            entire_line = all_selections_were_entire_line;
12663                            original_indent_column = first_selection_indent_column
12664                        }
12665
12666                        let (range, to_insert) =
12667                            if selection.is_empty() && handle_entire_lines && entire_line {
12668                                // If the corresponding selection was empty when this slice of the
12669                                // clipboard text was written, then the entire line containing the
12670                                // selection was copied. If this selection is also currently empty,
12671                                // then paste the line before the current line of the buffer.
12672                                let column = selection.start.to_point(&snapshot).column as usize;
12673                                let line_start = selection.start - column;
12674                                (line_start..line_start, Cow::Borrowed(to_insert))
12675                            } else {
12676                                let language = snapshot.language_at(selection.head());
12677                                let range = selection.range();
12678                                if let Some(language) = language
12679                                    && language.name() == "Markdown".into()
12680                                {
12681                                    edit_for_markdown_paste(
12682                                        &snapshot,
12683                                        range,
12684                                        to_insert,
12685                                        url::Url::parse(to_insert).ok(),
12686                                    )
12687                                } else {
12688                                    (range, Cow::Borrowed(to_insert))
12689                                }
12690                            };
12691
12692                        edits.push((range, to_insert));
12693                        original_indent_columns.push(original_indent_column);
12694                    }
12695                    drop(snapshot);
12696
12697                    buffer.edit(
12698                        edits,
12699                        if auto_indent_on_paste {
12700                            Some(AutoindentMode::Block {
12701                                original_indent_columns,
12702                            })
12703                        } else {
12704                            None
12705                        },
12706                        cx,
12707                    );
12708                });
12709
12710                let selections = this.selections.all::<usize>(cx);
12711                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12712            } else {
12713                let url = url::Url::parse(&clipboard_text).ok();
12714
12715                let auto_indent_mode = if !clipboard_text.is_empty() {
12716                    Some(AutoindentMode::Block {
12717                        original_indent_columns: Vec::new(),
12718                    })
12719                } else {
12720                    None
12721                };
12722
12723                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12724                    let snapshot = buffer.snapshot(cx);
12725
12726                    let anchors = old_selections
12727                        .iter()
12728                        .map(|s| {
12729                            let anchor = snapshot.anchor_after(s.head());
12730                            s.map(|_| anchor)
12731                        })
12732                        .collect::<Vec<_>>();
12733
12734                    let mut edits = Vec::new();
12735
12736                    for selection in old_selections.iter() {
12737                        let language = snapshot.language_at(selection.head());
12738                        let range = selection.range();
12739
12740                        let (edit_range, edit_text) = if let Some(language) = language
12741                            && language.name() == "Markdown".into()
12742                        {
12743                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12744                        } else {
12745                            (range, clipboard_text.clone())
12746                        };
12747
12748                        edits.push((edit_range, edit_text));
12749                    }
12750
12751                    drop(snapshot);
12752                    buffer.edit(edits, auto_indent_mode, cx);
12753
12754                    anchors
12755                });
12756
12757                this.change_selections(Default::default(), window, cx, |s| {
12758                    s.select_anchors(selection_anchors);
12759                });
12760            }
12761
12762            let trigger_in_words =
12763                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12764
12765            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12766        });
12767    }
12768
12769    pub fn diff_clipboard_with_selection(
12770        &mut self,
12771        _: &DiffClipboardWithSelection,
12772        window: &mut Window,
12773        cx: &mut Context<Self>,
12774    ) {
12775        let selections = self.selections.all::<usize>(cx);
12776
12777        if selections.is_empty() {
12778            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12779            return;
12780        };
12781
12782        let clipboard_text = match cx.read_from_clipboard() {
12783            Some(item) => match item.entries().first() {
12784                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12785                _ => None,
12786            },
12787            None => None,
12788        };
12789
12790        let Some(clipboard_text) = clipboard_text else {
12791            log::warn!("Clipboard doesn't contain text.");
12792            return;
12793        };
12794
12795        window.dispatch_action(
12796            Box::new(DiffClipboardWithSelectionData {
12797                clipboard_text,
12798                editor: cx.entity(),
12799            }),
12800            cx,
12801        );
12802    }
12803
12804    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12805        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12806        if let Some(item) = cx.read_from_clipboard() {
12807            let entries = item.entries();
12808
12809            match entries.first() {
12810                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12811                // of all the pasted entries.
12812                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12813                    .do_paste(
12814                        clipboard_string.text(),
12815                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12816                        true,
12817                        window,
12818                        cx,
12819                    ),
12820                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12821            }
12822        }
12823    }
12824
12825    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12826        if self.read_only(cx) {
12827            return;
12828        }
12829
12830        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12831
12832        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12833            if let Some((selections, _)) =
12834                self.selection_history.transaction(transaction_id).cloned()
12835            {
12836                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12837                    s.select_anchors(selections.to_vec());
12838                });
12839            } else {
12840                log::error!(
12841                    "No entry in selection_history found for undo. \
12842                     This may correspond to a bug where undo does not update the selection. \
12843                     If this is occurring, please add details to \
12844                     https://github.com/zed-industries/zed/issues/22692"
12845                );
12846            }
12847            self.request_autoscroll(Autoscroll::fit(), cx);
12848            self.unmark_text(window, cx);
12849            self.refresh_edit_prediction(true, false, window, cx);
12850            cx.emit(EditorEvent::Edited { transaction_id });
12851            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12852        }
12853    }
12854
12855    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12856        if self.read_only(cx) {
12857            return;
12858        }
12859
12860        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12861
12862        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12863            if let Some((_, Some(selections))) =
12864                self.selection_history.transaction(transaction_id).cloned()
12865            {
12866                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12867                    s.select_anchors(selections.to_vec());
12868                });
12869            } else {
12870                log::error!(
12871                    "No entry in selection_history found for redo. \
12872                     This may correspond to a bug where undo does not update the selection. \
12873                     If this is occurring, please add details to \
12874                     https://github.com/zed-industries/zed/issues/22692"
12875                );
12876            }
12877            self.request_autoscroll(Autoscroll::fit(), cx);
12878            self.unmark_text(window, cx);
12879            self.refresh_edit_prediction(true, false, window, cx);
12880            cx.emit(EditorEvent::Edited { transaction_id });
12881        }
12882    }
12883
12884    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12885        self.buffer
12886            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12887    }
12888
12889    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12890        self.buffer
12891            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12892    }
12893
12894    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12895        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12896        self.change_selections(Default::default(), window, cx, |s| {
12897            s.move_with(|map, selection| {
12898                let cursor = if selection.is_empty() {
12899                    movement::left(map, selection.start)
12900                } else {
12901                    selection.start
12902                };
12903                selection.collapse_to(cursor, SelectionGoal::None);
12904            });
12905        })
12906    }
12907
12908    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12910        self.change_selections(Default::default(), window, cx, |s| {
12911            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12912        })
12913    }
12914
12915    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12916        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12917        self.change_selections(Default::default(), window, cx, |s| {
12918            s.move_with(|map, selection| {
12919                let cursor = if selection.is_empty() {
12920                    movement::right(map, selection.end)
12921                } else {
12922                    selection.end
12923                };
12924                selection.collapse_to(cursor, SelectionGoal::None)
12925            });
12926        })
12927    }
12928
12929    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12930        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12931        self.change_selections(Default::default(), window, cx, |s| {
12932            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12933        });
12934    }
12935
12936    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12937        if self.take_rename(true, window, cx).is_some() {
12938            return;
12939        }
12940
12941        if self.mode.is_single_line() {
12942            cx.propagate();
12943            return;
12944        }
12945
12946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12947
12948        let text_layout_details = &self.text_layout_details(window);
12949        let selection_count = self.selections.count();
12950        let first_selection = self.selections.first_anchor();
12951
12952        self.change_selections(Default::default(), window, cx, |s| {
12953            s.move_with(|map, selection| {
12954                if !selection.is_empty() {
12955                    selection.goal = SelectionGoal::None;
12956                }
12957                let (cursor, goal) = movement::up(
12958                    map,
12959                    selection.start,
12960                    selection.goal,
12961                    false,
12962                    text_layout_details,
12963                );
12964                selection.collapse_to(cursor, goal);
12965            });
12966        });
12967
12968        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12969        {
12970            cx.propagate();
12971        }
12972    }
12973
12974    pub fn move_up_by_lines(
12975        &mut self,
12976        action: &MoveUpByLines,
12977        window: &mut Window,
12978        cx: &mut Context<Self>,
12979    ) {
12980        if self.take_rename(true, window, cx).is_some() {
12981            return;
12982        }
12983
12984        if self.mode.is_single_line() {
12985            cx.propagate();
12986            return;
12987        }
12988
12989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12990
12991        let text_layout_details = &self.text_layout_details(window);
12992
12993        self.change_selections(Default::default(), window, cx, |s| {
12994            s.move_with(|map, selection| {
12995                if !selection.is_empty() {
12996                    selection.goal = SelectionGoal::None;
12997                }
12998                let (cursor, goal) = movement::up_by_rows(
12999                    map,
13000                    selection.start,
13001                    action.lines,
13002                    selection.goal,
13003                    false,
13004                    text_layout_details,
13005                );
13006                selection.collapse_to(cursor, goal);
13007            });
13008        })
13009    }
13010
13011    pub fn move_down_by_lines(
13012        &mut self,
13013        action: &MoveDownByLines,
13014        window: &mut Window,
13015        cx: &mut Context<Self>,
13016    ) {
13017        if self.take_rename(true, window, cx).is_some() {
13018            return;
13019        }
13020
13021        if self.mode.is_single_line() {
13022            cx.propagate();
13023            return;
13024        }
13025
13026        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13027
13028        let text_layout_details = &self.text_layout_details(window);
13029
13030        self.change_selections(Default::default(), window, cx, |s| {
13031            s.move_with(|map, selection| {
13032                if !selection.is_empty() {
13033                    selection.goal = SelectionGoal::None;
13034                }
13035                let (cursor, goal) = movement::down_by_rows(
13036                    map,
13037                    selection.start,
13038                    action.lines,
13039                    selection.goal,
13040                    false,
13041                    text_layout_details,
13042                );
13043                selection.collapse_to(cursor, goal);
13044            });
13045        })
13046    }
13047
13048    pub fn select_down_by_lines(
13049        &mut self,
13050        action: &SelectDownByLines,
13051        window: &mut Window,
13052        cx: &mut Context<Self>,
13053    ) {
13054        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13055        let text_layout_details = &self.text_layout_details(window);
13056        self.change_selections(Default::default(), window, cx, |s| {
13057            s.move_heads_with(|map, head, goal| {
13058                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13059            })
13060        })
13061    }
13062
13063    pub fn select_up_by_lines(
13064        &mut self,
13065        action: &SelectUpByLines,
13066        window: &mut Window,
13067        cx: &mut Context<Self>,
13068    ) {
13069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13070        let text_layout_details = &self.text_layout_details(window);
13071        self.change_selections(Default::default(), window, cx, |s| {
13072            s.move_heads_with(|map, head, goal| {
13073                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13074            })
13075        })
13076    }
13077
13078    pub fn select_page_up(
13079        &mut self,
13080        _: &SelectPageUp,
13081        window: &mut Window,
13082        cx: &mut Context<Self>,
13083    ) {
13084        let Some(row_count) = self.visible_row_count() else {
13085            return;
13086        };
13087
13088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13089
13090        let text_layout_details = &self.text_layout_details(window);
13091
13092        self.change_selections(Default::default(), window, cx, |s| {
13093            s.move_heads_with(|map, head, goal| {
13094                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13095            })
13096        })
13097    }
13098
13099    pub fn move_page_up(
13100        &mut self,
13101        action: &MovePageUp,
13102        window: &mut Window,
13103        cx: &mut Context<Self>,
13104    ) {
13105        if self.take_rename(true, window, cx).is_some() {
13106            return;
13107        }
13108
13109        if self
13110            .context_menu
13111            .borrow_mut()
13112            .as_mut()
13113            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13114            .unwrap_or(false)
13115        {
13116            return;
13117        }
13118
13119        if matches!(self.mode, EditorMode::SingleLine) {
13120            cx.propagate();
13121            return;
13122        }
13123
13124        let Some(row_count) = self.visible_row_count() else {
13125            return;
13126        };
13127
13128        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13129
13130        let effects = if action.center_cursor {
13131            SelectionEffects::scroll(Autoscroll::center())
13132        } else {
13133            SelectionEffects::default()
13134        };
13135
13136        let text_layout_details = &self.text_layout_details(window);
13137
13138        self.change_selections(effects, window, cx, |s| {
13139            s.move_with(|map, selection| {
13140                if !selection.is_empty() {
13141                    selection.goal = SelectionGoal::None;
13142                }
13143                let (cursor, goal) = movement::up_by_rows(
13144                    map,
13145                    selection.end,
13146                    row_count,
13147                    selection.goal,
13148                    false,
13149                    text_layout_details,
13150                );
13151                selection.collapse_to(cursor, goal);
13152            });
13153        });
13154    }
13155
13156    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13157        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13158        let text_layout_details = &self.text_layout_details(window);
13159        self.change_selections(Default::default(), window, cx, |s| {
13160            s.move_heads_with(|map, head, goal| {
13161                movement::up(map, head, goal, false, text_layout_details)
13162            })
13163        })
13164    }
13165
13166    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13167        self.take_rename(true, window, cx);
13168
13169        if self.mode.is_single_line() {
13170            cx.propagate();
13171            return;
13172        }
13173
13174        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13175
13176        let text_layout_details = &self.text_layout_details(window);
13177        let selection_count = self.selections.count();
13178        let first_selection = self.selections.first_anchor();
13179
13180        self.change_selections(Default::default(), window, cx, |s| {
13181            s.move_with(|map, selection| {
13182                if !selection.is_empty() {
13183                    selection.goal = SelectionGoal::None;
13184                }
13185                let (cursor, goal) = movement::down(
13186                    map,
13187                    selection.end,
13188                    selection.goal,
13189                    false,
13190                    text_layout_details,
13191                );
13192                selection.collapse_to(cursor, goal);
13193            });
13194        });
13195
13196        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13197        {
13198            cx.propagate();
13199        }
13200    }
13201
13202    pub fn select_page_down(
13203        &mut self,
13204        _: &SelectPageDown,
13205        window: &mut Window,
13206        cx: &mut Context<Self>,
13207    ) {
13208        let Some(row_count) = self.visible_row_count() else {
13209            return;
13210        };
13211
13212        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13213
13214        let text_layout_details = &self.text_layout_details(window);
13215
13216        self.change_selections(Default::default(), window, cx, |s| {
13217            s.move_heads_with(|map, head, goal| {
13218                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13219            })
13220        })
13221    }
13222
13223    pub fn move_page_down(
13224        &mut self,
13225        action: &MovePageDown,
13226        window: &mut Window,
13227        cx: &mut Context<Self>,
13228    ) {
13229        if self.take_rename(true, window, cx).is_some() {
13230            return;
13231        }
13232
13233        if self
13234            .context_menu
13235            .borrow_mut()
13236            .as_mut()
13237            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13238            .unwrap_or(false)
13239        {
13240            return;
13241        }
13242
13243        if matches!(self.mode, EditorMode::SingleLine) {
13244            cx.propagate();
13245            return;
13246        }
13247
13248        let Some(row_count) = self.visible_row_count() else {
13249            return;
13250        };
13251
13252        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13253
13254        let effects = if action.center_cursor {
13255            SelectionEffects::scroll(Autoscroll::center())
13256        } else {
13257            SelectionEffects::default()
13258        };
13259
13260        let text_layout_details = &self.text_layout_details(window);
13261        self.change_selections(effects, window, cx, |s| {
13262            s.move_with(|map, selection| {
13263                if !selection.is_empty() {
13264                    selection.goal = SelectionGoal::None;
13265                }
13266                let (cursor, goal) = movement::down_by_rows(
13267                    map,
13268                    selection.end,
13269                    row_count,
13270                    selection.goal,
13271                    false,
13272                    text_layout_details,
13273                );
13274                selection.collapse_to(cursor, goal);
13275            });
13276        });
13277    }
13278
13279    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13280        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13281        let text_layout_details = &self.text_layout_details(window);
13282        self.change_selections(Default::default(), window, cx, |s| {
13283            s.move_heads_with(|map, head, goal| {
13284                movement::down(map, head, goal, false, text_layout_details)
13285            })
13286        });
13287    }
13288
13289    pub fn context_menu_first(
13290        &mut self,
13291        _: &ContextMenuFirst,
13292        window: &mut Window,
13293        cx: &mut Context<Self>,
13294    ) {
13295        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13296            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13297        }
13298    }
13299
13300    pub fn context_menu_prev(
13301        &mut self,
13302        _: &ContextMenuPrevious,
13303        window: &mut Window,
13304        cx: &mut Context<Self>,
13305    ) {
13306        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13307            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13308        }
13309    }
13310
13311    pub fn context_menu_next(
13312        &mut self,
13313        _: &ContextMenuNext,
13314        window: &mut Window,
13315        cx: &mut Context<Self>,
13316    ) {
13317        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13318            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13319        }
13320    }
13321
13322    pub fn context_menu_last(
13323        &mut self,
13324        _: &ContextMenuLast,
13325        window: &mut Window,
13326        cx: &mut Context<Self>,
13327    ) {
13328        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13329            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13330        }
13331    }
13332
13333    pub fn signature_help_prev(
13334        &mut self,
13335        _: &SignatureHelpPrevious,
13336        _: &mut Window,
13337        cx: &mut Context<Self>,
13338    ) {
13339        if let Some(popover) = self.signature_help_state.popover_mut() {
13340            if popover.current_signature == 0 {
13341                popover.current_signature = popover.signatures.len() - 1;
13342            } else {
13343                popover.current_signature -= 1;
13344            }
13345            cx.notify();
13346        }
13347    }
13348
13349    pub fn signature_help_next(
13350        &mut self,
13351        _: &SignatureHelpNext,
13352        _: &mut Window,
13353        cx: &mut Context<Self>,
13354    ) {
13355        if let Some(popover) = self.signature_help_state.popover_mut() {
13356            if popover.current_signature + 1 == popover.signatures.len() {
13357                popover.current_signature = 0;
13358            } else {
13359                popover.current_signature += 1;
13360            }
13361            cx.notify();
13362        }
13363    }
13364
13365    pub fn move_to_previous_word_start(
13366        &mut self,
13367        _: &MoveToPreviousWordStart,
13368        window: &mut Window,
13369        cx: &mut Context<Self>,
13370    ) {
13371        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13372        self.change_selections(Default::default(), window, cx, |s| {
13373            s.move_cursors_with(|map, head, _| {
13374                (
13375                    movement::previous_word_start(map, head),
13376                    SelectionGoal::None,
13377                )
13378            });
13379        })
13380    }
13381
13382    pub fn move_to_previous_subword_start(
13383        &mut self,
13384        _: &MoveToPreviousSubwordStart,
13385        window: &mut Window,
13386        cx: &mut Context<Self>,
13387    ) {
13388        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13389        self.change_selections(Default::default(), window, cx, |s| {
13390            s.move_cursors_with(|map, head, _| {
13391                (
13392                    movement::previous_subword_start(map, head),
13393                    SelectionGoal::None,
13394                )
13395            });
13396        })
13397    }
13398
13399    pub fn select_to_previous_word_start(
13400        &mut self,
13401        _: &SelectToPreviousWordStart,
13402        window: &mut Window,
13403        cx: &mut Context<Self>,
13404    ) {
13405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13406        self.change_selections(Default::default(), window, cx, |s| {
13407            s.move_heads_with(|map, head, _| {
13408                (
13409                    movement::previous_word_start(map, head),
13410                    SelectionGoal::None,
13411                )
13412            });
13413        })
13414    }
13415
13416    pub fn select_to_previous_subword_start(
13417        &mut self,
13418        _: &SelectToPreviousSubwordStart,
13419        window: &mut Window,
13420        cx: &mut Context<Self>,
13421    ) {
13422        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13423        self.change_selections(Default::default(), window, cx, |s| {
13424            s.move_heads_with(|map, head, _| {
13425                (
13426                    movement::previous_subword_start(map, head),
13427                    SelectionGoal::None,
13428                )
13429            });
13430        })
13431    }
13432
13433    pub fn delete_to_previous_word_start(
13434        &mut self,
13435        action: &DeleteToPreviousWordStart,
13436        window: &mut Window,
13437        cx: &mut Context<Self>,
13438    ) {
13439        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13440        self.transact(window, cx, |this, window, cx| {
13441            this.select_autoclose_pair(window, cx);
13442            this.change_selections(Default::default(), window, cx, |s| {
13443                s.move_with(|map, selection| {
13444                    if selection.is_empty() {
13445                        let mut cursor = if action.ignore_newlines {
13446                            movement::previous_word_start(map, selection.head())
13447                        } else {
13448                            movement::previous_word_start_or_newline(map, selection.head())
13449                        };
13450                        cursor = movement::adjust_greedy_deletion(
13451                            map,
13452                            selection.head(),
13453                            cursor,
13454                            action.ignore_brackets,
13455                        );
13456                        selection.set_head(cursor, SelectionGoal::None);
13457                    }
13458                });
13459            });
13460            this.insert("", window, cx);
13461        });
13462    }
13463
13464    pub fn delete_to_previous_subword_start(
13465        &mut self,
13466        _: &DeleteToPreviousSubwordStart,
13467        window: &mut Window,
13468        cx: &mut Context<Self>,
13469    ) {
13470        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13471        self.transact(window, cx, |this, window, cx| {
13472            this.select_autoclose_pair(window, cx);
13473            this.change_selections(Default::default(), window, cx, |s| {
13474                s.move_with(|map, selection| {
13475                    if selection.is_empty() {
13476                        let mut cursor = movement::previous_subword_start(map, selection.head());
13477                        cursor =
13478                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13479                        selection.set_head(cursor, SelectionGoal::None);
13480                    }
13481                });
13482            });
13483            this.insert("", window, cx);
13484        });
13485    }
13486
13487    pub fn move_to_next_word_end(
13488        &mut self,
13489        _: &MoveToNextWordEnd,
13490        window: &mut Window,
13491        cx: &mut Context<Self>,
13492    ) {
13493        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13494        self.change_selections(Default::default(), window, cx, |s| {
13495            s.move_cursors_with(|map, head, _| {
13496                (movement::next_word_end(map, head), SelectionGoal::None)
13497            });
13498        })
13499    }
13500
13501    pub fn move_to_next_subword_end(
13502        &mut self,
13503        _: &MoveToNextSubwordEnd,
13504        window: &mut Window,
13505        cx: &mut Context<Self>,
13506    ) {
13507        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13508        self.change_selections(Default::default(), window, cx, |s| {
13509            s.move_cursors_with(|map, head, _| {
13510                (movement::next_subword_end(map, head), SelectionGoal::None)
13511            });
13512        })
13513    }
13514
13515    pub fn select_to_next_word_end(
13516        &mut self,
13517        _: &SelectToNextWordEnd,
13518        window: &mut Window,
13519        cx: &mut Context<Self>,
13520    ) {
13521        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13522        self.change_selections(Default::default(), window, cx, |s| {
13523            s.move_heads_with(|map, head, _| {
13524                (movement::next_word_end(map, head), SelectionGoal::None)
13525            });
13526        })
13527    }
13528
13529    pub fn select_to_next_subword_end(
13530        &mut self,
13531        _: &SelectToNextSubwordEnd,
13532        window: &mut Window,
13533        cx: &mut Context<Self>,
13534    ) {
13535        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13536        self.change_selections(Default::default(), window, cx, |s| {
13537            s.move_heads_with(|map, head, _| {
13538                (movement::next_subword_end(map, head), SelectionGoal::None)
13539            });
13540        })
13541    }
13542
13543    pub fn delete_to_next_word_end(
13544        &mut self,
13545        action: &DeleteToNextWordEnd,
13546        window: &mut Window,
13547        cx: &mut Context<Self>,
13548    ) {
13549        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13550        self.transact(window, cx, |this, window, cx| {
13551            this.change_selections(Default::default(), window, cx, |s| {
13552                s.move_with(|map, selection| {
13553                    if selection.is_empty() {
13554                        let mut cursor = if action.ignore_newlines {
13555                            movement::next_word_end(map, selection.head())
13556                        } else {
13557                            movement::next_word_end_or_newline(map, selection.head())
13558                        };
13559                        cursor = movement::adjust_greedy_deletion(
13560                            map,
13561                            selection.head(),
13562                            cursor,
13563                            action.ignore_brackets,
13564                        );
13565                        selection.set_head(cursor, SelectionGoal::None);
13566                    }
13567                });
13568            });
13569            this.insert("", window, cx);
13570        });
13571    }
13572
13573    pub fn delete_to_next_subword_end(
13574        &mut self,
13575        _: &DeleteToNextSubwordEnd,
13576        window: &mut Window,
13577        cx: &mut Context<Self>,
13578    ) {
13579        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13580        self.transact(window, cx, |this, window, cx| {
13581            this.change_selections(Default::default(), window, cx, |s| {
13582                s.move_with(|map, selection| {
13583                    if selection.is_empty() {
13584                        let mut cursor = movement::next_subword_end(map, selection.head());
13585                        cursor =
13586                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13587                        selection.set_head(cursor, SelectionGoal::None);
13588                    }
13589                });
13590            });
13591            this.insert("", window, cx);
13592        });
13593    }
13594
13595    pub fn move_to_beginning_of_line(
13596        &mut self,
13597        action: &MoveToBeginningOfLine,
13598        window: &mut Window,
13599        cx: &mut Context<Self>,
13600    ) {
13601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13602        self.change_selections(Default::default(), window, cx, |s| {
13603            s.move_cursors_with(|map, head, _| {
13604                (
13605                    movement::indented_line_beginning(
13606                        map,
13607                        head,
13608                        action.stop_at_soft_wraps,
13609                        action.stop_at_indent,
13610                    ),
13611                    SelectionGoal::None,
13612                )
13613            });
13614        })
13615    }
13616
13617    pub fn select_to_beginning_of_line(
13618        &mut self,
13619        action: &SelectToBeginningOfLine,
13620        window: &mut Window,
13621        cx: &mut Context<Self>,
13622    ) {
13623        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13624        self.change_selections(Default::default(), window, cx, |s| {
13625            s.move_heads_with(|map, head, _| {
13626                (
13627                    movement::indented_line_beginning(
13628                        map,
13629                        head,
13630                        action.stop_at_soft_wraps,
13631                        action.stop_at_indent,
13632                    ),
13633                    SelectionGoal::None,
13634                )
13635            });
13636        });
13637    }
13638
13639    pub fn delete_to_beginning_of_line(
13640        &mut self,
13641        action: &DeleteToBeginningOfLine,
13642        window: &mut Window,
13643        cx: &mut Context<Self>,
13644    ) {
13645        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13646        self.transact(window, cx, |this, window, cx| {
13647            this.change_selections(Default::default(), window, cx, |s| {
13648                s.move_with(|_, selection| {
13649                    selection.reversed = true;
13650                });
13651            });
13652
13653            this.select_to_beginning_of_line(
13654                &SelectToBeginningOfLine {
13655                    stop_at_soft_wraps: false,
13656                    stop_at_indent: action.stop_at_indent,
13657                },
13658                window,
13659                cx,
13660            );
13661            this.backspace(&Backspace, window, cx);
13662        });
13663    }
13664
13665    pub fn move_to_end_of_line(
13666        &mut self,
13667        action: &MoveToEndOfLine,
13668        window: &mut Window,
13669        cx: &mut Context<Self>,
13670    ) {
13671        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13672        self.change_selections(Default::default(), window, cx, |s| {
13673            s.move_cursors_with(|map, head, _| {
13674                (
13675                    movement::line_end(map, head, action.stop_at_soft_wraps),
13676                    SelectionGoal::None,
13677                )
13678            });
13679        })
13680    }
13681
13682    pub fn select_to_end_of_line(
13683        &mut self,
13684        action: &SelectToEndOfLine,
13685        window: &mut Window,
13686        cx: &mut Context<Self>,
13687    ) {
13688        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13689        self.change_selections(Default::default(), window, cx, |s| {
13690            s.move_heads_with(|map, head, _| {
13691                (
13692                    movement::line_end(map, head, action.stop_at_soft_wraps),
13693                    SelectionGoal::None,
13694                )
13695            });
13696        })
13697    }
13698
13699    pub fn delete_to_end_of_line(
13700        &mut self,
13701        _: &DeleteToEndOfLine,
13702        window: &mut Window,
13703        cx: &mut Context<Self>,
13704    ) {
13705        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13706        self.transact(window, cx, |this, window, cx| {
13707            this.select_to_end_of_line(
13708                &SelectToEndOfLine {
13709                    stop_at_soft_wraps: false,
13710                },
13711                window,
13712                cx,
13713            );
13714            this.delete(&Delete, window, cx);
13715        });
13716    }
13717
13718    pub fn cut_to_end_of_line(
13719        &mut self,
13720        action: &CutToEndOfLine,
13721        window: &mut Window,
13722        cx: &mut Context<Self>,
13723    ) {
13724        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13725        self.transact(window, cx, |this, window, cx| {
13726            this.select_to_end_of_line(
13727                &SelectToEndOfLine {
13728                    stop_at_soft_wraps: false,
13729                },
13730                window,
13731                cx,
13732            );
13733            if !action.stop_at_newlines {
13734                this.change_selections(Default::default(), window, cx, |s| {
13735                    s.move_with(|_, sel| {
13736                        if sel.is_empty() {
13737                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13738                        }
13739                    });
13740                });
13741            }
13742            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13743            let item = this.cut_common(false, window, cx);
13744            cx.write_to_clipboard(item);
13745        });
13746    }
13747
13748    pub fn move_to_start_of_paragraph(
13749        &mut self,
13750        _: &MoveToStartOfParagraph,
13751        window: &mut Window,
13752        cx: &mut Context<Self>,
13753    ) {
13754        if matches!(self.mode, EditorMode::SingleLine) {
13755            cx.propagate();
13756            return;
13757        }
13758        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13759        self.change_selections(Default::default(), window, cx, |s| {
13760            s.move_with(|map, selection| {
13761                selection.collapse_to(
13762                    movement::start_of_paragraph(map, selection.head(), 1),
13763                    SelectionGoal::None,
13764                )
13765            });
13766        })
13767    }
13768
13769    pub fn move_to_end_of_paragraph(
13770        &mut self,
13771        _: &MoveToEndOfParagraph,
13772        window: &mut Window,
13773        cx: &mut Context<Self>,
13774    ) {
13775        if matches!(self.mode, EditorMode::SingleLine) {
13776            cx.propagate();
13777            return;
13778        }
13779        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13780        self.change_selections(Default::default(), window, cx, |s| {
13781            s.move_with(|map, selection| {
13782                selection.collapse_to(
13783                    movement::end_of_paragraph(map, selection.head(), 1),
13784                    SelectionGoal::None,
13785                )
13786            });
13787        })
13788    }
13789
13790    pub fn select_to_start_of_paragraph(
13791        &mut self,
13792        _: &SelectToStartOfParagraph,
13793        window: &mut Window,
13794        cx: &mut Context<Self>,
13795    ) {
13796        if matches!(self.mode, EditorMode::SingleLine) {
13797            cx.propagate();
13798            return;
13799        }
13800        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13801        self.change_selections(Default::default(), window, cx, |s| {
13802            s.move_heads_with(|map, head, _| {
13803                (
13804                    movement::start_of_paragraph(map, head, 1),
13805                    SelectionGoal::None,
13806                )
13807            });
13808        })
13809    }
13810
13811    pub fn select_to_end_of_paragraph(
13812        &mut self,
13813        _: &SelectToEndOfParagraph,
13814        window: &mut Window,
13815        cx: &mut Context<Self>,
13816    ) {
13817        if matches!(self.mode, EditorMode::SingleLine) {
13818            cx.propagate();
13819            return;
13820        }
13821        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13822        self.change_selections(Default::default(), window, cx, |s| {
13823            s.move_heads_with(|map, head, _| {
13824                (
13825                    movement::end_of_paragraph(map, head, 1),
13826                    SelectionGoal::None,
13827                )
13828            });
13829        })
13830    }
13831
13832    pub fn move_to_start_of_excerpt(
13833        &mut self,
13834        _: &MoveToStartOfExcerpt,
13835        window: &mut Window,
13836        cx: &mut Context<Self>,
13837    ) {
13838        if matches!(self.mode, EditorMode::SingleLine) {
13839            cx.propagate();
13840            return;
13841        }
13842        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13843        self.change_selections(Default::default(), window, cx, |s| {
13844            s.move_with(|map, selection| {
13845                selection.collapse_to(
13846                    movement::start_of_excerpt(
13847                        map,
13848                        selection.head(),
13849                        workspace::searchable::Direction::Prev,
13850                    ),
13851                    SelectionGoal::None,
13852                )
13853            });
13854        })
13855    }
13856
13857    pub fn move_to_start_of_next_excerpt(
13858        &mut self,
13859        _: &MoveToStartOfNextExcerpt,
13860        window: &mut Window,
13861        cx: &mut Context<Self>,
13862    ) {
13863        if matches!(self.mode, EditorMode::SingleLine) {
13864            cx.propagate();
13865            return;
13866        }
13867
13868        self.change_selections(Default::default(), window, cx, |s| {
13869            s.move_with(|map, selection| {
13870                selection.collapse_to(
13871                    movement::start_of_excerpt(
13872                        map,
13873                        selection.head(),
13874                        workspace::searchable::Direction::Next,
13875                    ),
13876                    SelectionGoal::None,
13877                )
13878            });
13879        })
13880    }
13881
13882    pub fn move_to_end_of_excerpt(
13883        &mut self,
13884        _: &MoveToEndOfExcerpt,
13885        window: &mut Window,
13886        cx: &mut Context<Self>,
13887    ) {
13888        if matches!(self.mode, EditorMode::SingleLine) {
13889            cx.propagate();
13890            return;
13891        }
13892        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13893        self.change_selections(Default::default(), window, cx, |s| {
13894            s.move_with(|map, selection| {
13895                selection.collapse_to(
13896                    movement::end_of_excerpt(
13897                        map,
13898                        selection.head(),
13899                        workspace::searchable::Direction::Next,
13900                    ),
13901                    SelectionGoal::None,
13902                )
13903            });
13904        })
13905    }
13906
13907    pub fn move_to_end_of_previous_excerpt(
13908        &mut self,
13909        _: &MoveToEndOfPreviousExcerpt,
13910        window: &mut Window,
13911        cx: &mut Context<Self>,
13912    ) {
13913        if matches!(self.mode, EditorMode::SingleLine) {
13914            cx.propagate();
13915            return;
13916        }
13917        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13918        self.change_selections(Default::default(), window, cx, |s| {
13919            s.move_with(|map, selection| {
13920                selection.collapse_to(
13921                    movement::end_of_excerpt(
13922                        map,
13923                        selection.head(),
13924                        workspace::searchable::Direction::Prev,
13925                    ),
13926                    SelectionGoal::None,
13927                )
13928            });
13929        })
13930    }
13931
13932    pub fn select_to_start_of_excerpt(
13933        &mut self,
13934        _: &SelectToStartOfExcerpt,
13935        window: &mut Window,
13936        cx: &mut Context<Self>,
13937    ) {
13938        if matches!(self.mode, EditorMode::SingleLine) {
13939            cx.propagate();
13940            return;
13941        }
13942        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13943        self.change_selections(Default::default(), window, cx, |s| {
13944            s.move_heads_with(|map, head, _| {
13945                (
13946                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13947                    SelectionGoal::None,
13948                )
13949            });
13950        })
13951    }
13952
13953    pub fn select_to_start_of_next_excerpt(
13954        &mut self,
13955        _: &SelectToStartOfNextExcerpt,
13956        window: &mut Window,
13957        cx: &mut Context<Self>,
13958    ) {
13959        if matches!(self.mode, EditorMode::SingleLine) {
13960            cx.propagate();
13961            return;
13962        }
13963        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13964        self.change_selections(Default::default(), window, cx, |s| {
13965            s.move_heads_with(|map, head, _| {
13966                (
13967                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13968                    SelectionGoal::None,
13969                )
13970            });
13971        })
13972    }
13973
13974    pub fn select_to_end_of_excerpt(
13975        &mut self,
13976        _: &SelectToEndOfExcerpt,
13977        window: &mut Window,
13978        cx: &mut Context<Self>,
13979    ) {
13980        if matches!(self.mode, EditorMode::SingleLine) {
13981            cx.propagate();
13982            return;
13983        }
13984        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13985        self.change_selections(Default::default(), window, cx, |s| {
13986            s.move_heads_with(|map, head, _| {
13987                (
13988                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13989                    SelectionGoal::None,
13990                )
13991            });
13992        })
13993    }
13994
13995    pub fn select_to_end_of_previous_excerpt(
13996        &mut self,
13997        _: &SelectToEndOfPreviousExcerpt,
13998        window: &mut Window,
13999        cx: &mut Context<Self>,
14000    ) {
14001        if matches!(self.mode, EditorMode::SingleLine) {
14002            cx.propagate();
14003            return;
14004        }
14005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14006        self.change_selections(Default::default(), window, cx, |s| {
14007            s.move_heads_with(|map, head, _| {
14008                (
14009                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14010                    SelectionGoal::None,
14011                )
14012            });
14013        })
14014    }
14015
14016    pub fn move_to_beginning(
14017        &mut self,
14018        _: &MoveToBeginning,
14019        window: &mut Window,
14020        cx: &mut Context<Self>,
14021    ) {
14022        if matches!(self.mode, EditorMode::SingleLine) {
14023            cx.propagate();
14024            return;
14025        }
14026        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14027        self.change_selections(Default::default(), window, cx, |s| {
14028            s.select_ranges(vec![0..0]);
14029        });
14030    }
14031
14032    pub fn select_to_beginning(
14033        &mut self,
14034        _: &SelectToBeginning,
14035        window: &mut Window,
14036        cx: &mut Context<Self>,
14037    ) {
14038        let mut selection = self.selections.last::<Point>(cx);
14039        selection.set_head(Point::zero(), SelectionGoal::None);
14040        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14041        self.change_selections(Default::default(), window, cx, |s| {
14042            s.select(vec![selection]);
14043        });
14044    }
14045
14046    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14047        if matches!(self.mode, EditorMode::SingleLine) {
14048            cx.propagate();
14049            return;
14050        }
14051        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14052        let cursor = self.buffer.read(cx).read(cx).len();
14053        self.change_selections(Default::default(), window, cx, |s| {
14054            s.select_ranges(vec![cursor..cursor])
14055        });
14056    }
14057
14058    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14059        self.nav_history = nav_history;
14060    }
14061
14062    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14063        self.nav_history.as_ref()
14064    }
14065
14066    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14067        self.push_to_nav_history(
14068            self.selections.newest_anchor().head(),
14069            None,
14070            false,
14071            true,
14072            cx,
14073        );
14074    }
14075
14076    fn push_to_nav_history(
14077        &mut self,
14078        cursor_anchor: Anchor,
14079        new_position: Option<Point>,
14080        is_deactivate: bool,
14081        always: bool,
14082        cx: &mut Context<Self>,
14083    ) {
14084        if let Some(nav_history) = self.nav_history.as_mut() {
14085            let buffer = self.buffer.read(cx).read(cx);
14086            let cursor_position = cursor_anchor.to_point(&buffer);
14087            let scroll_state = self.scroll_manager.anchor();
14088            let scroll_top_row = scroll_state.top_row(&buffer);
14089            drop(buffer);
14090
14091            if let Some(new_position) = new_position {
14092                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14093                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14094                    return;
14095                }
14096            }
14097
14098            nav_history.push(
14099                Some(NavigationData {
14100                    cursor_anchor,
14101                    cursor_position,
14102                    scroll_anchor: scroll_state,
14103                    scroll_top_row,
14104                }),
14105                cx,
14106            );
14107            cx.emit(EditorEvent::PushedToNavHistory {
14108                anchor: cursor_anchor,
14109                is_deactivate,
14110            })
14111        }
14112    }
14113
14114    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14115        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14116        let buffer = self.buffer.read(cx).snapshot(cx);
14117        let mut selection = self.selections.first::<usize>(cx);
14118        selection.set_head(buffer.len(), SelectionGoal::None);
14119        self.change_selections(Default::default(), window, cx, |s| {
14120            s.select(vec![selection]);
14121        });
14122    }
14123
14124    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14125        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14126        let end = self.buffer.read(cx).read(cx).len();
14127        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14128            s.select_ranges(vec![0..end]);
14129        });
14130    }
14131
14132    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14133        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14134        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14135        let mut selections = self.selections.all::<Point>(cx);
14136        let max_point = display_map.buffer_snapshot().max_point();
14137        for selection in &mut selections {
14138            let rows = selection.spanned_rows(true, &display_map);
14139            selection.start = Point::new(rows.start.0, 0);
14140            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14141            selection.reversed = false;
14142        }
14143        self.change_selections(Default::default(), window, cx, |s| {
14144            s.select(selections);
14145        });
14146    }
14147
14148    pub fn split_selection_into_lines(
14149        &mut self,
14150        action: &SplitSelectionIntoLines,
14151        window: &mut Window,
14152        cx: &mut Context<Self>,
14153    ) {
14154        let selections = self
14155            .selections
14156            .all::<Point>(cx)
14157            .into_iter()
14158            .map(|selection| selection.start..selection.end)
14159            .collect::<Vec<_>>();
14160        self.unfold_ranges(&selections, true, true, cx);
14161
14162        let mut new_selection_ranges = Vec::new();
14163        {
14164            let buffer = self.buffer.read(cx).read(cx);
14165            for selection in selections {
14166                for row in selection.start.row..selection.end.row {
14167                    let line_start = Point::new(row, 0);
14168                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14169
14170                    if action.keep_selections {
14171                        // Keep the selection range for each line
14172                        let selection_start = if row == selection.start.row {
14173                            selection.start
14174                        } else {
14175                            line_start
14176                        };
14177                        new_selection_ranges.push(selection_start..line_end);
14178                    } else {
14179                        // Collapse to cursor at end of line
14180                        new_selection_ranges.push(line_end..line_end);
14181                    }
14182                }
14183
14184                let is_multiline_selection = selection.start.row != selection.end.row;
14185                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14186                // so this action feels more ergonomic when paired with other selection operations
14187                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14188                if !should_skip_last {
14189                    if action.keep_selections {
14190                        if is_multiline_selection {
14191                            let line_start = Point::new(selection.end.row, 0);
14192                            new_selection_ranges.push(line_start..selection.end);
14193                        } else {
14194                            new_selection_ranges.push(selection.start..selection.end);
14195                        }
14196                    } else {
14197                        new_selection_ranges.push(selection.end..selection.end);
14198                    }
14199                }
14200            }
14201        }
14202        self.change_selections(Default::default(), window, cx, |s| {
14203            s.select_ranges(new_selection_ranges);
14204        });
14205    }
14206
14207    pub fn add_selection_above(
14208        &mut self,
14209        _: &AddSelectionAbove,
14210        window: &mut Window,
14211        cx: &mut Context<Self>,
14212    ) {
14213        self.add_selection(true, window, cx);
14214    }
14215
14216    pub fn add_selection_below(
14217        &mut self,
14218        _: &AddSelectionBelow,
14219        window: &mut Window,
14220        cx: &mut Context<Self>,
14221    ) {
14222        self.add_selection(false, window, cx);
14223    }
14224
14225    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14226        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14227
14228        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14229        let all_selections = self.selections.all::<Point>(cx);
14230        let text_layout_details = self.text_layout_details(window);
14231
14232        let (mut columnar_selections, new_selections_to_columnarize) = {
14233            if let Some(state) = self.add_selections_state.as_ref() {
14234                let columnar_selection_ids: HashSet<_> = state
14235                    .groups
14236                    .iter()
14237                    .flat_map(|group| group.stack.iter())
14238                    .copied()
14239                    .collect();
14240
14241                all_selections
14242                    .into_iter()
14243                    .partition(|s| columnar_selection_ids.contains(&s.id))
14244            } else {
14245                (Vec::new(), all_selections)
14246            }
14247        };
14248
14249        let mut state = self
14250            .add_selections_state
14251            .take()
14252            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14253
14254        for selection in new_selections_to_columnarize {
14255            let range = selection.display_range(&display_map).sorted();
14256            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14257            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14258            let positions = start_x.min(end_x)..start_x.max(end_x);
14259            let mut stack = Vec::new();
14260            for row in range.start.row().0..=range.end.row().0 {
14261                if let Some(selection) = self.selections.build_columnar_selection(
14262                    &display_map,
14263                    DisplayRow(row),
14264                    &positions,
14265                    selection.reversed,
14266                    &text_layout_details,
14267                ) {
14268                    stack.push(selection.id);
14269                    columnar_selections.push(selection);
14270                }
14271            }
14272            if !stack.is_empty() {
14273                if above {
14274                    stack.reverse();
14275                }
14276                state.groups.push(AddSelectionsGroup { above, stack });
14277            }
14278        }
14279
14280        let mut final_selections = Vec::new();
14281        let end_row = if above {
14282            DisplayRow(0)
14283        } else {
14284            display_map.max_point().row()
14285        };
14286
14287        let mut last_added_item_per_group = HashMap::default();
14288        for group in state.groups.iter_mut() {
14289            if let Some(last_id) = group.stack.last() {
14290                last_added_item_per_group.insert(*last_id, group);
14291            }
14292        }
14293
14294        for selection in columnar_selections {
14295            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14296                if above == group.above {
14297                    let range = selection.display_range(&display_map).sorted();
14298                    debug_assert_eq!(range.start.row(), range.end.row());
14299                    let mut row = range.start.row();
14300                    let positions =
14301                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14302                            Pixels::from(start)..Pixels::from(end)
14303                        } else {
14304                            let start_x =
14305                                display_map.x_for_display_point(range.start, &text_layout_details);
14306                            let end_x =
14307                                display_map.x_for_display_point(range.end, &text_layout_details);
14308                            start_x.min(end_x)..start_x.max(end_x)
14309                        };
14310
14311                    let mut maybe_new_selection = None;
14312                    while row != end_row {
14313                        if above {
14314                            row.0 -= 1;
14315                        } else {
14316                            row.0 += 1;
14317                        }
14318                        if let Some(new_selection) = self.selections.build_columnar_selection(
14319                            &display_map,
14320                            row,
14321                            &positions,
14322                            selection.reversed,
14323                            &text_layout_details,
14324                        ) {
14325                            maybe_new_selection = Some(new_selection);
14326                            break;
14327                        }
14328                    }
14329
14330                    if let Some(new_selection) = maybe_new_selection {
14331                        group.stack.push(new_selection.id);
14332                        if above {
14333                            final_selections.push(new_selection);
14334                            final_selections.push(selection);
14335                        } else {
14336                            final_selections.push(selection);
14337                            final_selections.push(new_selection);
14338                        }
14339                    } else {
14340                        final_selections.push(selection);
14341                    }
14342                } else {
14343                    group.stack.pop();
14344                }
14345            } else {
14346                final_selections.push(selection);
14347            }
14348        }
14349
14350        self.change_selections(Default::default(), window, cx, |s| {
14351            s.select(final_selections);
14352        });
14353
14354        let final_selection_ids: HashSet<_> = self
14355            .selections
14356            .all::<Point>(cx)
14357            .iter()
14358            .map(|s| s.id)
14359            .collect();
14360        state.groups.retain_mut(|group| {
14361            // selections might get merged above so we remove invalid items from stacks
14362            group.stack.retain(|id| final_selection_ids.contains(id));
14363
14364            // single selection in stack can be treated as initial state
14365            group.stack.len() > 1
14366        });
14367
14368        if !state.groups.is_empty() {
14369            self.add_selections_state = Some(state);
14370        }
14371    }
14372
14373    fn select_match_ranges(
14374        &mut self,
14375        range: Range<usize>,
14376        reversed: bool,
14377        replace_newest: bool,
14378        auto_scroll: Option<Autoscroll>,
14379        window: &mut Window,
14380        cx: &mut Context<Editor>,
14381    ) {
14382        self.unfold_ranges(
14383            std::slice::from_ref(&range),
14384            false,
14385            auto_scroll.is_some(),
14386            cx,
14387        );
14388        let effects = if let Some(scroll) = auto_scroll {
14389            SelectionEffects::scroll(scroll)
14390        } else {
14391            SelectionEffects::no_scroll()
14392        };
14393        self.change_selections(effects, window, cx, |s| {
14394            if replace_newest {
14395                s.delete(s.newest_anchor().id);
14396            }
14397            if reversed {
14398                s.insert_range(range.end..range.start);
14399            } else {
14400                s.insert_range(range);
14401            }
14402        });
14403    }
14404
14405    pub fn select_next_match_internal(
14406        &mut self,
14407        display_map: &DisplaySnapshot,
14408        replace_newest: bool,
14409        autoscroll: Option<Autoscroll>,
14410        window: &mut Window,
14411        cx: &mut Context<Self>,
14412    ) -> Result<()> {
14413        let buffer = display_map.buffer_snapshot();
14414        let mut selections = self.selections.all::<usize>(cx);
14415        if let Some(mut select_next_state) = self.select_next_state.take() {
14416            let query = &select_next_state.query;
14417            if !select_next_state.done {
14418                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14419                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14420                let mut next_selected_range = None;
14421
14422                let bytes_after_last_selection =
14423                    buffer.bytes_in_range(last_selection.end..buffer.len());
14424                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14425                let query_matches = query
14426                    .stream_find_iter(bytes_after_last_selection)
14427                    .map(|result| (last_selection.end, result))
14428                    .chain(
14429                        query
14430                            .stream_find_iter(bytes_before_first_selection)
14431                            .map(|result| (0, result)),
14432                    );
14433
14434                for (start_offset, query_match) in query_matches {
14435                    let query_match = query_match.unwrap(); // can only fail due to I/O
14436                    let offset_range =
14437                        start_offset + query_match.start()..start_offset + query_match.end();
14438
14439                    if !select_next_state.wordwise
14440                        || (!buffer.is_inside_word(offset_range.start, None)
14441                            && !buffer.is_inside_word(offset_range.end, None))
14442                    {
14443                        // TODO: This is n^2, because we might check all the selections
14444                        if !selections
14445                            .iter()
14446                            .any(|selection| selection.range().overlaps(&offset_range))
14447                        {
14448                            next_selected_range = Some(offset_range);
14449                            break;
14450                        }
14451                    }
14452                }
14453
14454                if let Some(next_selected_range) = next_selected_range {
14455                    self.select_match_ranges(
14456                        next_selected_range,
14457                        last_selection.reversed,
14458                        replace_newest,
14459                        autoscroll,
14460                        window,
14461                        cx,
14462                    );
14463                } else {
14464                    select_next_state.done = true;
14465                }
14466            }
14467
14468            self.select_next_state = Some(select_next_state);
14469        } else {
14470            let mut only_carets = true;
14471            let mut same_text_selected = true;
14472            let mut selected_text = None;
14473
14474            let mut selections_iter = selections.iter().peekable();
14475            while let Some(selection) = selections_iter.next() {
14476                if selection.start != selection.end {
14477                    only_carets = false;
14478                }
14479
14480                if same_text_selected {
14481                    if selected_text.is_none() {
14482                        selected_text =
14483                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14484                    }
14485
14486                    if let Some(next_selection) = selections_iter.peek() {
14487                        if next_selection.range().len() == selection.range().len() {
14488                            let next_selected_text = buffer
14489                                .text_for_range(next_selection.range())
14490                                .collect::<String>();
14491                            if Some(next_selected_text) != selected_text {
14492                                same_text_selected = false;
14493                                selected_text = None;
14494                            }
14495                        } else {
14496                            same_text_selected = false;
14497                            selected_text = None;
14498                        }
14499                    }
14500                }
14501            }
14502
14503            if only_carets {
14504                for selection in &mut selections {
14505                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14506                    selection.start = word_range.start;
14507                    selection.end = word_range.end;
14508                    selection.goal = SelectionGoal::None;
14509                    selection.reversed = false;
14510                    self.select_match_ranges(
14511                        selection.start..selection.end,
14512                        selection.reversed,
14513                        replace_newest,
14514                        autoscroll,
14515                        window,
14516                        cx,
14517                    );
14518                }
14519
14520                if selections.len() == 1 {
14521                    let selection = selections
14522                        .last()
14523                        .expect("ensured that there's only one selection");
14524                    let query = buffer
14525                        .text_for_range(selection.start..selection.end)
14526                        .collect::<String>();
14527                    let is_empty = query.is_empty();
14528                    let select_state = SelectNextState {
14529                        query: AhoCorasick::new(&[query])?,
14530                        wordwise: true,
14531                        done: is_empty,
14532                    };
14533                    self.select_next_state = Some(select_state);
14534                } else {
14535                    self.select_next_state = None;
14536                }
14537            } else if let Some(selected_text) = selected_text {
14538                self.select_next_state = Some(SelectNextState {
14539                    query: AhoCorasick::new(&[selected_text])?,
14540                    wordwise: false,
14541                    done: false,
14542                });
14543                self.select_next_match_internal(
14544                    display_map,
14545                    replace_newest,
14546                    autoscroll,
14547                    window,
14548                    cx,
14549                )?;
14550            }
14551        }
14552        Ok(())
14553    }
14554
14555    pub fn select_all_matches(
14556        &mut self,
14557        _action: &SelectAllMatches,
14558        window: &mut Window,
14559        cx: &mut Context<Self>,
14560    ) -> Result<()> {
14561        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14562
14563        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14564
14565        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14566        let Some(select_next_state) = self.select_next_state.as_mut() else {
14567            return Ok(());
14568        };
14569        if select_next_state.done {
14570            return Ok(());
14571        }
14572
14573        let mut new_selections = Vec::new();
14574
14575        let reversed = self.selections.oldest::<usize>(cx).reversed;
14576        let buffer = display_map.buffer_snapshot();
14577        let query_matches = select_next_state
14578            .query
14579            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14580
14581        for query_match in query_matches.into_iter() {
14582            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14583            let offset_range = if reversed {
14584                query_match.end()..query_match.start()
14585            } else {
14586                query_match.start()..query_match.end()
14587            };
14588
14589            if !select_next_state.wordwise
14590                || (!buffer.is_inside_word(offset_range.start, None)
14591                    && !buffer.is_inside_word(offset_range.end, None))
14592            {
14593                new_selections.push(offset_range.start..offset_range.end);
14594            }
14595        }
14596
14597        select_next_state.done = true;
14598
14599        if new_selections.is_empty() {
14600            log::error!("bug: new_selections is empty in select_all_matches");
14601            return Ok(());
14602        }
14603
14604        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14605        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14606            selections.select_ranges(new_selections)
14607        });
14608
14609        Ok(())
14610    }
14611
14612    pub fn select_next(
14613        &mut self,
14614        action: &SelectNext,
14615        window: &mut Window,
14616        cx: &mut Context<Self>,
14617    ) -> Result<()> {
14618        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14619        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14620        self.select_next_match_internal(
14621            &display_map,
14622            action.replace_newest,
14623            Some(Autoscroll::newest()),
14624            window,
14625            cx,
14626        )?;
14627        Ok(())
14628    }
14629
14630    pub fn select_previous(
14631        &mut self,
14632        action: &SelectPrevious,
14633        window: &mut Window,
14634        cx: &mut Context<Self>,
14635    ) -> Result<()> {
14636        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14637        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14638        let buffer = display_map.buffer_snapshot();
14639        let mut selections = self.selections.all::<usize>(cx);
14640        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14641            let query = &select_prev_state.query;
14642            if !select_prev_state.done {
14643                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14644                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14645                let mut next_selected_range = None;
14646                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14647                let bytes_before_last_selection =
14648                    buffer.reversed_bytes_in_range(0..last_selection.start);
14649                let bytes_after_first_selection =
14650                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14651                let query_matches = query
14652                    .stream_find_iter(bytes_before_last_selection)
14653                    .map(|result| (last_selection.start, result))
14654                    .chain(
14655                        query
14656                            .stream_find_iter(bytes_after_first_selection)
14657                            .map(|result| (buffer.len(), result)),
14658                    );
14659                for (end_offset, query_match) in query_matches {
14660                    let query_match = query_match.unwrap(); // can only fail due to I/O
14661                    let offset_range =
14662                        end_offset - query_match.end()..end_offset - query_match.start();
14663
14664                    if !select_prev_state.wordwise
14665                        || (!buffer.is_inside_word(offset_range.start, None)
14666                            && !buffer.is_inside_word(offset_range.end, None))
14667                    {
14668                        next_selected_range = Some(offset_range);
14669                        break;
14670                    }
14671                }
14672
14673                if let Some(next_selected_range) = next_selected_range {
14674                    self.select_match_ranges(
14675                        next_selected_range,
14676                        last_selection.reversed,
14677                        action.replace_newest,
14678                        Some(Autoscroll::newest()),
14679                        window,
14680                        cx,
14681                    );
14682                } else {
14683                    select_prev_state.done = true;
14684                }
14685            }
14686
14687            self.select_prev_state = Some(select_prev_state);
14688        } else {
14689            let mut only_carets = true;
14690            let mut same_text_selected = true;
14691            let mut selected_text = None;
14692
14693            let mut selections_iter = selections.iter().peekable();
14694            while let Some(selection) = selections_iter.next() {
14695                if selection.start != selection.end {
14696                    only_carets = false;
14697                }
14698
14699                if same_text_selected {
14700                    if selected_text.is_none() {
14701                        selected_text =
14702                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14703                    }
14704
14705                    if let Some(next_selection) = selections_iter.peek() {
14706                        if next_selection.range().len() == selection.range().len() {
14707                            let next_selected_text = buffer
14708                                .text_for_range(next_selection.range())
14709                                .collect::<String>();
14710                            if Some(next_selected_text) != selected_text {
14711                                same_text_selected = false;
14712                                selected_text = None;
14713                            }
14714                        } else {
14715                            same_text_selected = false;
14716                            selected_text = None;
14717                        }
14718                    }
14719                }
14720            }
14721
14722            if only_carets {
14723                for selection in &mut selections {
14724                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14725                    selection.start = word_range.start;
14726                    selection.end = word_range.end;
14727                    selection.goal = SelectionGoal::None;
14728                    selection.reversed = false;
14729                    self.select_match_ranges(
14730                        selection.start..selection.end,
14731                        selection.reversed,
14732                        action.replace_newest,
14733                        Some(Autoscroll::newest()),
14734                        window,
14735                        cx,
14736                    );
14737                }
14738                if selections.len() == 1 {
14739                    let selection = selections
14740                        .last()
14741                        .expect("ensured that there's only one selection");
14742                    let query = buffer
14743                        .text_for_range(selection.start..selection.end)
14744                        .collect::<String>();
14745                    let is_empty = query.is_empty();
14746                    let select_state = SelectNextState {
14747                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14748                        wordwise: true,
14749                        done: is_empty,
14750                    };
14751                    self.select_prev_state = Some(select_state);
14752                } else {
14753                    self.select_prev_state = None;
14754                }
14755            } else if let Some(selected_text) = selected_text {
14756                self.select_prev_state = Some(SelectNextState {
14757                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14758                    wordwise: false,
14759                    done: false,
14760                });
14761                self.select_previous(action, window, cx)?;
14762            }
14763        }
14764        Ok(())
14765    }
14766
14767    pub fn find_next_match(
14768        &mut self,
14769        _: &FindNextMatch,
14770        window: &mut Window,
14771        cx: &mut Context<Self>,
14772    ) -> Result<()> {
14773        let selections = self.selections.disjoint_anchors_arc();
14774        match selections.first() {
14775            Some(first) if selections.len() >= 2 => {
14776                self.change_selections(Default::default(), window, cx, |s| {
14777                    s.select_ranges([first.range()]);
14778                });
14779            }
14780            _ => self.select_next(
14781                &SelectNext {
14782                    replace_newest: true,
14783                },
14784                window,
14785                cx,
14786            )?,
14787        }
14788        Ok(())
14789    }
14790
14791    pub fn find_previous_match(
14792        &mut self,
14793        _: &FindPreviousMatch,
14794        window: &mut Window,
14795        cx: &mut Context<Self>,
14796    ) -> Result<()> {
14797        let selections = self.selections.disjoint_anchors_arc();
14798        match selections.last() {
14799            Some(last) if selections.len() >= 2 => {
14800                self.change_selections(Default::default(), window, cx, |s| {
14801                    s.select_ranges([last.range()]);
14802                });
14803            }
14804            _ => self.select_previous(
14805                &SelectPrevious {
14806                    replace_newest: true,
14807                },
14808                window,
14809                cx,
14810            )?,
14811        }
14812        Ok(())
14813    }
14814
14815    pub fn toggle_comments(
14816        &mut self,
14817        action: &ToggleComments,
14818        window: &mut Window,
14819        cx: &mut Context<Self>,
14820    ) {
14821        if self.read_only(cx) {
14822            return;
14823        }
14824        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14825        let text_layout_details = &self.text_layout_details(window);
14826        self.transact(window, cx, |this, window, cx| {
14827            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14828            let mut edits = Vec::new();
14829            let mut selection_edit_ranges = Vec::new();
14830            let mut last_toggled_row = None;
14831            let snapshot = this.buffer.read(cx).read(cx);
14832            let empty_str: Arc<str> = Arc::default();
14833            let mut suffixes_inserted = Vec::new();
14834            let ignore_indent = action.ignore_indent;
14835
14836            fn comment_prefix_range(
14837                snapshot: &MultiBufferSnapshot,
14838                row: MultiBufferRow,
14839                comment_prefix: &str,
14840                comment_prefix_whitespace: &str,
14841                ignore_indent: bool,
14842            ) -> Range<Point> {
14843                let indent_size = if ignore_indent {
14844                    0
14845                } else {
14846                    snapshot.indent_size_for_line(row).len
14847                };
14848
14849                let start = Point::new(row.0, indent_size);
14850
14851                let mut line_bytes = snapshot
14852                    .bytes_in_range(start..snapshot.max_point())
14853                    .flatten()
14854                    .copied();
14855
14856                // If this line currently begins with the line comment prefix, then record
14857                // the range containing the prefix.
14858                if line_bytes
14859                    .by_ref()
14860                    .take(comment_prefix.len())
14861                    .eq(comment_prefix.bytes())
14862                {
14863                    // Include any whitespace that matches the comment prefix.
14864                    let matching_whitespace_len = line_bytes
14865                        .zip(comment_prefix_whitespace.bytes())
14866                        .take_while(|(a, b)| a == b)
14867                        .count() as u32;
14868                    let end = Point::new(
14869                        start.row,
14870                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14871                    );
14872                    start..end
14873                } else {
14874                    start..start
14875                }
14876            }
14877
14878            fn comment_suffix_range(
14879                snapshot: &MultiBufferSnapshot,
14880                row: MultiBufferRow,
14881                comment_suffix: &str,
14882                comment_suffix_has_leading_space: bool,
14883            ) -> Range<Point> {
14884                let end = Point::new(row.0, snapshot.line_len(row));
14885                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14886
14887                let mut line_end_bytes = snapshot
14888                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14889                    .flatten()
14890                    .copied();
14891
14892                let leading_space_len = if suffix_start_column > 0
14893                    && line_end_bytes.next() == Some(b' ')
14894                    && comment_suffix_has_leading_space
14895                {
14896                    1
14897                } else {
14898                    0
14899                };
14900
14901                // If this line currently begins with the line comment prefix, then record
14902                // the range containing the prefix.
14903                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14904                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14905                    start..end
14906                } else {
14907                    end..end
14908                }
14909            }
14910
14911            // TODO: Handle selections that cross excerpts
14912            for selection in &mut selections {
14913                let start_column = snapshot
14914                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14915                    .len;
14916                let language = if let Some(language) =
14917                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14918                {
14919                    language
14920                } else {
14921                    continue;
14922                };
14923
14924                selection_edit_ranges.clear();
14925
14926                // If multiple selections contain a given row, avoid processing that
14927                // row more than once.
14928                let mut start_row = MultiBufferRow(selection.start.row);
14929                if last_toggled_row == Some(start_row) {
14930                    start_row = start_row.next_row();
14931                }
14932                let end_row =
14933                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14934                        MultiBufferRow(selection.end.row - 1)
14935                    } else {
14936                        MultiBufferRow(selection.end.row)
14937                    };
14938                last_toggled_row = Some(end_row);
14939
14940                if start_row > end_row {
14941                    continue;
14942                }
14943
14944                // If the language has line comments, toggle those.
14945                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14946
14947                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14948                if ignore_indent {
14949                    full_comment_prefixes = full_comment_prefixes
14950                        .into_iter()
14951                        .map(|s| Arc::from(s.trim_end()))
14952                        .collect();
14953                }
14954
14955                if !full_comment_prefixes.is_empty() {
14956                    let first_prefix = full_comment_prefixes
14957                        .first()
14958                        .expect("prefixes is non-empty");
14959                    let prefix_trimmed_lengths = full_comment_prefixes
14960                        .iter()
14961                        .map(|p| p.trim_end_matches(' ').len())
14962                        .collect::<SmallVec<[usize; 4]>>();
14963
14964                    let mut all_selection_lines_are_comments = true;
14965
14966                    for row in start_row.0..=end_row.0 {
14967                        let row = MultiBufferRow(row);
14968                        if start_row < end_row && snapshot.is_line_blank(row) {
14969                            continue;
14970                        }
14971
14972                        let prefix_range = full_comment_prefixes
14973                            .iter()
14974                            .zip(prefix_trimmed_lengths.iter().copied())
14975                            .map(|(prefix, trimmed_prefix_len)| {
14976                                comment_prefix_range(
14977                                    snapshot.deref(),
14978                                    row,
14979                                    &prefix[..trimmed_prefix_len],
14980                                    &prefix[trimmed_prefix_len..],
14981                                    ignore_indent,
14982                                )
14983                            })
14984                            .max_by_key(|range| range.end.column - range.start.column)
14985                            .expect("prefixes is non-empty");
14986
14987                        if prefix_range.is_empty() {
14988                            all_selection_lines_are_comments = false;
14989                        }
14990
14991                        selection_edit_ranges.push(prefix_range);
14992                    }
14993
14994                    if all_selection_lines_are_comments {
14995                        edits.extend(
14996                            selection_edit_ranges
14997                                .iter()
14998                                .cloned()
14999                                .map(|range| (range, empty_str.clone())),
15000                        );
15001                    } else {
15002                        let min_column = selection_edit_ranges
15003                            .iter()
15004                            .map(|range| range.start.column)
15005                            .min()
15006                            .unwrap_or(0);
15007                        edits.extend(selection_edit_ranges.iter().map(|range| {
15008                            let position = Point::new(range.start.row, min_column);
15009                            (position..position, first_prefix.clone())
15010                        }));
15011                    }
15012                } else if let Some(BlockCommentConfig {
15013                    start: full_comment_prefix,
15014                    end: comment_suffix,
15015                    ..
15016                }) = language.block_comment()
15017                {
15018                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15019                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15020                    let prefix_range = comment_prefix_range(
15021                        snapshot.deref(),
15022                        start_row,
15023                        comment_prefix,
15024                        comment_prefix_whitespace,
15025                        ignore_indent,
15026                    );
15027                    let suffix_range = comment_suffix_range(
15028                        snapshot.deref(),
15029                        end_row,
15030                        comment_suffix.trim_start_matches(' '),
15031                        comment_suffix.starts_with(' '),
15032                    );
15033
15034                    if prefix_range.is_empty() || suffix_range.is_empty() {
15035                        edits.push((
15036                            prefix_range.start..prefix_range.start,
15037                            full_comment_prefix.clone(),
15038                        ));
15039                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15040                        suffixes_inserted.push((end_row, comment_suffix.len()));
15041                    } else {
15042                        edits.push((prefix_range, empty_str.clone()));
15043                        edits.push((suffix_range, empty_str.clone()));
15044                    }
15045                } else {
15046                    continue;
15047                }
15048            }
15049
15050            drop(snapshot);
15051            this.buffer.update(cx, |buffer, cx| {
15052                buffer.edit(edits, None, cx);
15053            });
15054
15055            // Adjust selections so that they end before any comment suffixes that
15056            // were inserted.
15057            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15058            let mut selections = this.selections.all::<Point>(cx);
15059            let snapshot = this.buffer.read(cx).read(cx);
15060            for selection in &mut selections {
15061                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15062                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15063                        Ordering::Less => {
15064                            suffixes_inserted.next();
15065                            continue;
15066                        }
15067                        Ordering::Greater => break,
15068                        Ordering::Equal => {
15069                            if selection.end.column == snapshot.line_len(row) {
15070                                if selection.is_empty() {
15071                                    selection.start.column -= suffix_len as u32;
15072                                }
15073                                selection.end.column -= suffix_len as u32;
15074                            }
15075                            break;
15076                        }
15077                    }
15078                }
15079            }
15080
15081            drop(snapshot);
15082            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15083
15084            let selections = this.selections.all::<Point>(cx);
15085            let selections_on_single_row = selections.windows(2).all(|selections| {
15086                selections[0].start.row == selections[1].start.row
15087                    && selections[0].end.row == selections[1].end.row
15088                    && selections[0].start.row == selections[0].end.row
15089            });
15090            let selections_selecting = selections
15091                .iter()
15092                .any(|selection| selection.start != selection.end);
15093            let advance_downwards = action.advance_downwards
15094                && selections_on_single_row
15095                && !selections_selecting
15096                && !matches!(this.mode, EditorMode::SingleLine);
15097
15098            if advance_downwards {
15099                let snapshot = this.buffer.read(cx).snapshot(cx);
15100
15101                this.change_selections(Default::default(), window, cx, |s| {
15102                    s.move_cursors_with(|display_snapshot, display_point, _| {
15103                        let mut point = display_point.to_point(display_snapshot);
15104                        point.row += 1;
15105                        point = snapshot.clip_point(point, Bias::Left);
15106                        let display_point = point.to_display_point(display_snapshot);
15107                        let goal = SelectionGoal::HorizontalPosition(
15108                            display_snapshot
15109                                .x_for_display_point(display_point, text_layout_details)
15110                                .into(),
15111                        );
15112                        (display_point, goal)
15113                    })
15114                });
15115            }
15116        });
15117    }
15118
15119    pub fn select_enclosing_symbol(
15120        &mut self,
15121        _: &SelectEnclosingSymbol,
15122        window: &mut Window,
15123        cx: &mut Context<Self>,
15124    ) {
15125        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15126
15127        let buffer = self.buffer.read(cx).snapshot(cx);
15128        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15129
15130        fn update_selection(
15131            selection: &Selection<usize>,
15132            buffer_snap: &MultiBufferSnapshot,
15133        ) -> Option<Selection<usize>> {
15134            let cursor = selection.head();
15135            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15136            for symbol in symbols.iter().rev() {
15137                let start = symbol.range.start.to_offset(buffer_snap);
15138                let end = symbol.range.end.to_offset(buffer_snap);
15139                let new_range = start..end;
15140                if start < selection.start || end > selection.end {
15141                    return Some(Selection {
15142                        id: selection.id,
15143                        start: new_range.start,
15144                        end: new_range.end,
15145                        goal: SelectionGoal::None,
15146                        reversed: selection.reversed,
15147                    });
15148                }
15149            }
15150            None
15151        }
15152
15153        let mut selected_larger_symbol = false;
15154        let new_selections = old_selections
15155            .iter()
15156            .map(|selection| match update_selection(selection, &buffer) {
15157                Some(new_selection) => {
15158                    if new_selection.range() != selection.range() {
15159                        selected_larger_symbol = true;
15160                    }
15161                    new_selection
15162                }
15163                None => selection.clone(),
15164            })
15165            .collect::<Vec<_>>();
15166
15167        if selected_larger_symbol {
15168            self.change_selections(Default::default(), window, cx, |s| {
15169                s.select(new_selections);
15170            });
15171        }
15172    }
15173
15174    pub fn select_larger_syntax_node(
15175        &mut self,
15176        _: &SelectLargerSyntaxNode,
15177        window: &mut Window,
15178        cx: &mut Context<Self>,
15179    ) {
15180        let Some(visible_row_count) = self.visible_row_count() else {
15181            return;
15182        };
15183        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15184        if old_selections.is_empty() {
15185            return;
15186        }
15187
15188        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15189
15190        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15191        let buffer = self.buffer.read(cx).snapshot(cx);
15192
15193        let mut selected_larger_node = false;
15194        let mut new_selections = old_selections
15195            .iter()
15196            .map(|selection| {
15197                let old_range = selection.start..selection.end;
15198
15199                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15200                    // manually select word at selection
15201                    if ["string_content", "inline"].contains(&node.kind()) {
15202                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15203                        // ignore if word is already selected
15204                        if !word_range.is_empty() && old_range != word_range {
15205                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15206                            // only select word if start and end point belongs to same word
15207                            if word_range == last_word_range {
15208                                selected_larger_node = true;
15209                                return Selection {
15210                                    id: selection.id,
15211                                    start: word_range.start,
15212                                    end: word_range.end,
15213                                    goal: SelectionGoal::None,
15214                                    reversed: selection.reversed,
15215                                };
15216                            }
15217                        }
15218                    }
15219                }
15220
15221                let mut new_range = old_range.clone();
15222                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15223                    new_range = range;
15224                    if !node.is_named() {
15225                        continue;
15226                    }
15227                    if !display_map.intersects_fold(new_range.start)
15228                        && !display_map.intersects_fold(new_range.end)
15229                    {
15230                        break;
15231                    }
15232                }
15233
15234                selected_larger_node |= new_range != old_range;
15235                Selection {
15236                    id: selection.id,
15237                    start: new_range.start,
15238                    end: new_range.end,
15239                    goal: SelectionGoal::None,
15240                    reversed: selection.reversed,
15241                }
15242            })
15243            .collect::<Vec<_>>();
15244
15245        if !selected_larger_node {
15246            return; // don't put this call in the history
15247        }
15248
15249        // scroll based on transformation done to the last selection created by the user
15250        let (last_old, last_new) = old_selections
15251            .last()
15252            .zip(new_selections.last().cloned())
15253            .expect("old_selections isn't empty");
15254
15255        // revert selection
15256        let is_selection_reversed = {
15257            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15258            new_selections.last_mut().expect("checked above").reversed =
15259                should_newest_selection_be_reversed;
15260            should_newest_selection_be_reversed
15261        };
15262
15263        if selected_larger_node {
15264            self.select_syntax_node_history.disable_clearing = true;
15265            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15266                s.select(new_selections.clone());
15267            });
15268            self.select_syntax_node_history.disable_clearing = false;
15269        }
15270
15271        let start_row = last_new.start.to_display_point(&display_map).row().0;
15272        let end_row = last_new.end.to_display_point(&display_map).row().0;
15273        let selection_height = end_row - start_row + 1;
15274        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15275
15276        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15277        let scroll_behavior = if fits_on_the_screen {
15278            self.request_autoscroll(Autoscroll::fit(), cx);
15279            SelectSyntaxNodeScrollBehavior::FitSelection
15280        } else if is_selection_reversed {
15281            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15282            SelectSyntaxNodeScrollBehavior::CursorTop
15283        } else {
15284            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15285            SelectSyntaxNodeScrollBehavior::CursorBottom
15286        };
15287
15288        self.select_syntax_node_history.push((
15289            old_selections,
15290            scroll_behavior,
15291            is_selection_reversed,
15292        ));
15293    }
15294
15295    pub fn select_smaller_syntax_node(
15296        &mut self,
15297        _: &SelectSmallerSyntaxNode,
15298        window: &mut Window,
15299        cx: &mut Context<Self>,
15300    ) {
15301        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15302
15303        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15304            self.select_syntax_node_history.pop()
15305        {
15306            if let Some(selection) = selections.last_mut() {
15307                selection.reversed = is_selection_reversed;
15308            }
15309
15310            self.select_syntax_node_history.disable_clearing = true;
15311            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15312                s.select(selections.to_vec());
15313            });
15314            self.select_syntax_node_history.disable_clearing = false;
15315
15316            match scroll_behavior {
15317                SelectSyntaxNodeScrollBehavior::CursorTop => {
15318                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15319                }
15320                SelectSyntaxNodeScrollBehavior::FitSelection => {
15321                    self.request_autoscroll(Autoscroll::fit(), cx);
15322                }
15323                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15324                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15325                }
15326            }
15327        }
15328    }
15329
15330    pub fn unwrap_syntax_node(
15331        &mut self,
15332        _: &UnwrapSyntaxNode,
15333        window: &mut Window,
15334        cx: &mut Context<Self>,
15335    ) {
15336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15337
15338        let buffer = self.buffer.read(cx).snapshot(cx);
15339        let selections = self
15340            .selections
15341            .all::<usize>(cx)
15342            .into_iter()
15343            // subtracting the offset requires sorting
15344            .sorted_by_key(|i| i.start);
15345
15346        let full_edits = selections
15347            .into_iter()
15348            .filter_map(|selection| {
15349                let child = if selection.is_empty()
15350                    && let Some((_, ancestor_range)) =
15351                        buffer.syntax_ancestor(selection.start..selection.end)
15352                {
15353                    ancestor_range
15354                } else {
15355                    selection.range()
15356                };
15357
15358                let mut parent = child.clone();
15359                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15360                    parent = ancestor_range;
15361                    if parent.start < child.start || parent.end > child.end {
15362                        break;
15363                    }
15364                }
15365
15366                if parent == child {
15367                    return None;
15368                }
15369                let text = buffer.text_for_range(child).collect::<String>();
15370                Some((selection.id, parent, text))
15371            })
15372            .collect::<Vec<_>>();
15373        if full_edits.is_empty() {
15374            return;
15375        }
15376
15377        self.transact(window, cx, |this, window, cx| {
15378            this.buffer.update(cx, |buffer, cx| {
15379                buffer.edit(
15380                    full_edits
15381                        .iter()
15382                        .map(|(_, p, t)| (p.clone(), t.clone()))
15383                        .collect::<Vec<_>>(),
15384                    None,
15385                    cx,
15386                );
15387            });
15388            this.change_selections(Default::default(), window, cx, |s| {
15389                let mut offset = 0;
15390                let mut selections = vec![];
15391                for (id, parent, text) in full_edits {
15392                    let start = parent.start - offset;
15393                    offset += parent.len() - text.len();
15394                    selections.push(Selection {
15395                        id,
15396                        start,
15397                        end: start + text.len(),
15398                        reversed: false,
15399                        goal: Default::default(),
15400                    });
15401                }
15402                s.select(selections);
15403            });
15404        });
15405    }
15406
15407    pub fn select_next_syntax_node(
15408        &mut self,
15409        _: &SelectNextSyntaxNode,
15410        window: &mut Window,
15411        cx: &mut Context<Self>,
15412    ) {
15413        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15414        if old_selections.is_empty() {
15415            return;
15416        }
15417
15418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15419
15420        let buffer = self.buffer.read(cx).snapshot(cx);
15421        let mut selected_sibling = false;
15422
15423        let new_selections = old_selections
15424            .iter()
15425            .map(|selection| {
15426                let old_range = selection.start..selection.end;
15427
15428                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15429                    let new_range = node.byte_range();
15430                    selected_sibling = true;
15431                    Selection {
15432                        id: selection.id,
15433                        start: new_range.start,
15434                        end: new_range.end,
15435                        goal: SelectionGoal::None,
15436                        reversed: selection.reversed,
15437                    }
15438                } else {
15439                    selection.clone()
15440                }
15441            })
15442            .collect::<Vec<_>>();
15443
15444        if selected_sibling {
15445            self.change_selections(
15446                SelectionEffects::scroll(Autoscroll::fit()),
15447                window,
15448                cx,
15449                |s| {
15450                    s.select(new_selections);
15451                },
15452            );
15453        }
15454    }
15455
15456    pub fn select_prev_syntax_node(
15457        &mut self,
15458        _: &SelectPreviousSyntaxNode,
15459        window: &mut Window,
15460        cx: &mut Context<Self>,
15461    ) {
15462        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15463        if old_selections.is_empty() {
15464            return;
15465        }
15466
15467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15468
15469        let buffer = self.buffer.read(cx).snapshot(cx);
15470        let mut selected_sibling = false;
15471
15472        let new_selections = old_selections
15473            .iter()
15474            .map(|selection| {
15475                let old_range = selection.start..selection.end;
15476
15477                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15478                    let new_range = node.byte_range();
15479                    selected_sibling = true;
15480                    Selection {
15481                        id: selection.id,
15482                        start: new_range.start,
15483                        end: new_range.end,
15484                        goal: SelectionGoal::None,
15485                        reversed: selection.reversed,
15486                    }
15487                } else {
15488                    selection.clone()
15489                }
15490            })
15491            .collect::<Vec<_>>();
15492
15493        if selected_sibling {
15494            self.change_selections(
15495                SelectionEffects::scroll(Autoscroll::fit()),
15496                window,
15497                cx,
15498                |s| {
15499                    s.select(new_selections);
15500                },
15501            );
15502        }
15503    }
15504
15505    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15506        if !EditorSettings::get_global(cx).gutter.runnables {
15507            self.clear_tasks();
15508            return Task::ready(());
15509        }
15510        let project = self.project().map(Entity::downgrade);
15511        let task_sources = self.lsp_task_sources(cx);
15512        let multi_buffer = self.buffer.downgrade();
15513        cx.spawn_in(window, async move |editor, cx| {
15514            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15515            let Some(project) = project.and_then(|p| p.upgrade()) else {
15516                return;
15517            };
15518            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15519                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15520            }) else {
15521                return;
15522            };
15523
15524            let hide_runnables = project
15525                .update(cx, |project, _| project.is_via_collab())
15526                .unwrap_or(true);
15527            if hide_runnables {
15528                return;
15529            }
15530            let new_rows =
15531                cx.background_spawn({
15532                    let snapshot = display_snapshot.clone();
15533                    async move {
15534                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15535                    }
15536                })
15537                    .await;
15538            let Ok(lsp_tasks) =
15539                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15540            else {
15541                return;
15542            };
15543            let lsp_tasks = lsp_tasks.await;
15544
15545            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15546                lsp_tasks
15547                    .into_iter()
15548                    .flat_map(|(kind, tasks)| {
15549                        tasks.into_iter().filter_map(move |(location, task)| {
15550                            Some((kind.clone(), location?, task))
15551                        })
15552                    })
15553                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15554                        let buffer = location.target.buffer;
15555                        let buffer_snapshot = buffer.read(cx).snapshot();
15556                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15557                            |(excerpt_id, snapshot, _)| {
15558                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15559                                    display_snapshot
15560                                        .buffer_snapshot()
15561                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15562                                } else {
15563                                    None
15564                                }
15565                            },
15566                        );
15567                        if let Some(offset) = offset {
15568                            let task_buffer_range =
15569                                location.target.range.to_point(&buffer_snapshot);
15570                            let context_buffer_range =
15571                                task_buffer_range.to_offset(&buffer_snapshot);
15572                            let context_range = BufferOffset(context_buffer_range.start)
15573                                ..BufferOffset(context_buffer_range.end);
15574
15575                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15576                                .or_insert_with(|| RunnableTasks {
15577                                    templates: Vec::new(),
15578                                    offset,
15579                                    column: task_buffer_range.start.column,
15580                                    extra_variables: HashMap::default(),
15581                                    context_range,
15582                                })
15583                                .templates
15584                                .push((kind, task.original_task().clone()));
15585                        }
15586
15587                        acc
15588                    })
15589            }) else {
15590                return;
15591            };
15592
15593            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15594                buffer.language_settings(cx).tasks.prefer_lsp
15595            }) else {
15596                return;
15597            };
15598
15599            let rows = Self::runnable_rows(
15600                project,
15601                display_snapshot,
15602                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15603                new_rows,
15604                cx.clone(),
15605            )
15606            .await;
15607            editor
15608                .update(cx, |editor, _| {
15609                    editor.clear_tasks();
15610                    for (key, mut value) in rows {
15611                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15612                            value.templates.extend(lsp_tasks.templates);
15613                        }
15614
15615                        editor.insert_tasks(key, value);
15616                    }
15617                    for (key, value) in lsp_tasks_by_rows {
15618                        editor.insert_tasks(key, value);
15619                    }
15620                })
15621                .ok();
15622        })
15623    }
15624    fn fetch_runnable_ranges(
15625        snapshot: &DisplaySnapshot,
15626        range: Range<Anchor>,
15627    ) -> Vec<language::RunnableRange> {
15628        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15629    }
15630
15631    fn runnable_rows(
15632        project: Entity<Project>,
15633        snapshot: DisplaySnapshot,
15634        prefer_lsp: bool,
15635        runnable_ranges: Vec<RunnableRange>,
15636        cx: AsyncWindowContext,
15637    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15638        cx.spawn(async move |cx| {
15639            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15640            for mut runnable in runnable_ranges {
15641                let Some(tasks) = cx
15642                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15643                    .ok()
15644                else {
15645                    continue;
15646                };
15647                let mut tasks = tasks.await;
15648
15649                if prefer_lsp {
15650                    tasks.retain(|(task_kind, _)| {
15651                        !matches!(task_kind, TaskSourceKind::Language { .. })
15652                    });
15653                }
15654                if tasks.is_empty() {
15655                    continue;
15656                }
15657
15658                let point = runnable
15659                    .run_range
15660                    .start
15661                    .to_point(&snapshot.buffer_snapshot());
15662                let Some(row) = snapshot
15663                    .buffer_snapshot()
15664                    .buffer_line_for_row(MultiBufferRow(point.row))
15665                    .map(|(_, range)| range.start.row)
15666                else {
15667                    continue;
15668                };
15669
15670                let context_range =
15671                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15672                runnable_rows.push((
15673                    (runnable.buffer_id, row),
15674                    RunnableTasks {
15675                        templates: tasks,
15676                        offset: snapshot
15677                            .buffer_snapshot()
15678                            .anchor_before(runnable.run_range.start),
15679                        context_range,
15680                        column: point.column,
15681                        extra_variables: runnable.extra_captures,
15682                    },
15683                ));
15684            }
15685            runnable_rows
15686        })
15687    }
15688
15689    fn templates_with_tags(
15690        project: &Entity<Project>,
15691        runnable: &mut Runnable,
15692        cx: &mut App,
15693    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15694        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15695            let (worktree_id, file) = project
15696                .buffer_for_id(runnable.buffer, cx)
15697                .and_then(|buffer| buffer.read(cx).file())
15698                .map(|file| (file.worktree_id(cx), file.clone()))
15699                .unzip();
15700
15701            (
15702                project.task_store().read(cx).task_inventory().cloned(),
15703                worktree_id,
15704                file,
15705            )
15706        });
15707
15708        let tags = mem::take(&mut runnable.tags);
15709        let language = runnable.language.clone();
15710        cx.spawn(async move |cx| {
15711            let mut templates_with_tags = Vec::new();
15712            if let Some(inventory) = inventory {
15713                for RunnableTag(tag) in tags {
15714                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15715                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15716                    }) else {
15717                        return templates_with_tags;
15718                    };
15719                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15720                        move |(_, template)| {
15721                            template.tags.iter().any(|source_tag| source_tag == &tag)
15722                        },
15723                    ));
15724                }
15725            }
15726            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15727
15728            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15729                // Strongest source wins; if we have worktree tag binding, prefer that to
15730                // global and language bindings;
15731                // if we have a global binding, prefer that to language binding.
15732                let first_mismatch = templates_with_tags
15733                    .iter()
15734                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15735                if let Some(index) = first_mismatch {
15736                    templates_with_tags.truncate(index);
15737                }
15738            }
15739
15740            templates_with_tags
15741        })
15742    }
15743
15744    pub fn move_to_enclosing_bracket(
15745        &mut self,
15746        _: &MoveToEnclosingBracket,
15747        window: &mut Window,
15748        cx: &mut Context<Self>,
15749    ) {
15750        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15751        self.change_selections(Default::default(), window, cx, |s| {
15752            s.move_offsets_with(|snapshot, selection| {
15753                let Some(enclosing_bracket_ranges) =
15754                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15755                else {
15756                    return;
15757                };
15758
15759                let mut best_length = usize::MAX;
15760                let mut best_inside = false;
15761                let mut best_in_bracket_range = false;
15762                let mut best_destination = None;
15763                for (open, close) in enclosing_bracket_ranges {
15764                    let close = close.to_inclusive();
15765                    let length = close.end() - open.start;
15766                    let inside = selection.start >= open.end && selection.end <= *close.start();
15767                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15768                        || close.contains(&selection.head());
15769
15770                    // If best is next to a bracket and current isn't, skip
15771                    if !in_bracket_range && best_in_bracket_range {
15772                        continue;
15773                    }
15774
15775                    // Prefer smaller lengths unless best is inside and current isn't
15776                    if length > best_length && (best_inside || !inside) {
15777                        continue;
15778                    }
15779
15780                    best_length = length;
15781                    best_inside = inside;
15782                    best_in_bracket_range = in_bracket_range;
15783                    best_destination = Some(
15784                        if close.contains(&selection.start) && close.contains(&selection.end) {
15785                            if inside { open.end } else { open.start }
15786                        } else if inside {
15787                            *close.start()
15788                        } else {
15789                            *close.end()
15790                        },
15791                    );
15792                }
15793
15794                if let Some(destination) = best_destination {
15795                    selection.collapse_to(destination, SelectionGoal::None);
15796                }
15797            })
15798        });
15799    }
15800
15801    pub fn undo_selection(
15802        &mut self,
15803        _: &UndoSelection,
15804        window: &mut Window,
15805        cx: &mut Context<Self>,
15806    ) {
15807        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15808        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15809            self.selection_history.mode = SelectionHistoryMode::Undoing;
15810            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15811                this.end_selection(window, cx);
15812                this.change_selections(
15813                    SelectionEffects::scroll(Autoscroll::newest()),
15814                    window,
15815                    cx,
15816                    |s| s.select_anchors(entry.selections.to_vec()),
15817                );
15818            });
15819            self.selection_history.mode = SelectionHistoryMode::Normal;
15820
15821            self.select_next_state = entry.select_next_state;
15822            self.select_prev_state = entry.select_prev_state;
15823            self.add_selections_state = entry.add_selections_state;
15824        }
15825    }
15826
15827    pub fn redo_selection(
15828        &mut self,
15829        _: &RedoSelection,
15830        window: &mut Window,
15831        cx: &mut Context<Self>,
15832    ) {
15833        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15834        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15835            self.selection_history.mode = SelectionHistoryMode::Redoing;
15836            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15837                this.end_selection(window, cx);
15838                this.change_selections(
15839                    SelectionEffects::scroll(Autoscroll::newest()),
15840                    window,
15841                    cx,
15842                    |s| s.select_anchors(entry.selections.to_vec()),
15843                );
15844            });
15845            self.selection_history.mode = SelectionHistoryMode::Normal;
15846
15847            self.select_next_state = entry.select_next_state;
15848            self.select_prev_state = entry.select_prev_state;
15849            self.add_selections_state = entry.add_selections_state;
15850        }
15851    }
15852
15853    pub fn expand_excerpts(
15854        &mut self,
15855        action: &ExpandExcerpts,
15856        _: &mut Window,
15857        cx: &mut Context<Self>,
15858    ) {
15859        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15860    }
15861
15862    pub fn expand_excerpts_down(
15863        &mut self,
15864        action: &ExpandExcerptsDown,
15865        _: &mut Window,
15866        cx: &mut Context<Self>,
15867    ) {
15868        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15869    }
15870
15871    pub fn expand_excerpts_up(
15872        &mut self,
15873        action: &ExpandExcerptsUp,
15874        _: &mut Window,
15875        cx: &mut Context<Self>,
15876    ) {
15877        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15878    }
15879
15880    pub fn expand_excerpts_for_direction(
15881        &mut self,
15882        lines: u32,
15883        direction: ExpandExcerptDirection,
15884
15885        cx: &mut Context<Self>,
15886    ) {
15887        let selections = self.selections.disjoint_anchors_arc();
15888
15889        let lines = if lines == 0 {
15890            EditorSettings::get_global(cx).expand_excerpt_lines
15891        } else {
15892            lines
15893        };
15894
15895        self.buffer.update(cx, |buffer, cx| {
15896            let snapshot = buffer.snapshot(cx);
15897            let mut excerpt_ids = selections
15898                .iter()
15899                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15900                .collect::<Vec<_>>();
15901            excerpt_ids.sort();
15902            excerpt_ids.dedup();
15903            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15904        })
15905    }
15906
15907    pub fn expand_excerpt(
15908        &mut self,
15909        excerpt: ExcerptId,
15910        direction: ExpandExcerptDirection,
15911        window: &mut Window,
15912        cx: &mut Context<Self>,
15913    ) {
15914        let current_scroll_position = self.scroll_position(cx);
15915        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15916        let mut should_scroll_up = false;
15917
15918        if direction == ExpandExcerptDirection::Down {
15919            let multi_buffer = self.buffer.read(cx);
15920            let snapshot = multi_buffer.snapshot(cx);
15921            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15922                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15923                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15924            {
15925                let buffer_snapshot = buffer.read(cx).snapshot();
15926                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15927                let last_row = buffer_snapshot.max_point().row;
15928                let lines_below = last_row.saturating_sub(excerpt_end_row);
15929                should_scroll_up = lines_below >= lines_to_expand;
15930            }
15931        }
15932
15933        self.buffer.update(cx, |buffer, cx| {
15934            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15935        });
15936
15937        if should_scroll_up {
15938            let new_scroll_position =
15939                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15940            self.set_scroll_position(new_scroll_position, window, cx);
15941        }
15942    }
15943
15944    pub fn go_to_singleton_buffer_point(
15945        &mut self,
15946        point: Point,
15947        window: &mut Window,
15948        cx: &mut Context<Self>,
15949    ) {
15950        self.go_to_singleton_buffer_range(point..point, window, cx);
15951    }
15952
15953    pub fn go_to_singleton_buffer_range(
15954        &mut self,
15955        range: Range<Point>,
15956        window: &mut Window,
15957        cx: &mut Context<Self>,
15958    ) {
15959        let multibuffer = self.buffer().read(cx);
15960        let Some(buffer) = multibuffer.as_singleton() else {
15961            return;
15962        };
15963        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15964            return;
15965        };
15966        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15967            return;
15968        };
15969        self.change_selections(
15970            SelectionEffects::default().nav_history(true),
15971            window,
15972            cx,
15973            |s| s.select_anchor_ranges([start..end]),
15974        );
15975    }
15976
15977    pub fn go_to_diagnostic(
15978        &mut self,
15979        action: &GoToDiagnostic,
15980        window: &mut Window,
15981        cx: &mut Context<Self>,
15982    ) {
15983        if !self.diagnostics_enabled() {
15984            return;
15985        }
15986        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15987        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15988    }
15989
15990    pub fn go_to_prev_diagnostic(
15991        &mut self,
15992        action: &GoToPreviousDiagnostic,
15993        window: &mut Window,
15994        cx: &mut Context<Self>,
15995    ) {
15996        if !self.diagnostics_enabled() {
15997            return;
15998        }
15999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16000        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16001    }
16002
16003    pub fn go_to_diagnostic_impl(
16004        &mut self,
16005        direction: Direction,
16006        severity: GoToDiagnosticSeverityFilter,
16007        window: &mut Window,
16008        cx: &mut Context<Self>,
16009    ) {
16010        let buffer = self.buffer.read(cx).snapshot(cx);
16011        let selection = self.selections.newest::<usize>(cx);
16012
16013        let mut active_group_id = None;
16014        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16015            && active_group.active_range.start.to_offset(&buffer) == selection.start
16016        {
16017            active_group_id = Some(active_group.group_id);
16018        }
16019
16020        fn filtered<'a>(
16021            snapshot: EditorSnapshot,
16022            severity: GoToDiagnosticSeverityFilter,
16023            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16024        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16025            diagnostics
16026                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16027                .filter(|entry| entry.range.start != entry.range.end)
16028                .filter(|entry| !entry.diagnostic.is_unnecessary)
16029                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16030        }
16031
16032        let snapshot = self.snapshot(window, cx);
16033        let before = filtered(
16034            snapshot.clone(),
16035            severity,
16036            buffer
16037                .diagnostics_in_range(0..selection.start)
16038                .filter(|entry| entry.range.start <= selection.start),
16039        );
16040        let after = filtered(
16041            snapshot,
16042            severity,
16043            buffer
16044                .diagnostics_in_range(selection.start..buffer.len())
16045                .filter(|entry| entry.range.start >= selection.start),
16046        );
16047
16048        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16049        if direction == Direction::Prev {
16050            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16051            {
16052                for diagnostic in prev_diagnostics.into_iter().rev() {
16053                    if diagnostic.range.start != selection.start
16054                        || active_group_id
16055                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16056                    {
16057                        found = Some(diagnostic);
16058                        break 'outer;
16059                    }
16060                }
16061            }
16062        } else {
16063            for diagnostic in after.chain(before) {
16064                if diagnostic.range.start != selection.start
16065                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16066                {
16067                    found = Some(diagnostic);
16068                    break;
16069                }
16070            }
16071        }
16072        let Some(next_diagnostic) = found else {
16073            return;
16074        };
16075
16076        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16077        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16078            return;
16079        };
16080        self.change_selections(Default::default(), window, cx, |s| {
16081            s.select_ranges(vec![
16082                next_diagnostic.range.start..next_diagnostic.range.start,
16083            ])
16084        });
16085        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16086        self.refresh_edit_prediction(false, true, window, cx);
16087    }
16088
16089    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16090        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16091        let snapshot = self.snapshot(window, cx);
16092        let selection = self.selections.newest::<Point>(cx);
16093        self.go_to_hunk_before_or_after_position(
16094            &snapshot,
16095            selection.head(),
16096            Direction::Next,
16097            window,
16098            cx,
16099        );
16100    }
16101
16102    pub fn go_to_hunk_before_or_after_position(
16103        &mut self,
16104        snapshot: &EditorSnapshot,
16105        position: Point,
16106        direction: Direction,
16107        window: &mut Window,
16108        cx: &mut Context<Editor>,
16109    ) {
16110        let row = if direction == Direction::Next {
16111            self.hunk_after_position(snapshot, position)
16112                .map(|hunk| hunk.row_range.start)
16113        } else {
16114            self.hunk_before_position(snapshot, position)
16115        };
16116
16117        if let Some(row) = row {
16118            let destination = Point::new(row.0, 0);
16119            let autoscroll = Autoscroll::center();
16120
16121            self.unfold_ranges(&[destination..destination], false, false, cx);
16122            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16123                s.select_ranges([destination..destination]);
16124            });
16125        }
16126    }
16127
16128    fn hunk_after_position(
16129        &mut self,
16130        snapshot: &EditorSnapshot,
16131        position: Point,
16132    ) -> Option<MultiBufferDiffHunk> {
16133        snapshot
16134            .buffer_snapshot()
16135            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16136            .find(|hunk| hunk.row_range.start.0 > position.row)
16137            .or_else(|| {
16138                snapshot
16139                    .buffer_snapshot()
16140                    .diff_hunks_in_range(Point::zero()..position)
16141                    .find(|hunk| hunk.row_range.end.0 < position.row)
16142            })
16143    }
16144
16145    fn go_to_prev_hunk(
16146        &mut self,
16147        _: &GoToPreviousHunk,
16148        window: &mut Window,
16149        cx: &mut Context<Self>,
16150    ) {
16151        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16152        let snapshot = self.snapshot(window, cx);
16153        let selection = self.selections.newest::<Point>(cx);
16154        self.go_to_hunk_before_or_after_position(
16155            &snapshot,
16156            selection.head(),
16157            Direction::Prev,
16158            window,
16159            cx,
16160        );
16161    }
16162
16163    fn hunk_before_position(
16164        &mut self,
16165        snapshot: &EditorSnapshot,
16166        position: Point,
16167    ) -> Option<MultiBufferRow> {
16168        snapshot
16169            .buffer_snapshot()
16170            .diff_hunk_before(position)
16171            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16172    }
16173
16174    fn go_to_next_change(
16175        &mut self,
16176        _: &GoToNextChange,
16177        window: &mut Window,
16178        cx: &mut Context<Self>,
16179    ) {
16180        if let Some(selections) = self
16181            .change_list
16182            .next_change(1, Direction::Next)
16183            .map(|s| s.to_vec())
16184        {
16185            self.change_selections(Default::default(), window, cx, |s| {
16186                let map = s.display_map();
16187                s.select_display_ranges(selections.iter().map(|a| {
16188                    let point = a.to_display_point(&map);
16189                    point..point
16190                }))
16191            })
16192        }
16193    }
16194
16195    fn go_to_previous_change(
16196        &mut self,
16197        _: &GoToPreviousChange,
16198        window: &mut Window,
16199        cx: &mut Context<Self>,
16200    ) {
16201        if let Some(selections) = self
16202            .change_list
16203            .next_change(1, Direction::Prev)
16204            .map(|s| s.to_vec())
16205        {
16206            self.change_selections(Default::default(), window, cx, |s| {
16207                let map = s.display_map();
16208                s.select_display_ranges(selections.iter().map(|a| {
16209                    let point = a.to_display_point(&map);
16210                    point..point
16211                }))
16212            })
16213        }
16214    }
16215
16216    pub fn go_to_next_document_highlight(
16217        &mut self,
16218        _: &GoToNextDocumentHighlight,
16219        window: &mut Window,
16220        cx: &mut Context<Self>,
16221    ) {
16222        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16223    }
16224
16225    pub fn go_to_prev_document_highlight(
16226        &mut self,
16227        _: &GoToPreviousDocumentHighlight,
16228        window: &mut Window,
16229        cx: &mut Context<Self>,
16230    ) {
16231        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16232    }
16233
16234    pub fn go_to_document_highlight_before_or_after_position(
16235        &mut self,
16236        direction: Direction,
16237        window: &mut Window,
16238        cx: &mut Context<Editor>,
16239    ) {
16240        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16241        let snapshot = self.snapshot(window, cx);
16242        let buffer = &snapshot.buffer_snapshot();
16243        let position = self.selections.newest::<Point>(cx).head();
16244        let anchor_position = buffer.anchor_after(position);
16245
16246        // Get all document highlights (both read and write)
16247        let mut all_highlights = Vec::new();
16248
16249        if let Some((_, read_highlights)) = self
16250            .background_highlights
16251            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16252        {
16253            all_highlights.extend(read_highlights.iter());
16254        }
16255
16256        if let Some((_, write_highlights)) = self
16257            .background_highlights
16258            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16259        {
16260            all_highlights.extend(write_highlights.iter());
16261        }
16262
16263        if all_highlights.is_empty() {
16264            return;
16265        }
16266
16267        // Sort highlights by position
16268        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16269
16270        let target_highlight = match direction {
16271            Direction::Next => {
16272                // Find the first highlight after the current position
16273                all_highlights
16274                    .iter()
16275                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16276            }
16277            Direction::Prev => {
16278                // Find the last highlight before the current position
16279                all_highlights
16280                    .iter()
16281                    .rev()
16282                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16283            }
16284        };
16285
16286        if let Some(highlight) = target_highlight {
16287            let destination = highlight.start.to_point(buffer);
16288            let autoscroll = Autoscroll::center();
16289
16290            self.unfold_ranges(&[destination..destination], false, false, cx);
16291            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16292                s.select_ranges([destination..destination]);
16293            });
16294        }
16295    }
16296
16297    fn go_to_line<T: 'static>(
16298        &mut self,
16299        position: Anchor,
16300        highlight_color: Option<Hsla>,
16301        window: &mut Window,
16302        cx: &mut Context<Self>,
16303    ) {
16304        let snapshot = self.snapshot(window, cx).display_snapshot;
16305        let position = position.to_point(&snapshot.buffer_snapshot());
16306        let start = snapshot
16307            .buffer_snapshot()
16308            .clip_point(Point::new(position.row, 0), Bias::Left);
16309        let end = start + Point::new(1, 0);
16310        let start = snapshot.buffer_snapshot().anchor_before(start);
16311        let end = snapshot.buffer_snapshot().anchor_before(end);
16312
16313        self.highlight_rows::<T>(
16314            start..end,
16315            highlight_color
16316                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16317            Default::default(),
16318            cx,
16319        );
16320
16321        if self.buffer.read(cx).is_singleton() {
16322            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16323        }
16324    }
16325
16326    pub fn go_to_definition(
16327        &mut self,
16328        _: &GoToDefinition,
16329        window: &mut Window,
16330        cx: &mut Context<Self>,
16331    ) -> Task<Result<Navigated>> {
16332        let definition =
16333            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16334        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16335        cx.spawn_in(window, async move |editor, cx| {
16336            if definition.await? == Navigated::Yes {
16337                return Ok(Navigated::Yes);
16338            }
16339            match fallback_strategy {
16340                GoToDefinitionFallback::None => Ok(Navigated::No),
16341                GoToDefinitionFallback::FindAllReferences => {
16342                    match editor.update_in(cx, |editor, window, cx| {
16343                        editor.find_all_references(&FindAllReferences, window, cx)
16344                    })? {
16345                        Some(references) => references.await,
16346                        None => Ok(Navigated::No),
16347                    }
16348                }
16349            }
16350        })
16351    }
16352
16353    pub fn go_to_declaration(
16354        &mut self,
16355        _: &GoToDeclaration,
16356        window: &mut Window,
16357        cx: &mut Context<Self>,
16358    ) -> Task<Result<Navigated>> {
16359        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16360    }
16361
16362    pub fn go_to_declaration_split(
16363        &mut self,
16364        _: &GoToDeclaration,
16365        window: &mut Window,
16366        cx: &mut Context<Self>,
16367    ) -> Task<Result<Navigated>> {
16368        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16369    }
16370
16371    pub fn go_to_implementation(
16372        &mut self,
16373        _: &GoToImplementation,
16374        window: &mut Window,
16375        cx: &mut Context<Self>,
16376    ) -> Task<Result<Navigated>> {
16377        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16378    }
16379
16380    pub fn go_to_implementation_split(
16381        &mut self,
16382        _: &GoToImplementationSplit,
16383        window: &mut Window,
16384        cx: &mut Context<Self>,
16385    ) -> Task<Result<Navigated>> {
16386        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16387    }
16388
16389    pub fn go_to_type_definition(
16390        &mut self,
16391        _: &GoToTypeDefinition,
16392        window: &mut Window,
16393        cx: &mut Context<Self>,
16394    ) -> Task<Result<Navigated>> {
16395        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16396    }
16397
16398    pub fn go_to_definition_split(
16399        &mut self,
16400        _: &GoToDefinitionSplit,
16401        window: &mut Window,
16402        cx: &mut Context<Self>,
16403    ) -> Task<Result<Navigated>> {
16404        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16405    }
16406
16407    pub fn go_to_type_definition_split(
16408        &mut self,
16409        _: &GoToTypeDefinitionSplit,
16410        window: &mut Window,
16411        cx: &mut Context<Self>,
16412    ) -> Task<Result<Navigated>> {
16413        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16414    }
16415
16416    fn go_to_definition_of_kind(
16417        &mut self,
16418        kind: GotoDefinitionKind,
16419        split: bool,
16420        window: &mut Window,
16421        cx: &mut Context<Self>,
16422    ) -> Task<Result<Navigated>> {
16423        let Some(provider) = self.semantics_provider.clone() else {
16424            return Task::ready(Ok(Navigated::No));
16425        };
16426        let head = self.selections.newest::<usize>(cx).head();
16427        let buffer = self.buffer.read(cx);
16428        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16429            return Task::ready(Ok(Navigated::No));
16430        };
16431        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16432            return Task::ready(Ok(Navigated::No));
16433        };
16434
16435        cx.spawn_in(window, async move |editor, cx| {
16436            let Some(definitions) = definitions.await? else {
16437                return Ok(Navigated::No);
16438            };
16439            let navigated = editor
16440                .update_in(cx, |editor, window, cx| {
16441                    editor.navigate_to_hover_links(
16442                        Some(kind),
16443                        definitions
16444                            .into_iter()
16445                            .filter(|location| {
16446                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16447                            })
16448                            .map(HoverLink::Text)
16449                            .collect::<Vec<_>>(),
16450                        split,
16451                        window,
16452                        cx,
16453                    )
16454                })?
16455                .await?;
16456            anyhow::Ok(navigated)
16457        })
16458    }
16459
16460    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16461        let selection = self.selections.newest_anchor();
16462        let head = selection.head();
16463        let tail = selection.tail();
16464
16465        let Some((buffer, start_position)) =
16466            self.buffer.read(cx).text_anchor_for_position(head, cx)
16467        else {
16468            return;
16469        };
16470
16471        let end_position = if head != tail {
16472            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16473                return;
16474            };
16475            Some(pos)
16476        } else {
16477            None
16478        };
16479
16480        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16481            let url = if let Some(end_pos) = end_position {
16482                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16483            } else {
16484                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16485            };
16486
16487            if let Some(url) = url {
16488                cx.update(|window, cx| {
16489                    if parse_zed_link(&url, cx).is_some() {
16490                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16491                    } else {
16492                        cx.open_url(&url);
16493                    }
16494                })?;
16495            }
16496
16497            anyhow::Ok(())
16498        });
16499
16500        url_finder.detach();
16501    }
16502
16503    pub fn open_selected_filename(
16504        &mut self,
16505        _: &OpenSelectedFilename,
16506        window: &mut Window,
16507        cx: &mut Context<Self>,
16508    ) {
16509        let Some(workspace) = self.workspace() else {
16510            return;
16511        };
16512
16513        let position = self.selections.newest_anchor().head();
16514
16515        let Some((buffer, buffer_position)) =
16516            self.buffer.read(cx).text_anchor_for_position(position, cx)
16517        else {
16518            return;
16519        };
16520
16521        let project = self.project.clone();
16522
16523        cx.spawn_in(window, async move |_, cx| {
16524            let result = find_file(&buffer, project, buffer_position, cx).await;
16525
16526            if let Some((_, path)) = result {
16527                workspace
16528                    .update_in(cx, |workspace, window, cx| {
16529                        workspace.open_resolved_path(path, window, cx)
16530                    })?
16531                    .await?;
16532            }
16533            anyhow::Ok(())
16534        })
16535        .detach();
16536    }
16537
16538    pub(crate) fn navigate_to_hover_links(
16539        &mut self,
16540        kind: Option<GotoDefinitionKind>,
16541        definitions: Vec<HoverLink>,
16542        split: bool,
16543        window: &mut Window,
16544        cx: &mut Context<Editor>,
16545    ) -> Task<Result<Navigated>> {
16546        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16547        let mut first_url_or_file = None;
16548        let definitions: Vec<_> = definitions
16549            .into_iter()
16550            .filter_map(|def| match def {
16551                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16552                HoverLink::InlayHint(lsp_location, server_id) => {
16553                    let computation =
16554                        self.compute_target_location(lsp_location, server_id, window, cx);
16555                    Some(cx.background_spawn(computation))
16556                }
16557                HoverLink::Url(url) => {
16558                    first_url_or_file = Some(Either::Left(url));
16559                    None
16560                }
16561                HoverLink::File(path) => {
16562                    first_url_or_file = Some(Either::Right(path));
16563                    None
16564                }
16565            })
16566            .collect();
16567
16568        let workspace = self.workspace();
16569
16570        cx.spawn_in(window, async move |editor, cx| {
16571            let locations: Vec<Location> = future::join_all(definitions)
16572                .await
16573                .into_iter()
16574                .filter_map(|location| location.transpose())
16575                .collect::<Result<_>>()
16576                .context("location tasks")?;
16577            let mut locations = cx.update(|_, cx| {
16578                locations
16579                    .into_iter()
16580                    .map(|location| {
16581                        let buffer = location.buffer.read(cx);
16582                        (location.buffer, location.range.to_point(buffer))
16583                    })
16584                    .into_group_map()
16585            })?;
16586            let mut num_locations = 0;
16587            for ranges in locations.values_mut() {
16588                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16589                ranges.dedup();
16590                num_locations += ranges.len();
16591            }
16592
16593            if num_locations > 1 {
16594                let Some(workspace) = workspace else {
16595                    return Ok(Navigated::No);
16596                };
16597
16598                let tab_kind = match kind {
16599                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16600                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16601                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16602                    Some(GotoDefinitionKind::Type) => "Types",
16603                };
16604                let title = editor
16605                    .update_in(cx, |_, _, cx| {
16606                        let target = locations
16607                            .iter()
16608                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16609                            .map(|(buffer, location)| {
16610                                buffer
16611                                    .read(cx)
16612                                    .text_for_range(location.clone())
16613                                    .collect::<String>()
16614                            })
16615                            .filter(|text| !text.contains('\n'))
16616                            .unique()
16617                            .take(3)
16618                            .join(", ");
16619                        if target.is_empty() {
16620                            tab_kind.to_owned()
16621                        } else {
16622                            format!("{tab_kind} for {target}")
16623                        }
16624                    })
16625                    .context("buffer title")?;
16626
16627                let opened = workspace
16628                    .update_in(cx, |workspace, window, cx| {
16629                        Self::open_locations_in_multibuffer(
16630                            workspace,
16631                            locations,
16632                            title,
16633                            split,
16634                            MultibufferSelectionMode::First,
16635                            window,
16636                            cx,
16637                        )
16638                    })
16639                    .is_ok();
16640
16641                anyhow::Ok(Navigated::from_bool(opened))
16642            } else if num_locations == 0 {
16643                // If there is one url or file, open it directly
16644                match first_url_or_file {
16645                    Some(Either::Left(url)) => {
16646                        cx.update(|_, cx| cx.open_url(&url))?;
16647                        Ok(Navigated::Yes)
16648                    }
16649                    Some(Either::Right(path)) => {
16650                        let Some(workspace) = workspace else {
16651                            return Ok(Navigated::No);
16652                        };
16653
16654                        workspace
16655                            .update_in(cx, |workspace, window, cx| {
16656                                workspace.open_resolved_path(path, window, cx)
16657                            })?
16658                            .await?;
16659                        Ok(Navigated::Yes)
16660                    }
16661                    None => Ok(Navigated::No),
16662                }
16663            } else {
16664                let Some(workspace) = workspace else {
16665                    return Ok(Navigated::No);
16666                };
16667
16668                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16669                let target_range = target_ranges.first().unwrap().clone();
16670
16671                editor.update_in(cx, |editor, window, cx| {
16672                    let range = target_range.to_point(target_buffer.read(cx));
16673                    let range = editor.range_for_match(&range);
16674                    let range = collapse_multiline_range(range);
16675
16676                    if !split
16677                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16678                    {
16679                        editor.go_to_singleton_buffer_range(range, window, cx);
16680                    } else {
16681                        let pane = workspace.read(cx).active_pane().clone();
16682                        window.defer(cx, move |window, cx| {
16683                            let target_editor: Entity<Self> =
16684                                workspace.update(cx, |workspace, cx| {
16685                                    let pane = if split {
16686                                        workspace.adjacent_pane(window, cx)
16687                                    } else {
16688                                        workspace.active_pane().clone()
16689                                    };
16690
16691                                    workspace.open_project_item(
16692                                        pane,
16693                                        target_buffer.clone(),
16694                                        true,
16695                                        true,
16696                                        window,
16697                                        cx,
16698                                    )
16699                                });
16700                            target_editor.update(cx, |target_editor, cx| {
16701                                // When selecting a definition in a different buffer, disable the nav history
16702                                // to avoid creating a history entry at the previous cursor location.
16703                                pane.update(cx, |pane, _| pane.disable_history());
16704                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16705                                pane.update(cx, |pane, _| pane.enable_history());
16706                            });
16707                        });
16708                    }
16709                    Navigated::Yes
16710                })
16711            }
16712        })
16713    }
16714
16715    fn compute_target_location(
16716        &self,
16717        lsp_location: lsp::Location,
16718        server_id: LanguageServerId,
16719        window: &mut Window,
16720        cx: &mut Context<Self>,
16721    ) -> Task<anyhow::Result<Option<Location>>> {
16722        let Some(project) = self.project.clone() else {
16723            return Task::ready(Ok(None));
16724        };
16725
16726        cx.spawn_in(window, async move |editor, cx| {
16727            let location_task = editor.update(cx, |_, cx| {
16728                project.update(cx, |project, cx| {
16729                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16730                })
16731            })?;
16732            let location = Some({
16733                let target_buffer_handle = location_task.await.context("open local buffer")?;
16734                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16735                    let target_start = target_buffer
16736                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16737                    let target_end = target_buffer
16738                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16739                    target_buffer.anchor_after(target_start)
16740                        ..target_buffer.anchor_before(target_end)
16741                })?;
16742                Location {
16743                    buffer: target_buffer_handle,
16744                    range,
16745                }
16746            });
16747            Ok(location)
16748        })
16749    }
16750
16751    pub fn find_all_references(
16752        &mut self,
16753        _: &FindAllReferences,
16754        window: &mut Window,
16755        cx: &mut Context<Self>,
16756    ) -> Option<Task<Result<Navigated>>> {
16757        let selection = self.selections.newest::<usize>(cx);
16758        let multi_buffer = self.buffer.read(cx);
16759        let head = selection.head();
16760
16761        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16762        let head_anchor = multi_buffer_snapshot.anchor_at(
16763            head,
16764            if head < selection.tail() {
16765                Bias::Right
16766            } else {
16767                Bias::Left
16768            },
16769        );
16770
16771        match self
16772            .find_all_references_task_sources
16773            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16774        {
16775            Ok(_) => {
16776                log::info!(
16777                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16778                );
16779                return None;
16780            }
16781            Err(i) => {
16782                self.find_all_references_task_sources.insert(i, head_anchor);
16783            }
16784        }
16785
16786        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16787        let workspace = self.workspace()?;
16788        let project = workspace.read(cx).project().clone();
16789        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16790        Some(cx.spawn_in(window, async move |editor, cx| {
16791            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16792                if let Ok(i) = editor
16793                    .find_all_references_task_sources
16794                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16795                {
16796                    editor.find_all_references_task_sources.remove(i);
16797                }
16798            });
16799
16800            let Some(locations) = references.await? else {
16801                return anyhow::Ok(Navigated::No);
16802            };
16803            let mut locations = cx.update(|_, cx| {
16804                locations
16805                    .into_iter()
16806                    .map(|location| {
16807                        let buffer = location.buffer.read(cx);
16808                        (location.buffer, location.range.to_point(buffer))
16809                    })
16810                    .into_group_map()
16811            })?;
16812            if locations.is_empty() {
16813                return anyhow::Ok(Navigated::No);
16814            }
16815            for ranges in locations.values_mut() {
16816                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16817                ranges.dedup();
16818            }
16819
16820            workspace.update_in(cx, |workspace, window, cx| {
16821                let target = locations
16822                    .iter()
16823                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16824                    .map(|(buffer, location)| {
16825                        buffer
16826                            .read(cx)
16827                            .text_for_range(location.clone())
16828                            .collect::<String>()
16829                    })
16830                    .filter(|text| !text.contains('\n'))
16831                    .unique()
16832                    .take(3)
16833                    .join(", ");
16834                let title = if target.is_empty() {
16835                    "References".to_owned()
16836                } else {
16837                    format!("References to {target}")
16838                };
16839                Self::open_locations_in_multibuffer(
16840                    workspace,
16841                    locations,
16842                    title,
16843                    false,
16844                    MultibufferSelectionMode::First,
16845                    window,
16846                    cx,
16847                );
16848                Navigated::Yes
16849            })
16850        }))
16851    }
16852
16853    /// Opens a multibuffer with the given project locations in it
16854    pub fn open_locations_in_multibuffer(
16855        workspace: &mut Workspace,
16856        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16857        title: String,
16858        split: bool,
16859        multibuffer_selection_mode: MultibufferSelectionMode,
16860        window: &mut Window,
16861        cx: &mut Context<Workspace>,
16862    ) {
16863        if locations.is_empty() {
16864            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16865            return;
16866        }
16867
16868        let capability = workspace.project().read(cx).capability();
16869        let mut ranges = <Vec<Range<Anchor>>>::new();
16870
16871        // a key to find existing multibuffer editors with the same set of locations
16872        // to prevent us from opening more and more multibuffer tabs for searches and the like
16873        let mut key = (title.clone(), vec![]);
16874        let excerpt_buffer = cx.new(|cx| {
16875            let key = &mut key.1;
16876            let mut multibuffer = MultiBuffer::new(capability);
16877            for (buffer, mut ranges_for_buffer) in locations {
16878                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16879                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16880                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16881                    PathKey::for_buffer(&buffer, cx),
16882                    buffer.clone(),
16883                    ranges_for_buffer,
16884                    multibuffer_context_lines(cx),
16885                    cx,
16886                );
16887                ranges.extend(new_ranges)
16888            }
16889
16890            multibuffer.with_title(title)
16891        });
16892        let existing = workspace.active_pane().update(cx, |pane, cx| {
16893            pane.items()
16894                .filter_map(|item| item.downcast::<Editor>())
16895                .find(|editor| {
16896                    editor
16897                        .read(cx)
16898                        .lookup_key
16899                        .as_ref()
16900                        .and_then(|it| {
16901                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16902                        })
16903                        .is_some_and(|it| *it == key)
16904                })
16905        });
16906        let editor = existing.unwrap_or_else(|| {
16907            cx.new(|cx| {
16908                let mut editor = Editor::for_multibuffer(
16909                    excerpt_buffer,
16910                    Some(workspace.project().clone()),
16911                    window,
16912                    cx,
16913                );
16914                editor.lookup_key = Some(Box::new(key));
16915                editor
16916            })
16917        });
16918        editor.update(cx, |editor, cx| {
16919            match multibuffer_selection_mode {
16920                MultibufferSelectionMode::First => {
16921                    if let Some(first_range) = ranges.first() {
16922                        editor.change_selections(
16923                            SelectionEffects::no_scroll(),
16924                            window,
16925                            cx,
16926                            |selections| {
16927                                selections.clear_disjoint();
16928                                selections
16929                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16930                            },
16931                        );
16932                    }
16933                    editor.highlight_background::<Self>(
16934                        &ranges,
16935                        |theme| theme.colors().editor_highlighted_line_background,
16936                        cx,
16937                    );
16938                }
16939                MultibufferSelectionMode::All => {
16940                    editor.change_selections(
16941                        SelectionEffects::no_scroll(),
16942                        window,
16943                        cx,
16944                        |selections| {
16945                            selections.clear_disjoint();
16946                            selections.select_anchor_ranges(ranges);
16947                        },
16948                    );
16949                }
16950            }
16951            editor.register_buffers_with_language_servers(cx);
16952        });
16953
16954        let item = Box::new(editor);
16955        let item_id = item.item_id();
16956
16957        if split {
16958            let pane = workspace.adjacent_pane(window, cx);
16959            workspace.add_item(pane, item, None, true, true, window, cx);
16960        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16961            let (preview_item_id, preview_item_idx) =
16962                workspace.active_pane().read_with(cx, |pane, _| {
16963                    (pane.preview_item_id(), pane.preview_item_idx())
16964                });
16965
16966            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16967
16968            if let Some(preview_item_id) = preview_item_id {
16969                workspace.active_pane().update(cx, |pane, cx| {
16970                    pane.remove_item(preview_item_id, false, false, window, cx);
16971                });
16972            }
16973        } else {
16974            workspace.add_item_to_active_pane(item, None, true, window, cx);
16975        }
16976        workspace.active_pane().update(cx, |pane, cx| {
16977            pane.set_preview_item_id(Some(item_id), cx);
16978        });
16979    }
16980
16981    pub fn rename(
16982        &mut self,
16983        _: &Rename,
16984        window: &mut Window,
16985        cx: &mut Context<Self>,
16986    ) -> Option<Task<Result<()>>> {
16987        use language::ToOffset as _;
16988
16989        let provider = self.semantics_provider.clone()?;
16990        let selection = self.selections.newest_anchor().clone();
16991        let (cursor_buffer, cursor_buffer_position) = self
16992            .buffer
16993            .read(cx)
16994            .text_anchor_for_position(selection.head(), cx)?;
16995        let (tail_buffer, cursor_buffer_position_end) = self
16996            .buffer
16997            .read(cx)
16998            .text_anchor_for_position(selection.tail(), cx)?;
16999        if tail_buffer != cursor_buffer {
17000            return None;
17001        }
17002
17003        let snapshot = cursor_buffer.read(cx).snapshot();
17004        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17005        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17006        let prepare_rename = provider
17007            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17008            .unwrap_or_else(|| Task::ready(Ok(None)));
17009        drop(snapshot);
17010
17011        Some(cx.spawn_in(window, async move |this, cx| {
17012            let rename_range = if let Some(range) = prepare_rename.await? {
17013                Some(range)
17014            } else {
17015                this.update(cx, |this, cx| {
17016                    let buffer = this.buffer.read(cx).snapshot(cx);
17017                    let mut buffer_highlights = this
17018                        .document_highlights_for_position(selection.head(), &buffer)
17019                        .filter(|highlight| {
17020                            highlight.start.excerpt_id == selection.head().excerpt_id
17021                                && highlight.end.excerpt_id == selection.head().excerpt_id
17022                        });
17023                    buffer_highlights
17024                        .next()
17025                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17026                })?
17027            };
17028            if let Some(rename_range) = rename_range {
17029                this.update_in(cx, |this, window, cx| {
17030                    let snapshot = cursor_buffer.read(cx).snapshot();
17031                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17032                    let cursor_offset_in_rename_range =
17033                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17034                    let cursor_offset_in_rename_range_end =
17035                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17036
17037                    this.take_rename(false, window, cx);
17038                    let buffer = this.buffer.read(cx).read(cx);
17039                    let cursor_offset = selection.head().to_offset(&buffer);
17040                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17041                    let rename_end = rename_start + rename_buffer_range.len();
17042                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17043                    let mut old_highlight_id = None;
17044                    let old_name: Arc<str> = buffer
17045                        .chunks(rename_start..rename_end, true)
17046                        .map(|chunk| {
17047                            if old_highlight_id.is_none() {
17048                                old_highlight_id = chunk.syntax_highlight_id;
17049                            }
17050                            chunk.text
17051                        })
17052                        .collect::<String>()
17053                        .into();
17054
17055                    drop(buffer);
17056
17057                    // Position the selection in the rename editor so that it matches the current selection.
17058                    this.show_local_selections = false;
17059                    let rename_editor = cx.new(|cx| {
17060                        let mut editor = Editor::single_line(window, cx);
17061                        editor.buffer.update(cx, |buffer, cx| {
17062                            buffer.edit([(0..0, old_name.clone())], None, cx)
17063                        });
17064                        let rename_selection_range = match cursor_offset_in_rename_range
17065                            .cmp(&cursor_offset_in_rename_range_end)
17066                        {
17067                            Ordering::Equal => {
17068                                editor.select_all(&SelectAll, window, cx);
17069                                return editor;
17070                            }
17071                            Ordering::Less => {
17072                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17073                            }
17074                            Ordering::Greater => {
17075                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17076                            }
17077                        };
17078                        if rename_selection_range.end > old_name.len() {
17079                            editor.select_all(&SelectAll, window, cx);
17080                        } else {
17081                            editor.change_selections(Default::default(), window, cx, |s| {
17082                                s.select_ranges([rename_selection_range]);
17083                            });
17084                        }
17085                        editor
17086                    });
17087                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17088                        if e == &EditorEvent::Focused {
17089                            cx.emit(EditorEvent::FocusedIn)
17090                        }
17091                    })
17092                    .detach();
17093
17094                    let write_highlights =
17095                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17096                    let read_highlights =
17097                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17098                    let ranges = write_highlights
17099                        .iter()
17100                        .flat_map(|(_, ranges)| ranges.iter())
17101                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17102                        .cloned()
17103                        .collect();
17104
17105                    this.highlight_text::<Rename>(
17106                        ranges,
17107                        HighlightStyle {
17108                            fade_out: Some(0.6),
17109                            ..Default::default()
17110                        },
17111                        cx,
17112                    );
17113                    let rename_focus_handle = rename_editor.focus_handle(cx);
17114                    window.focus(&rename_focus_handle);
17115                    let block_id = this.insert_blocks(
17116                        [BlockProperties {
17117                            style: BlockStyle::Flex,
17118                            placement: BlockPlacement::Below(range.start),
17119                            height: Some(1),
17120                            render: Arc::new({
17121                                let rename_editor = rename_editor.clone();
17122                                move |cx: &mut BlockContext| {
17123                                    let mut text_style = cx.editor_style.text.clone();
17124                                    if let Some(highlight_style) = old_highlight_id
17125                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17126                                    {
17127                                        text_style = text_style.highlight(highlight_style);
17128                                    }
17129                                    div()
17130                                        .block_mouse_except_scroll()
17131                                        .pl(cx.anchor_x)
17132                                        .child(EditorElement::new(
17133                                            &rename_editor,
17134                                            EditorStyle {
17135                                                background: cx.theme().system().transparent,
17136                                                local_player: cx.editor_style.local_player,
17137                                                text: text_style,
17138                                                scrollbar_width: cx.editor_style.scrollbar_width,
17139                                                syntax: cx.editor_style.syntax.clone(),
17140                                                status: cx.editor_style.status.clone(),
17141                                                inlay_hints_style: HighlightStyle {
17142                                                    font_weight: Some(FontWeight::BOLD),
17143                                                    ..make_inlay_hints_style(cx.app)
17144                                                },
17145                                                edit_prediction_styles: make_suggestion_styles(
17146                                                    cx.app,
17147                                                ),
17148                                                ..EditorStyle::default()
17149                                            },
17150                                        ))
17151                                        .into_any_element()
17152                                }
17153                            }),
17154                            priority: 0,
17155                        }],
17156                        Some(Autoscroll::fit()),
17157                        cx,
17158                    )[0];
17159                    this.pending_rename = Some(RenameState {
17160                        range,
17161                        old_name,
17162                        editor: rename_editor,
17163                        block_id,
17164                    });
17165                })?;
17166            }
17167
17168            Ok(())
17169        }))
17170    }
17171
17172    pub fn confirm_rename(
17173        &mut self,
17174        _: &ConfirmRename,
17175        window: &mut Window,
17176        cx: &mut Context<Self>,
17177    ) -> Option<Task<Result<()>>> {
17178        let rename = self.take_rename(false, window, cx)?;
17179        let workspace = self.workspace()?.downgrade();
17180        let (buffer, start) = self
17181            .buffer
17182            .read(cx)
17183            .text_anchor_for_position(rename.range.start, cx)?;
17184        let (end_buffer, _) = self
17185            .buffer
17186            .read(cx)
17187            .text_anchor_for_position(rename.range.end, cx)?;
17188        if buffer != end_buffer {
17189            return None;
17190        }
17191
17192        let old_name = rename.old_name;
17193        let new_name = rename.editor.read(cx).text(cx);
17194
17195        let rename = self.semantics_provider.as_ref()?.perform_rename(
17196            &buffer,
17197            start,
17198            new_name.clone(),
17199            cx,
17200        )?;
17201
17202        Some(cx.spawn_in(window, async move |editor, cx| {
17203            let project_transaction = rename.await?;
17204            Self::open_project_transaction(
17205                &editor,
17206                workspace,
17207                project_transaction,
17208                format!("Rename: {}{}", old_name, new_name),
17209                cx,
17210            )
17211            .await?;
17212
17213            editor.update(cx, |editor, cx| {
17214                editor.refresh_document_highlights(cx);
17215            })?;
17216            Ok(())
17217        }))
17218    }
17219
17220    fn take_rename(
17221        &mut self,
17222        moving_cursor: bool,
17223        window: &mut Window,
17224        cx: &mut Context<Self>,
17225    ) -> Option<RenameState> {
17226        let rename = self.pending_rename.take()?;
17227        if rename.editor.focus_handle(cx).is_focused(window) {
17228            window.focus(&self.focus_handle);
17229        }
17230
17231        self.remove_blocks(
17232            [rename.block_id].into_iter().collect(),
17233            Some(Autoscroll::fit()),
17234            cx,
17235        );
17236        self.clear_highlights::<Rename>(cx);
17237        self.show_local_selections = true;
17238
17239        if moving_cursor {
17240            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17241                editor.selections.newest::<usize>(cx).head()
17242            });
17243
17244            // Update the selection to match the position of the selection inside
17245            // the rename editor.
17246            let snapshot = self.buffer.read(cx).read(cx);
17247            let rename_range = rename.range.to_offset(&snapshot);
17248            let cursor_in_editor = snapshot
17249                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17250                .min(rename_range.end);
17251            drop(snapshot);
17252
17253            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17254                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17255            });
17256        } else {
17257            self.refresh_document_highlights(cx);
17258        }
17259
17260        Some(rename)
17261    }
17262
17263    pub fn pending_rename(&self) -> Option<&RenameState> {
17264        self.pending_rename.as_ref()
17265    }
17266
17267    fn format(
17268        &mut self,
17269        _: &Format,
17270        window: &mut Window,
17271        cx: &mut Context<Self>,
17272    ) -> Option<Task<Result<()>>> {
17273        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17274
17275        let project = match &self.project {
17276            Some(project) => project.clone(),
17277            None => return None,
17278        };
17279
17280        Some(self.perform_format(
17281            project,
17282            FormatTrigger::Manual,
17283            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17284            window,
17285            cx,
17286        ))
17287    }
17288
17289    fn format_selections(
17290        &mut self,
17291        _: &FormatSelections,
17292        window: &mut Window,
17293        cx: &mut Context<Self>,
17294    ) -> Option<Task<Result<()>>> {
17295        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17296
17297        let project = match &self.project {
17298            Some(project) => project.clone(),
17299            None => return None,
17300        };
17301
17302        let ranges = self
17303            .selections
17304            .all_adjusted(cx)
17305            .into_iter()
17306            .map(|selection| selection.range())
17307            .collect_vec();
17308
17309        Some(self.perform_format(
17310            project,
17311            FormatTrigger::Manual,
17312            FormatTarget::Ranges(ranges),
17313            window,
17314            cx,
17315        ))
17316    }
17317
17318    fn perform_format(
17319        &mut self,
17320        project: Entity<Project>,
17321        trigger: FormatTrigger,
17322        target: FormatTarget,
17323        window: &mut Window,
17324        cx: &mut Context<Self>,
17325    ) -> Task<Result<()>> {
17326        let buffer = self.buffer.clone();
17327        let (buffers, target) = match target {
17328            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17329            FormatTarget::Ranges(selection_ranges) => {
17330                let multi_buffer = buffer.read(cx);
17331                let snapshot = multi_buffer.read(cx);
17332                let mut buffers = HashSet::default();
17333                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17334                    BTreeMap::new();
17335                for selection_range in selection_ranges {
17336                    for (buffer, buffer_range, _) in
17337                        snapshot.range_to_buffer_ranges(selection_range)
17338                    {
17339                        let buffer_id = buffer.remote_id();
17340                        let start = buffer.anchor_before(buffer_range.start);
17341                        let end = buffer.anchor_after(buffer_range.end);
17342                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17343                        buffer_id_to_ranges
17344                            .entry(buffer_id)
17345                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17346                            .or_insert_with(|| vec![start..end]);
17347                    }
17348                }
17349                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17350            }
17351        };
17352
17353        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17354        let selections_prev = transaction_id_prev
17355            .and_then(|transaction_id_prev| {
17356                // default to selections as they were after the last edit, if we have them,
17357                // instead of how they are now.
17358                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17359                // will take you back to where you made the last edit, instead of staying where you scrolled
17360                self.selection_history
17361                    .transaction(transaction_id_prev)
17362                    .map(|t| t.0.clone())
17363            })
17364            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17365
17366        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17367        let format = project.update(cx, |project, cx| {
17368            project.format(buffers, target, true, trigger, cx)
17369        });
17370
17371        cx.spawn_in(window, async move |editor, cx| {
17372            let transaction = futures::select_biased! {
17373                transaction = format.log_err().fuse() => transaction,
17374                () = timeout => {
17375                    log::warn!("timed out waiting for formatting");
17376                    None
17377                }
17378            };
17379
17380            buffer
17381                .update(cx, |buffer, cx| {
17382                    if let Some(transaction) = transaction
17383                        && !buffer.is_singleton()
17384                    {
17385                        buffer.push_transaction(&transaction.0, cx);
17386                    }
17387                    cx.notify();
17388                })
17389                .ok();
17390
17391            if let Some(transaction_id_now) =
17392                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17393            {
17394                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17395                if has_new_transaction {
17396                    _ = editor.update(cx, |editor, _| {
17397                        editor
17398                            .selection_history
17399                            .insert_transaction(transaction_id_now, selections_prev);
17400                    });
17401                }
17402            }
17403
17404            Ok(())
17405        })
17406    }
17407
17408    fn organize_imports(
17409        &mut self,
17410        _: &OrganizeImports,
17411        window: &mut Window,
17412        cx: &mut Context<Self>,
17413    ) -> Option<Task<Result<()>>> {
17414        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17415        let project = match &self.project {
17416            Some(project) => project.clone(),
17417            None => return None,
17418        };
17419        Some(self.perform_code_action_kind(
17420            project,
17421            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17422            window,
17423            cx,
17424        ))
17425    }
17426
17427    fn perform_code_action_kind(
17428        &mut self,
17429        project: Entity<Project>,
17430        kind: CodeActionKind,
17431        window: &mut Window,
17432        cx: &mut Context<Self>,
17433    ) -> Task<Result<()>> {
17434        let buffer = self.buffer.clone();
17435        let buffers = buffer.read(cx).all_buffers();
17436        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17437        let apply_action = project.update(cx, |project, cx| {
17438            project.apply_code_action_kind(buffers, kind, true, cx)
17439        });
17440        cx.spawn_in(window, async move |_, cx| {
17441            let transaction = futures::select_biased! {
17442                () = timeout => {
17443                    log::warn!("timed out waiting for executing code action");
17444                    None
17445                }
17446                transaction = apply_action.log_err().fuse() => transaction,
17447            };
17448            buffer
17449                .update(cx, |buffer, cx| {
17450                    // check if we need this
17451                    if let Some(transaction) = transaction
17452                        && !buffer.is_singleton()
17453                    {
17454                        buffer.push_transaction(&transaction.0, cx);
17455                    }
17456                    cx.notify();
17457                })
17458                .ok();
17459            Ok(())
17460        })
17461    }
17462
17463    pub fn restart_language_server(
17464        &mut self,
17465        _: &RestartLanguageServer,
17466        _: &mut Window,
17467        cx: &mut Context<Self>,
17468    ) {
17469        if let Some(project) = self.project.clone() {
17470            self.buffer.update(cx, |multi_buffer, cx| {
17471                project.update(cx, |project, cx| {
17472                    project.restart_language_servers_for_buffers(
17473                        multi_buffer.all_buffers().into_iter().collect(),
17474                        HashSet::default(),
17475                        cx,
17476                    );
17477                });
17478            })
17479        }
17480    }
17481
17482    pub fn stop_language_server(
17483        &mut self,
17484        _: &StopLanguageServer,
17485        _: &mut Window,
17486        cx: &mut Context<Self>,
17487    ) {
17488        if let Some(project) = self.project.clone() {
17489            self.buffer.update(cx, |multi_buffer, cx| {
17490                project.update(cx, |project, cx| {
17491                    project.stop_language_servers_for_buffers(
17492                        multi_buffer.all_buffers().into_iter().collect(),
17493                        HashSet::default(),
17494                        cx,
17495                    );
17496                    cx.emit(project::Event::RefreshInlayHints);
17497                });
17498            });
17499        }
17500    }
17501
17502    fn cancel_language_server_work(
17503        workspace: &mut Workspace,
17504        _: &actions::CancelLanguageServerWork,
17505        _: &mut Window,
17506        cx: &mut Context<Workspace>,
17507    ) {
17508        let project = workspace.project();
17509        let buffers = workspace
17510            .active_item(cx)
17511            .and_then(|item| item.act_as::<Editor>(cx))
17512            .map_or(HashSet::default(), |editor| {
17513                editor.read(cx).buffer.read(cx).all_buffers()
17514            });
17515        project.update(cx, |project, cx| {
17516            project.cancel_language_server_work_for_buffers(buffers, cx);
17517        });
17518    }
17519
17520    fn show_character_palette(
17521        &mut self,
17522        _: &ShowCharacterPalette,
17523        window: &mut Window,
17524        _: &mut Context<Self>,
17525    ) {
17526        window.show_character_palette();
17527    }
17528
17529    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17530        if !self.diagnostics_enabled() {
17531            return;
17532        }
17533
17534        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17535            let buffer = self.buffer.read(cx).snapshot(cx);
17536            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17537            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17538            let is_valid = buffer
17539                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17540                .any(|entry| {
17541                    entry.diagnostic.is_primary
17542                        && !entry.range.is_empty()
17543                        && entry.range.start == primary_range_start
17544                        && entry.diagnostic.message == active_diagnostics.active_message
17545                });
17546
17547            if !is_valid {
17548                self.dismiss_diagnostics(cx);
17549            }
17550        }
17551    }
17552
17553    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17554        match &self.active_diagnostics {
17555            ActiveDiagnostic::Group(group) => Some(group),
17556            _ => None,
17557        }
17558    }
17559
17560    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17561        if !self.diagnostics_enabled() {
17562            return;
17563        }
17564        self.dismiss_diagnostics(cx);
17565        self.active_diagnostics = ActiveDiagnostic::All;
17566    }
17567
17568    fn activate_diagnostics(
17569        &mut self,
17570        buffer_id: BufferId,
17571        diagnostic: DiagnosticEntryRef<'_, usize>,
17572        window: &mut Window,
17573        cx: &mut Context<Self>,
17574    ) {
17575        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17576            return;
17577        }
17578        self.dismiss_diagnostics(cx);
17579        let snapshot = self.snapshot(window, cx);
17580        let buffer = self.buffer.read(cx).snapshot(cx);
17581        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17582            return;
17583        };
17584
17585        let diagnostic_group = buffer
17586            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17587            .collect::<Vec<_>>();
17588
17589        let blocks =
17590            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17591
17592        let blocks = self.display_map.update(cx, |display_map, cx| {
17593            display_map.insert_blocks(blocks, cx).into_iter().collect()
17594        });
17595        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17596            active_range: buffer.anchor_before(diagnostic.range.start)
17597                ..buffer.anchor_after(diagnostic.range.end),
17598            active_message: diagnostic.diagnostic.message.clone(),
17599            group_id: diagnostic.diagnostic.group_id,
17600            blocks,
17601        });
17602        cx.notify();
17603    }
17604
17605    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17606        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17607            return;
17608        };
17609
17610        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17611        if let ActiveDiagnostic::Group(group) = prev {
17612            self.display_map.update(cx, |display_map, cx| {
17613                display_map.remove_blocks(group.blocks, cx);
17614            });
17615            cx.notify();
17616        }
17617    }
17618
17619    /// Disable inline diagnostics rendering for this editor.
17620    pub fn disable_inline_diagnostics(&mut self) {
17621        self.inline_diagnostics_enabled = false;
17622        self.inline_diagnostics_update = Task::ready(());
17623        self.inline_diagnostics.clear();
17624    }
17625
17626    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17627        self.diagnostics_enabled = false;
17628        self.dismiss_diagnostics(cx);
17629        self.inline_diagnostics_update = Task::ready(());
17630        self.inline_diagnostics.clear();
17631    }
17632
17633    pub fn disable_word_completions(&mut self) {
17634        self.word_completions_enabled = false;
17635    }
17636
17637    pub fn diagnostics_enabled(&self) -> bool {
17638        self.diagnostics_enabled && self.mode.is_full()
17639    }
17640
17641    pub fn inline_diagnostics_enabled(&self) -> bool {
17642        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17643    }
17644
17645    pub fn show_inline_diagnostics(&self) -> bool {
17646        self.show_inline_diagnostics
17647    }
17648
17649    pub fn toggle_inline_diagnostics(
17650        &mut self,
17651        _: &ToggleInlineDiagnostics,
17652        window: &mut Window,
17653        cx: &mut Context<Editor>,
17654    ) {
17655        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17656        self.refresh_inline_diagnostics(false, window, cx);
17657    }
17658
17659    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17660        self.diagnostics_max_severity = severity;
17661        self.display_map.update(cx, |display_map, _| {
17662            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17663        });
17664    }
17665
17666    pub fn toggle_diagnostics(
17667        &mut self,
17668        _: &ToggleDiagnostics,
17669        window: &mut Window,
17670        cx: &mut Context<Editor>,
17671    ) {
17672        if !self.diagnostics_enabled() {
17673            return;
17674        }
17675
17676        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17677            EditorSettings::get_global(cx)
17678                .diagnostics_max_severity
17679                .filter(|severity| severity != &DiagnosticSeverity::Off)
17680                .unwrap_or(DiagnosticSeverity::Hint)
17681        } else {
17682            DiagnosticSeverity::Off
17683        };
17684        self.set_max_diagnostics_severity(new_severity, cx);
17685        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17686            self.active_diagnostics = ActiveDiagnostic::None;
17687            self.inline_diagnostics_update = Task::ready(());
17688            self.inline_diagnostics.clear();
17689        } else {
17690            self.refresh_inline_diagnostics(false, window, cx);
17691        }
17692
17693        cx.notify();
17694    }
17695
17696    pub fn toggle_minimap(
17697        &mut self,
17698        _: &ToggleMinimap,
17699        window: &mut Window,
17700        cx: &mut Context<Editor>,
17701    ) {
17702        if self.supports_minimap(cx) {
17703            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17704        }
17705    }
17706
17707    fn refresh_inline_diagnostics(
17708        &mut self,
17709        debounce: bool,
17710        window: &mut Window,
17711        cx: &mut Context<Self>,
17712    ) {
17713        let max_severity = ProjectSettings::get_global(cx)
17714            .diagnostics
17715            .inline
17716            .max_severity
17717            .unwrap_or(self.diagnostics_max_severity);
17718
17719        if !self.inline_diagnostics_enabled()
17720            || !self.show_inline_diagnostics
17721            || max_severity == DiagnosticSeverity::Off
17722        {
17723            self.inline_diagnostics_update = Task::ready(());
17724            self.inline_diagnostics.clear();
17725            return;
17726        }
17727
17728        let debounce_ms = ProjectSettings::get_global(cx)
17729            .diagnostics
17730            .inline
17731            .update_debounce_ms;
17732        let debounce = if debounce && debounce_ms > 0 {
17733            Some(Duration::from_millis(debounce_ms))
17734        } else {
17735            None
17736        };
17737        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17738            if let Some(debounce) = debounce {
17739                cx.background_executor().timer(debounce).await;
17740            }
17741            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17742                editor
17743                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17744                    .ok()
17745            }) else {
17746                return;
17747            };
17748
17749            let new_inline_diagnostics = cx
17750                .background_spawn(async move {
17751                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17752                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17753                        let message = diagnostic_entry
17754                            .diagnostic
17755                            .message
17756                            .split_once('\n')
17757                            .map(|(line, _)| line)
17758                            .map(SharedString::new)
17759                            .unwrap_or_else(|| {
17760                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17761                            });
17762                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17763                        let (Ok(i) | Err(i)) = inline_diagnostics
17764                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17765                        inline_diagnostics.insert(
17766                            i,
17767                            (
17768                                start_anchor,
17769                                InlineDiagnostic {
17770                                    message,
17771                                    group_id: diagnostic_entry.diagnostic.group_id,
17772                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17773                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17774                                    severity: diagnostic_entry.diagnostic.severity,
17775                                },
17776                            ),
17777                        );
17778                    }
17779                    inline_diagnostics
17780                })
17781                .await;
17782
17783            editor
17784                .update(cx, |editor, cx| {
17785                    editor.inline_diagnostics = new_inline_diagnostics;
17786                    cx.notify();
17787                })
17788                .ok();
17789        });
17790    }
17791
17792    fn pull_diagnostics(
17793        &mut self,
17794        buffer_id: Option<BufferId>,
17795        window: &Window,
17796        cx: &mut Context<Self>,
17797    ) -> Option<()> {
17798        if !self.mode().is_full() {
17799            return None;
17800        }
17801        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17802            .diagnostics
17803            .lsp_pull_diagnostics;
17804        if !pull_diagnostics_settings.enabled {
17805            return None;
17806        }
17807        let project = self.project()?.downgrade();
17808        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17809        let mut buffers = self.buffer.read(cx).all_buffers();
17810        if let Some(buffer_id) = buffer_id {
17811            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17812        }
17813
17814        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17815            cx.background_executor().timer(debounce).await;
17816
17817            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17818                buffers
17819                    .into_iter()
17820                    .filter_map(|buffer| {
17821                        project
17822                            .update(cx, |project, cx| {
17823                                project.lsp_store().update(cx, |lsp_store, cx| {
17824                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17825                                })
17826                            })
17827                            .ok()
17828                    })
17829                    .collect::<FuturesUnordered<_>>()
17830            }) else {
17831                return;
17832            };
17833
17834            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17835                match pull_task {
17836                    Ok(()) => {
17837                        if editor
17838                            .update_in(cx, |editor, window, cx| {
17839                                editor.update_diagnostics_state(window, cx);
17840                            })
17841                            .is_err()
17842                        {
17843                            return;
17844                        }
17845                    }
17846                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17847                }
17848            }
17849        });
17850
17851        Some(())
17852    }
17853
17854    pub fn set_selections_from_remote(
17855        &mut self,
17856        selections: Vec<Selection<Anchor>>,
17857        pending_selection: Option<Selection<Anchor>>,
17858        window: &mut Window,
17859        cx: &mut Context<Self>,
17860    ) {
17861        let old_cursor_position = self.selections.newest_anchor().head();
17862        self.selections.change_with(cx, |s| {
17863            s.select_anchors(selections);
17864            if let Some(pending_selection) = pending_selection {
17865                s.set_pending(pending_selection, SelectMode::Character);
17866            } else {
17867                s.clear_pending();
17868            }
17869        });
17870        self.selections_did_change(
17871            false,
17872            &old_cursor_position,
17873            SelectionEffects::default(),
17874            window,
17875            cx,
17876        );
17877    }
17878
17879    pub fn transact(
17880        &mut self,
17881        window: &mut Window,
17882        cx: &mut Context<Self>,
17883        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17884    ) -> Option<TransactionId> {
17885        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17886            this.start_transaction_at(Instant::now(), window, cx);
17887            update(this, window, cx);
17888            this.end_transaction_at(Instant::now(), cx)
17889        })
17890    }
17891
17892    pub fn start_transaction_at(
17893        &mut self,
17894        now: Instant,
17895        window: &mut Window,
17896        cx: &mut Context<Self>,
17897    ) -> Option<TransactionId> {
17898        self.end_selection(window, cx);
17899        if let Some(tx_id) = self
17900            .buffer
17901            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17902        {
17903            self.selection_history
17904                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17905            cx.emit(EditorEvent::TransactionBegun {
17906                transaction_id: tx_id,
17907            });
17908            Some(tx_id)
17909        } else {
17910            None
17911        }
17912    }
17913
17914    pub fn end_transaction_at(
17915        &mut self,
17916        now: Instant,
17917        cx: &mut Context<Self>,
17918    ) -> Option<TransactionId> {
17919        if let Some(transaction_id) = self
17920            .buffer
17921            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17922        {
17923            if let Some((_, end_selections)) =
17924                self.selection_history.transaction_mut(transaction_id)
17925            {
17926                *end_selections = Some(self.selections.disjoint_anchors_arc());
17927            } else {
17928                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17929            }
17930
17931            cx.emit(EditorEvent::Edited { transaction_id });
17932            Some(transaction_id)
17933        } else {
17934            None
17935        }
17936    }
17937
17938    pub fn modify_transaction_selection_history(
17939        &mut self,
17940        transaction_id: TransactionId,
17941        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17942    ) -> bool {
17943        self.selection_history
17944            .transaction_mut(transaction_id)
17945            .map(modify)
17946            .is_some()
17947    }
17948
17949    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17950        if self.selection_mark_mode {
17951            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17952                s.move_with(|_, sel| {
17953                    sel.collapse_to(sel.head(), SelectionGoal::None);
17954                });
17955            })
17956        }
17957        self.selection_mark_mode = true;
17958        cx.notify();
17959    }
17960
17961    pub fn swap_selection_ends(
17962        &mut self,
17963        _: &actions::SwapSelectionEnds,
17964        window: &mut Window,
17965        cx: &mut Context<Self>,
17966    ) {
17967        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17968            s.move_with(|_, sel| {
17969                if sel.start != sel.end {
17970                    sel.reversed = !sel.reversed
17971                }
17972            });
17973        });
17974        self.request_autoscroll(Autoscroll::newest(), cx);
17975        cx.notify();
17976    }
17977
17978    pub fn toggle_focus(
17979        workspace: &mut Workspace,
17980        _: &actions::ToggleFocus,
17981        window: &mut Window,
17982        cx: &mut Context<Workspace>,
17983    ) {
17984        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17985            return;
17986        };
17987        workspace.activate_item(&item, true, true, window, cx);
17988    }
17989
17990    pub fn toggle_fold(
17991        &mut self,
17992        _: &actions::ToggleFold,
17993        window: &mut Window,
17994        cx: &mut Context<Self>,
17995    ) {
17996        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
17997            let selection = self.selections.newest::<Point>(cx);
17998
17999            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18000            let range = if selection.is_empty() {
18001                let point = selection.head().to_display_point(&display_map);
18002                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18003                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18004                    .to_point(&display_map);
18005                start..end
18006            } else {
18007                selection.range()
18008            };
18009            if display_map.folds_in_range(range).next().is_some() {
18010                self.unfold_lines(&Default::default(), window, cx)
18011            } else {
18012                self.fold(&Default::default(), window, cx)
18013            }
18014        } else {
18015            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18016            let buffer_ids: HashSet<_> = self
18017                .selections
18018                .disjoint_anchor_ranges()
18019                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18020                .collect();
18021
18022            let should_unfold = buffer_ids
18023                .iter()
18024                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18025
18026            for buffer_id in buffer_ids {
18027                if should_unfold {
18028                    self.unfold_buffer(buffer_id, cx);
18029                } else {
18030                    self.fold_buffer(buffer_id, cx);
18031                }
18032            }
18033        }
18034    }
18035
18036    pub fn toggle_fold_recursive(
18037        &mut self,
18038        _: &actions::ToggleFoldRecursive,
18039        window: &mut Window,
18040        cx: &mut Context<Self>,
18041    ) {
18042        let selection = self.selections.newest::<Point>(cx);
18043
18044        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18045        let range = if selection.is_empty() {
18046            let point = selection.head().to_display_point(&display_map);
18047            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18048            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18049                .to_point(&display_map);
18050            start..end
18051        } else {
18052            selection.range()
18053        };
18054        if display_map.folds_in_range(range).next().is_some() {
18055            self.unfold_recursive(&Default::default(), window, cx)
18056        } else {
18057            self.fold_recursive(&Default::default(), window, cx)
18058        }
18059    }
18060
18061    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18062        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18063            let mut to_fold = Vec::new();
18064            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18065            let selections = self.selections.all_adjusted(cx);
18066
18067            for selection in selections {
18068                let range = selection.range().sorted();
18069                let buffer_start_row = range.start.row;
18070
18071                if range.start.row != range.end.row {
18072                    let mut found = false;
18073                    let mut row = range.start.row;
18074                    while row <= range.end.row {
18075                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18076                        {
18077                            found = true;
18078                            row = crease.range().end.row + 1;
18079                            to_fold.push(crease);
18080                        } else {
18081                            row += 1
18082                        }
18083                    }
18084                    if found {
18085                        continue;
18086                    }
18087                }
18088
18089                for row in (0..=range.start.row).rev() {
18090                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18091                        && crease.range().end.row >= buffer_start_row
18092                    {
18093                        to_fold.push(crease);
18094                        if row <= range.start.row {
18095                            break;
18096                        }
18097                    }
18098                }
18099            }
18100
18101            self.fold_creases(to_fold, true, window, cx);
18102        } else {
18103            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18104            let buffer_ids = self
18105                .selections
18106                .disjoint_anchor_ranges()
18107                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18108                .collect::<HashSet<_>>();
18109            for buffer_id in buffer_ids {
18110                self.fold_buffer(buffer_id, cx);
18111            }
18112        }
18113    }
18114
18115    pub fn toggle_fold_all(
18116        &mut self,
18117        _: &actions::ToggleFoldAll,
18118        window: &mut Window,
18119        cx: &mut Context<Self>,
18120    ) {
18121        if self.buffer.read(cx).is_singleton() {
18122            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18123            let has_folds = display_map
18124                .folds_in_range(0..display_map.buffer_snapshot().len())
18125                .next()
18126                .is_some();
18127
18128            if has_folds {
18129                self.unfold_all(&actions::UnfoldAll, window, cx);
18130            } else {
18131                self.fold_all(&actions::FoldAll, window, cx);
18132            }
18133        } else {
18134            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18135            let should_unfold = buffer_ids
18136                .iter()
18137                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18138
18139            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18140                editor
18141                    .update_in(cx, |editor, _, cx| {
18142                        for buffer_id in buffer_ids {
18143                            if should_unfold {
18144                                editor.unfold_buffer(buffer_id, cx);
18145                            } else {
18146                                editor.fold_buffer(buffer_id, cx);
18147                            }
18148                        }
18149                    })
18150                    .ok();
18151            });
18152        }
18153    }
18154
18155    fn fold_at_level(
18156        &mut self,
18157        fold_at: &FoldAtLevel,
18158        window: &mut Window,
18159        cx: &mut Context<Self>,
18160    ) {
18161        if !self.buffer.read(cx).is_singleton() {
18162            return;
18163        }
18164
18165        let fold_at_level = fold_at.0;
18166        let snapshot = self.buffer.read(cx).snapshot(cx);
18167        let mut to_fold = Vec::new();
18168        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18169
18170        let row_ranges_to_keep: Vec<Range<u32>> = self
18171            .selections
18172            .all::<Point>(cx)
18173            .into_iter()
18174            .map(|sel| sel.start.row..sel.end.row)
18175            .collect();
18176
18177        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18178            while start_row < end_row {
18179                match self
18180                    .snapshot(window, cx)
18181                    .crease_for_buffer_row(MultiBufferRow(start_row))
18182                {
18183                    Some(crease) => {
18184                        let nested_start_row = crease.range().start.row + 1;
18185                        let nested_end_row = crease.range().end.row;
18186
18187                        if current_level < fold_at_level {
18188                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18189                        } else if current_level == fold_at_level {
18190                            // Fold iff there is no selection completely contained within the fold region
18191                            if !row_ranges_to_keep.iter().any(|selection| {
18192                                selection.end >= nested_start_row
18193                                    && selection.start <= nested_end_row
18194                            }) {
18195                                to_fold.push(crease);
18196                            }
18197                        }
18198
18199                        start_row = nested_end_row + 1;
18200                    }
18201                    None => start_row += 1,
18202                }
18203            }
18204        }
18205
18206        self.fold_creases(to_fold, true, window, cx);
18207    }
18208
18209    pub fn fold_at_level_1(
18210        &mut self,
18211        _: &actions::FoldAtLevel1,
18212        window: &mut Window,
18213        cx: &mut Context<Self>,
18214    ) {
18215        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18216    }
18217
18218    pub fn fold_at_level_2(
18219        &mut self,
18220        _: &actions::FoldAtLevel2,
18221        window: &mut Window,
18222        cx: &mut Context<Self>,
18223    ) {
18224        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18225    }
18226
18227    pub fn fold_at_level_3(
18228        &mut self,
18229        _: &actions::FoldAtLevel3,
18230        window: &mut Window,
18231        cx: &mut Context<Self>,
18232    ) {
18233        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18234    }
18235
18236    pub fn fold_at_level_4(
18237        &mut self,
18238        _: &actions::FoldAtLevel4,
18239        window: &mut Window,
18240        cx: &mut Context<Self>,
18241    ) {
18242        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18243    }
18244
18245    pub fn fold_at_level_5(
18246        &mut self,
18247        _: &actions::FoldAtLevel5,
18248        window: &mut Window,
18249        cx: &mut Context<Self>,
18250    ) {
18251        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18252    }
18253
18254    pub fn fold_at_level_6(
18255        &mut self,
18256        _: &actions::FoldAtLevel6,
18257        window: &mut Window,
18258        cx: &mut Context<Self>,
18259    ) {
18260        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18261    }
18262
18263    pub fn fold_at_level_7(
18264        &mut self,
18265        _: &actions::FoldAtLevel7,
18266        window: &mut Window,
18267        cx: &mut Context<Self>,
18268    ) {
18269        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18270    }
18271
18272    pub fn fold_at_level_8(
18273        &mut self,
18274        _: &actions::FoldAtLevel8,
18275        window: &mut Window,
18276        cx: &mut Context<Self>,
18277    ) {
18278        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18279    }
18280
18281    pub fn fold_at_level_9(
18282        &mut self,
18283        _: &actions::FoldAtLevel9,
18284        window: &mut Window,
18285        cx: &mut Context<Self>,
18286    ) {
18287        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18288    }
18289
18290    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18291        if self.buffer.read(cx).is_singleton() {
18292            let mut fold_ranges = Vec::new();
18293            let snapshot = self.buffer.read(cx).snapshot(cx);
18294
18295            for row in 0..snapshot.max_row().0 {
18296                if let Some(foldable_range) = self
18297                    .snapshot(window, cx)
18298                    .crease_for_buffer_row(MultiBufferRow(row))
18299                {
18300                    fold_ranges.push(foldable_range);
18301                }
18302            }
18303
18304            self.fold_creases(fold_ranges, true, window, cx);
18305        } else {
18306            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18307                editor
18308                    .update_in(cx, |editor, _, cx| {
18309                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18310                            editor.fold_buffer(buffer_id, cx);
18311                        }
18312                    })
18313                    .ok();
18314            });
18315        }
18316    }
18317
18318    pub fn fold_function_bodies(
18319        &mut self,
18320        _: &actions::FoldFunctionBodies,
18321        window: &mut Window,
18322        cx: &mut Context<Self>,
18323    ) {
18324        let snapshot = self.buffer.read(cx).snapshot(cx);
18325
18326        let ranges = snapshot
18327            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18328            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18329            .collect::<Vec<_>>();
18330
18331        let creases = ranges
18332            .into_iter()
18333            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18334            .collect();
18335
18336        self.fold_creases(creases, true, window, cx);
18337    }
18338
18339    pub fn fold_recursive(
18340        &mut self,
18341        _: &actions::FoldRecursive,
18342        window: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) {
18345        let mut to_fold = Vec::new();
18346        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18347        let selections = self.selections.all_adjusted(cx);
18348
18349        for selection in selections {
18350            let range = selection.range().sorted();
18351            let buffer_start_row = range.start.row;
18352
18353            if range.start.row != range.end.row {
18354                let mut found = false;
18355                for row in range.start.row..=range.end.row {
18356                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18357                        found = true;
18358                        to_fold.push(crease);
18359                    }
18360                }
18361                if found {
18362                    continue;
18363                }
18364            }
18365
18366            for row in (0..=range.start.row).rev() {
18367                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18368                    if crease.range().end.row >= buffer_start_row {
18369                        to_fold.push(crease);
18370                    } else {
18371                        break;
18372                    }
18373                }
18374            }
18375        }
18376
18377        self.fold_creases(to_fold, true, window, cx);
18378    }
18379
18380    pub fn fold_at(
18381        &mut self,
18382        buffer_row: MultiBufferRow,
18383        window: &mut Window,
18384        cx: &mut Context<Self>,
18385    ) {
18386        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18387
18388        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18389            let autoscroll = self
18390                .selections
18391                .all::<Point>(cx)
18392                .iter()
18393                .any(|selection| crease.range().overlaps(&selection.range()));
18394
18395            self.fold_creases(vec![crease], autoscroll, window, cx);
18396        }
18397    }
18398
18399    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18400        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18401            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18402            let buffer = display_map.buffer_snapshot();
18403            let selections = self.selections.all::<Point>(cx);
18404            let ranges = selections
18405                .iter()
18406                .map(|s| {
18407                    let range = s.display_range(&display_map).sorted();
18408                    let mut start = range.start.to_point(&display_map);
18409                    let mut end = range.end.to_point(&display_map);
18410                    start.column = 0;
18411                    end.column = buffer.line_len(MultiBufferRow(end.row));
18412                    start..end
18413                })
18414                .collect::<Vec<_>>();
18415
18416            self.unfold_ranges(&ranges, true, true, cx);
18417        } else {
18418            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18419            let buffer_ids = self
18420                .selections
18421                .disjoint_anchor_ranges()
18422                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18423                .collect::<HashSet<_>>();
18424            for buffer_id in buffer_ids {
18425                self.unfold_buffer(buffer_id, cx);
18426            }
18427        }
18428    }
18429
18430    pub fn unfold_recursive(
18431        &mut self,
18432        _: &UnfoldRecursive,
18433        _window: &mut Window,
18434        cx: &mut Context<Self>,
18435    ) {
18436        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18437        let selections = self.selections.all::<Point>(cx);
18438        let ranges = selections
18439            .iter()
18440            .map(|s| {
18441                let mut range = s.display_range(&display_map).sorted();
18442                *range.start.column_mut() = 0;
18443                *range.end.column_mut() = display_map.line_len(range.end.row());
18444                let start = range.start.to_point(&display_map);
18445                let end = range.end.to_point(&display_map);
18446                start..end
18447            })
18448            .collect::<Vec<_>>();
18449
18450        self.unfold_ranges(&ranges, true, true, cx);
18451    }
18452
18453    pub fn unfold_at(
18454        &mut self,
18455        buffer_row: MultiBufferRow,
18456        _window: &mut Window,
18457        cx: &mut Context<Self>,
18458    ) {
18459        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18460
18461        let intersection_range = Point::new(buffer_row.0, 0)
18462            ..Point::new(
18463                buffer_row.0,
18464                display_map.buffer_snapshot().line_len(buffer_row),
18465            );
18466
18467        let autoscroll = self
18468            .selections
18469            .all::<Point>(cx)
18470            .iter()
18471            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18472
18473        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18474    }
18475
18476    pub fn unfold_all(
18477        &mut self,
18478        _: &actions::UnfoldAll,
18479        _window: &mut Window,
18480        cx: &mut Context<Self>,
18481    ) {
18482        if self.buffer.read(cx).is_singleton() {
18483            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18484            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18485        } else {
18486            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18487                editor
18488                    .update(cx, |editor, cx| {
18489                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18490                            editor.unfold_buffer(buffer_id, cx);
18491                        }
18492                    })
18493                    .ok();
18494            });
18495        }
18496    }
18497
18498    pub fn fold_selected_ranges(
18499        &mut self,
18500        _: &FoldSelectedRanges,
18501        window: &mut Window,
18502        cx: &mut Context<Self>,
18503    ) {
18504        let selections = self.selections.all_adjusted(cx);
18505        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18506        let ranges = selections
18507            .into_iter()
18508            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18509            .collect::<Vec<_>>();
18510        self.fold_creases(ranges, true, window, cx);
18511    }
18512
18513    pub fn fold_ranges<T: ToOffset + Clone>(
18514        &mut self,
18515        ranges: Vec<Range<T>>,
18516        auto_scroll: bool,
18517        window: &mut Window,
18518        cx: &mut Context<Self>,
18519    ) {
18520        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18521        let ranges = ranges
18522            .into_iter()
18523            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18524            .collect::<Vec<_>>();
18525        self.fold_creases(ranges, auto_scroll, window, cx);
18526    }
18527
18528    pub fn fold_creases<T: ToOffset + Clone>(
18529        &mut self,
18530        creases: Vec<Crease<T>>,
18531        auto_scroll: bool,
18532        _window: &mut Window,
18533        cx: &mut Context<Self>,
18534    ) {
18535        if creases.is_empty() {
18536            return;
18537        }
18538
18539        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18540
18541        if auto_scroll {
18542            self.request_autoscroll(Autoscroll::fit(), cx);
18543        }
18544
18545        cx.notify();
18546
18547        self.scrollbar_marker_state.dirty = true;
18548        self.folds_did_change(cx);
18549    }
18550
18551    /// Removes any folds whose ranges intersect any of the given ranges.
18552    pub fn unfold_ranges<T: ToOffset + Clone>(
18553        &mut self,
18554        ranges: &[Range<T>],
18555        inclusive: bool,
18556        auto_scroll: bool,
18557        cx: &mut Context<Self>,
18558    ) {
18559        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18560            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18561        });
18562        self.folds_did_change(cx);
18563    }
18564
18565    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18566        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18567            return;
18568        }
18569        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18570        self.display_map.update(cx, |display_map, cx| {
18571            display_map.fold_buffers([buffer_id], cx)
18572        });
18573        cx.emit(EditorEvent::BufferFoldToggled {
18574            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18575            folded: true,
18576        });
18577        cx.notify();
18578    }
18579
18580    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18581        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18582            return;
18583        }
18584        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18585        self.display_map.update(cx, |display_map, cx| {
18586            display_map.unfold_buffers([buffer_id], cx);
18587        });
18588        cx.emit(EditorEvent::BufferFoldToggled {
18589            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18590            folded: false,
18591        });
18592        cx.notify();
18593    }
18594
18595    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18596        self.display_map.read(cx).is_buffer_folded(buffer)
18597    }
18598
18599    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18600        self.display_map.read(cx).folded_buffers()
18601    }
18602
18603    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18604        self.display_map.update(cx, |display_map, cx| {
18605            display_map.disable_header_for_buffer(buffer_id, cx);
18606        });
18607        cx.notify();
18608    }
18609
18610    /// Removes any folds with the given ranges.
18611    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18612        &mut self,
18613        ranges: &[Range<T>],
18614        type_id: TypeId,
18615        auto_scroll: bool,
18616        cx: &mut Context<Self>,
18617    ) {
18618        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18619            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18620        });
18621        self.folds_did_change(cx);
18622    }
18623
18624    fn remove_folds_with<T: ToOffset + Clone>(
18625        &mut self,
18626        ranges: &[Range<T>],
18627        auto_scroll: bool,
18628        cx: &mut Context<Self>,
18629        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18630    ) {
18631        if ranges.is_empty() {
18632            return;
18633        }
18634
18635        let mut buffers_affected = HashSet::default();
18636        let multi_buffer = self.buffer().read(cx);
18637        for range in ranges {
18638            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18639                buffers_affected.insert(buffer.read(cx).remote_id());
18640            };
18641        }
18642
18643        self.display_map.update(cx, update);
18644
18645        if auto_scroll {
18646            self.request_autoscroll(Autoscroll::fit(), cx);
18647        }
18648
18649        cx.notify();
18650        self.scrollbar_marker_state.dirty = true;
18651        self.active_indent_guides_state.dirty = true;
18652    }
18653
18654    pub fn update_renderer_widths(
18655        &mut self,
18656        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18657        cx: &mut Context<Self>,
18658    ) -> bool {
18659        self.display_map
18660            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18661    }
18662
18663    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18664        self.display_map.read(cx).fold_placeholder.clone()
18665    }
18666
18667    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18668        self.buffer.update(cx, |buffer, cx| {
18669            buffer.set_all_diff_hunks_expanded(cx);
18670        });
18671    }
18672
18673    pub fn expand_all_diff_hunks(
18674        &mut self,
18675        _: &ExpandAllDiffHunks,
18676        _window: &mut Window,
18677        cx: &mut Context<Self>,
18678    ) {
18679        self.buffer.update(cx, |buffer, cx| {
18680            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18681        });
18682    }
18683
18684    pub fn toggle_selected_diff_hunks(
18685        &mut self,
18686        _: &ToggleSelectedDiffHunks,
18687        _window: &mut Window,
18688        cx: &mut Context<Self>,
18689    ) {
18690        let ranges: Vec<_> = self
18691            .selections
18692            .disjoint_anchors()
18693            .iter()
18694            .map(|s| s.range())
18695            .collect();
18696        self.toggle_diff_hunks_in_ranges(ranges, cx);
18697    }
18698
18699    pub fn diff_hunks_in_ranges<'a>(
18700        &'a self,
18701        ranges: &'a [Range<Anchor>],
18702        buffer: &'a MultiBufferSnapshot,
18703    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18704        ranges.iter().flat_map(move |range| {
18705            let end_excerpt_id = range.end.excerpt_id;
18706            let range = range.to_point(buffer);
18707            let mut peek_end = range.end;
18708            if range.end.row < buffer.max_row().0 {
18709                peek_end = Point::new(range.end.row + 1, 0);
18710            }
18711            buffer
18712                .diff_hunks_in_range(range.start..peek_end)
18713                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18714        })
18715    }
18716
18717    pub fn has_stageable_diff_hunks_in_ranges(
18718        &self,
18719        ranges: &[Range<Anchor>],
18720        snapshot: &MultiBufferSnapshot,
18721    ) -> bool {
18722        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18723        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18724    }
18725
18726    pub fn toggle_staged_selected_diff_hunks(
18727        &mut self,
18728        _: &::git::ToggleStaged,
18729        _: &mut Window,
18730        cx: &mut Context<Self>,
18731    ) {
18732        let snapshot = self.buffer.read(cx).snapshot(cx);
18733        let ranges: Vec<_> = self
18734            .selections
18735            .disjoint_anchors()
18736            .iter()
18737            .map(|s| s.range())
18738            .collect();
18739        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18740        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18741    }
18742
18743    pub fn set_render_diff_hunk_controls(
18744        &mut self,
18745        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18746        cx: &mut Context<Self>,
18747    ) {
18748        self.render_diff_hunk_controls = render_diff_hunk_controls;
18749        cx.notify();
18750    }
18751
18752    pub fn stage_and_next(
18753        &mut self,
18754        _: &::git::StageAndNext,
18755        window: &mut Window,
18756        cx: &mut Context<Self>,
18757    ) {
18758        self.do_stage_or_unstage_and_next(true, window, cx);
18759    }
18760
18761    pub fn unstage_and_next(
18762        &mut self,
18763        _: &::git::UnstageAndNext,
18764        window: &mut Window,
18765        cx: &mut Context<Self>,
18766    ) {
18767        self.do_stage_or_unstage_and_next(false, window, cx);
18768    }
18769
18770    pub fn stage_or_unstage_diff_hunks(
18771        &mut self,
18772        stage: bool,
18773        ranges: Vec<Range<Anchor>>,
18774        cx: &mut Context<Self>,
18775    ) {
18776        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18777        cx.spawn(async move |this, cx| {
18778            task.await?;
18779            this.update(cx, |this, cx| {
18780                let snapshot = this.buffer.read(cx).snapshot(cx);
18781                let chunk_by = this
18782                    .diff_hunks_in_ranges(&ranges, &snapshot)
18783                    .chunk_by(|hunk| hunk.buffer_id);
18784                for (buffer_id, hunks) in &chunk_by {
18785                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18786                }
18787            })
18788        })
18789        .detach_and_log_err(cx);
18790    }
18791
18792    fn save_buffers_for_ranges_if_needed(
18793        &mut self,
18794        ranges: &[Range<Anchor>],
18795        cx: &mut Context<Editor>,
18796    ) -> Task<Result<()>> {
18797        let multibuffer = self.buffer.read(cx);
18798        let snapshot = multibuffer.read(cx);
18799        let buffer_ids: HashSet<_> = ranges
18800            .iter()
18801            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18802            .collect();
18803        drop(snapshot);
18804
18805        let mut buffers = HashSet::default();
18806        for buffer_id in buffer_ids {
18807            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18808                let buffer = buffer_entity.read(cx);
18809                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18810                {
18811                    buffers.insert(buffer_entity);
18812                }
18813            }
18814        }
18815
18816        if let Some(project) = &self.project {
18817            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18818        } else {
18819            Task::ready(Ok(()))
18820        }
18821    }
18822
18823    fn do_stage_or_unstage_and_next(
18824        &mut self,
18825        stage: bool,
18826        window: &mut Window,
18827        cx: &mut Context<Self>,
18828    ) {
18829        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18830
18831        if ranges.iter().any(|range| range.start != range.end) {
18832            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18833            return;
18834        }
18835
18836        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18837        let snapshot = self.snapshot(window, cx);
18838        let position = self.selections.newest::<Point>(cx).head();
18839        let mut row = snapshot
18840            .buffer_snapshot()
18841            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18842            .find(|hunk| hunk.row_range.start.0 > position.row)
18843            .map(|hunk| hunk.row_range.start);
18844
18845        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18846        // Outside of the project diff editor, wrap around to the beginning.
18847        if !all_diff_hunks_expanded {
18848            row = row.or_else(|| {
18849                snapshot
18850                    .buffer_snapshot()
18851                    .diff_hunks_in_range(Point::zero()..position)
18852                    .find(|hunk| hunk.row_range.end.0 < position.row)
18853                    .map(|hunk| hunk.row_range.start)
18854            });
18855        }
18856
18857        if let Some(row) = row {
18858            let destination = Point::new(row.0, 0);
18859            let autoscroll = Autoscroll::center();
18860
18861            self.unfold_ranges(&[destination..destination], false, false, cx);
18862            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18863                s.select_ranges([destination..destination]);
18864            });
18865        }
18866    }
18867
18868    fn do_stage_or_unstage(
18869        &self,
18870        stage: bool,
18871        buffer_id: BufferId,
18872        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18873        cx: &mut App,
18874    ) -> Option<()> {
18875        let project = self.project()?;
18876        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18877        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18878        let buffer_snapshot = buffer.read(cx).snapshot();
18879        let file_exists = buffer_snapshot
18880            .file()
18881            .is_some_and(|file| file.disk_state().exists());
18882        diff.update(cx, |diff, cx| {
18883            diff.stage_or_unstage_hunks(
18884                stage,
18885                &hunks
18886                    .map(|hunk| buffer_diff::DiffHunk {
18887                        buffer_range: hunk.buffer_range,
18888                        diff_base_byte_range: hunk.diff_base_byte_range,
18889                        secondary_status: hunk.secondary_status,
18890                        range: Point::zero()..Point::zero(), // unused
18891                    })
18892                    .collect::<Vec<_>>(),
18893                &buffer_snapshot,
18894                file_exists,
18895                cx,
18896            )
18897        });
18898        None
18899    }
18900
18901    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18902        let ranges: Vec<_> = self
18903            .selections
18904            .disjoint_anchors()
18905            .iter()
18906            .map(|s| s.range())
18907            .collect();
18908        self.buffer
18909            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18910    }
18911
18912    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18913        self.buffer.update(cx, |buffer, cx| {
18914            let ranges = vec![Anchor::min()..Anchor::max()];
18915            if !buffer.all_diff_hunks_expanded()
18916                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18917            {
18918                buffer.collapse_diff_hunks(ranges, cx);
18919                true
18920            } else {
18921                false
18922            }
18923        })
18924    }
18925
18926    fn toggle_diff_hunks_in_ranges(
18927        &mut self,
18928        ranges: Vec<Range<Anchor>>,
18929        cx: &mut Context<Editor>,
18930    ) {
18931        self.buffer.update(cx, |buffer, cx| {
18932            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18933            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18934        })
18935    }
18936
18937    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18938        self.buffer.update(cx, |buffer, cx| {
18939            let snapshot = buffer.snapshot(cx);
18940            let excerpt_id = range.end.excerpt_id;
18941            let point_range = range.to_point(&snapshot);
18942            let expand = !buffer.single_hunk_is_expanded(range, cx);
18943            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18944        })
18945    }
18946
18947    pub(crate) fn apply_all_diff_hunks(
18948        &mut self,
18949        _: &ApplyAllDiffHunks,
18950        window: &mut Window,
18951        cx: &mut Context<Self>,
18952    ) {
18953        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18954
18955        let buffers = self.buffer.read(cx).all_buffers();
18956        for branch_buffer in buffers {
18957            branch_buffer.update(cx, |branch_buffer, cx| {
18958                branch_buffer.merge_into_base(Vec::new(), cx);
18959            });
18960        }
18961
18962        if let Some(project) = self.project.clone() {
18963            self.save(
18964                SaveOptions {
18965                    format: true,
18966                    autosave: false,
18967                },
18968                project,
18969                window,
18970                cx,
18971            )
18972            .detach_and_log_err(cx);
18973        }
18974    }
18975
18976    pub(crate) fn apply_selected_diff_hunks(
18977        &mut self,
18978        _: &ApplyDiffHunk,
18979        window: &mut Window,
18980        cx: &mut Context<Self>,
18981    ) {
18982        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18983        let snapshot = self.snapshot(window, cx);
18984        let hunks = snapshot.hunks_for_ranges(
18985            self.selections
18986                .all(cx)
18987                .into_iter()
18988                .map(|selection| selection.range()),
18989        );
18990        let mut ranges_by_buffer = HashMap::default();
18991        self.transact(window, cx, |editor, _window, cx| {
18992            for hunk in hunks {
18993                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18994                    ranges_by_buffer
18995                        .entry(buffer.clone())
18996                        .or_insert_with(Vec::new)
18997                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18998                }
18999            }
19000
19001            for (buffer, ranges) in ranges_by_buffer {
19002                buffer.update(cx, |buffer, cx| {
19003                    buffer.merge_into_base(ranges, cx);
19004                });
19005            }
19006        });
19007
19008        if let Some(project) = self.project.clone() {
19009            self.save(
19010                SaveOptions {
19011                    format: true,
19012                    autosave: false,
19013                },
19014                project,
19015                window,
19016                cx,
19017            )
19018            .detach_and_log_err(cx);
19019        }
19020    }
19021
19022    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19023        if hovered != self.gutter_hovered {
19024            self.gutter_hovered = hovered;
19025            cx.notify();
19026        }
19027    }
19028
19029    pub fn insert_blocks(
19030        &mut self,
19031        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19032        autoscroll: Option<Autoscroll>,
19033        cx: &mut Context<Self>,
19034    ) -> Vec<CustomBlockId> {
19035        let blocks = self
19036            .display_map
19037            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19038        if let Some(autoscroll) = autoscroll {
19039            self.request_autoscroll(autoscroll, cx);
19040        }
19041        cx.notify();
19042        blocks
19043    }
19044
19045    pub fn resize_blocks(
19046        &mut self,
19047        heights: HashMap<CustomBlockId, u32>,
19048        autoscroll: Option<Autoscroll>,
19049        cx: &mut Context<Self>,
19050    ) {
19051        self.display_map
19052            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19053        if let Some(autoscroll) = autoscroll {
19054            self.request_autoscroll(autoscroll, cx);
19055        }
19056        cx.notify();
19057    }
19058
19059    pub fn replace_blocks(
19060        &mut self,
19061        renderers: HashMap<CustomBlockId, RenderBlock>,
19062        autoscroll: Option<Autoscroll>,
19063        cx: &mut Context<Self>,
19064    ) {
19065        self.display_map
19066            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19067        if let Some(autoscroll) = autoscroll {
19068            self.request_autoscroll(autoscroll, cx);
19069        }
19070        cx.notify();
19071    }
19072
19073    pub fn remove_blocks(
19074        &mut self,
19075        block_ids: HashSet<CustomBlockId>,
19076        autoscroll: Option<Autoscroll>,
19077        cx: &mut Context<Self>,
19078    ) {
19079        self.display_map.update(cx, |display_map, cx| {
19080            display_map.remove_blocks(block_ids, cx)
19081        });
19082        if let Some(autoscroll) = autoscroll {
19083            self.request_autoscroll(autoscroll, cx);
19084        }
19085        cx.notify();
19086    }
19087
19088    pub fn row_for_block(
19089        &self,
19090        block_id: CustomBlockId,
19091        cx: &mut Context<Self>,
19092    ) -> Option<DisplayRow> {
19093        self.display_map
19094            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19095    }
19096
19097    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19098        self.focused_block = Some(focused_block);
19099    }
19100
19101    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19102        self.focused_block.take()
19103    }
19104
19105    pub fn insert_creases(
19106        &mut self,
19107        creases: impl IntoIterator<Item = Crease<Anchor>>,
19108        cx: &mut Context<Self>,
19109    ) -> Vec<CreaseId> {
19110        self.display_map
19111            .update(cx, |map, cx| map.insert_creases(creases, cx))
19112    }
19113
19114    pub fn remove_creases(
19115        &mut self,
19116        ids: impl IntoIterator<Item = CreaseId>,
19117        cx: &mut Context<Self>,
19118    ) -> Vec<(CreaseId, Range<Anchor>)> {
19119        self.display_map
19120            .update(cx, |map, cx| map.remove_creases(ids, cx))
19121    }
19122
19123    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19124        self.display_map
19125            .update(cx, |map, cx| map.snapshot(cx))
19126            .longest_row()
19127    }
19128
19129    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19130        self.display_map
19131            .update(cx, |map, cx| map.snapshot(cx))
19132            .max_point()
19133    }
19134
19135    pub fn text(&self, cx: &App) -> String {
19136        self.buffer.read(cx).read(cx).text()
19137    }
19138
19139    pub fn is_empty(&self, cx: &App) -> bool {
19140        self.buffer.read(cx).read(cx).is_empty()
19141    }
19142
19143    pub fn text_option(&self, cx: &App) -> Option<String> {
19144        let text = self.text(cx);
19145        let text = text.trim();
19146
19147        if text.is_empty() {
19148            return None;
19149        }
19150
19151        Some(text.to_string())
19152    }
19153
19154    pub fn set_text(
19155        &mut self,
19156        text: impl Into<Arc<str>>,
19157        window: &mut Window,
19158        cx: &mut Context<Self>,
19159    ) {
19160        self.transact(window, cx, |this, _, cx| {
19161            this.buffer
19162                .read(cx)
19163                .as_singleton()
19164                .expect("you can only call set_text on editors for singleton buffers")
19165                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19166        });
19167    }
19168
19169    pub fn display_text(&self, cx: &mut App) -> String {
19170        self.display_map
19171            .update(cx, |map, cx| map.snapshot(cx))
19172            .text()
19173    }
19174
19175    fn create_minimap(
19176        &self,
19177        minimap_settings: MinimapSettings,
19178        window: &mut Window,
19179        cx: &mut Context<Self>,
19180    ) -> Option<Entity<Self>> {
19181        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19182            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19183    }
19184
19185    fn initialize_new_minimap(
19186        &self,
19187        minimap_settings: MinimapSettings,
19188        window: &mut Window,
19189        cx: &mut Context<Self>,
19190    ) -> Entity<Self> {
19191        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19192
19193        let mut minimap = Editor::new_internal(
19194            EditorMode::Minimap {
19195                parent: cx.weak_entity(),
19196            },
19197            self.buffer.clone(),
19198            None,
19199            Some(self.display_map.clone()),
19200            window,
19201            cx,
19202        );
19203        minimap.scroll_manager.clone_state(&self.scroll_manager);
19204        minimap.set_text_style_refinement(TextStyleRefinement {
19205            font_size: Some(MINIMAP_FONT_SIZE),
19206            font_weight: Some(MINIMAP_FONT_WEIGHT),
19207            ..Default::default()
19208        });
19209        minimap.update_minimap_configuration(minimap_settings, cx);
19210        cx.new(|_| minimap)
19211    }
19212
19213    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19214        let current_line_highlight = minimap_settings
19215            .current_line_highlight
19216            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19217        self.set_current_line_highlight(Some(current_line_highlight));
19218    }
19219
19220    pub fn minimap(&self) -> Option<&Entity<Self>> {
19221        self.minimap
19222            .as_ref()
19223            .filter(|_| self.minimap_visibility.visible())
19224    }
19225
19226    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19227        let mut wrap_guides = smallvec![];
19228
19229        if self.show_wrap_guides == Some(false) {
19230            return wrap_guides;
19231        }
19232
19233        let settings = self.buffer.read(cx).language_settings(cx);
19234        if settings.show_wrap_guides {
19235            match self.soft_wrap_mode(cx) {
19236                SoftWrap::Column(soft_wrap) => {
19237                    wrap_guides.push((soft_wrap as usize, true));
19238                }
19239                SoftWrap::Bounded(soft_wrap) => {
19240                    wrap_guides.push((soft_wrap as usize, true));
19241                }
19242                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19243            }
19244            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19245        }
19246
19247        wrap_guides
19248    }
19249
19250    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19251        let settings = self.buffer.read(cx).language_settings(cx);
19252        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19253        match mode {
19254            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19255                SoftWrap::None
19256            }
19257            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19258            language_settings::SoftWrap::PreferredLineLength => {
19259                SoftWrap::Column(settings.preferred_line_length)
19260            }
19261            language_settings::SoftWrap::Bounded => {
19262                SoftWrap::Bounded(settings.preferred_line_length)
19263            }
19264        }
19265    }
19266
19267    pub fn set_soft_wrap_mode(
19268        &mut self,
19269        mode: language_settings::SoftWrap,
19270
19271        cx: &mut Context<Self>,
19272    ) {
19273        self.soft_wrap_mode_override = Some(mode);
19274        cx.notify();
19275    }
19276
19277    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19278        self.hard_wrap = hard_wrap;
19279        cx.notify();
19280    }
19281
19282    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19283        self.text_style_refinement = Some(style);
19284    }
19285
19286    /// called by the Element so we know what style we were most recently rendered with.
19287    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19288        // We intentionally do not inform the display map about the minimap style
19289        // so that wrapping is not recalculated and stays consistent for the editor
19290        // and its linked minimap.
19291        if !self.mode.is_minimap() {
19292            let font = style.text.font();
19293            let font_size = style.text.font_size.to_pixels(window.rem_size());
19294            let display_map = self
19295                .placeholder_display_map
19296                .as_ref()
19297                .filter(|_| self.is_empty(cx))
19298                .unwrap_or(&self.display_map);
19299
19300            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19301        }
19302        self.style = Some(style);
19303    }
19304
19305    pub fn style(&self) -> Option<&EditorStyle> {
19306        self.style.as_ref()
19307    }
19308
19309    // Called by the element. This method is not designed to be called outside of the editor
19310    // element's layout code because it does not notify when rewrapping is computed synchronously.
19311    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19312        if self.is_empty(cx) {
19313            self.placeholder_display_map
19314                .as_ref()
19315                .map_or(false, |display_map| {
19316                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19317                })
19318        } else {
19319            self.display_map
19320                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19321        }
19322    }
19323
19324    pub fn set_soft_wrap(&mut self) {
19325        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19326    }
19327
19328    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19329        if self.soft_wrap_mode_override.is_some() {
19330            self.soft_wrap_mode_override.take();
19331        } else {
19332            let soft_wrap = match self.soft_wrap_mode(cx) {
19333                SoftWrap::GitDiff => return,
19334                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19335                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19336                    language_settings::SoftWrap::None
19337                }
19338            };
19339            self.soft_wrap_mode_override = Some(soft_wrap);
19340        }
19341        cx.notify();
19342    }
19343
19344    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19345        let Some(workspace) = self.workspace() else {
19346            return;
19347        };
19348        let fs = workspace.read(cx).app_state().fs.clone();
19349        let current_show = TabBarSettings::get_global(cx).show;
19350        update_settings_file(fs, cx, move |setting, _| {
19351            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19352        });
19353    }
19354
19355    pub fn toggle_indent_guides(
19356        &mut self,
19357        _: &ToggleIndentGuides,
19358        _: &mut Window,
19359        cx: &mut Context<Self>,
19360    ) {
19361        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19362            self.buffer
19363                .read(cx)
19364                .language_settings(cx)
19365                .indent_guides
19366                .enabled
19367        });
19368        self.show_indent_guides = Some(!currently_enabled);
19369        cx.notify();
19370    }
19371
19372    fn should_show_indent_guides(&self) -> Option<bool> {
19373        self.show_indent_guides
19374    }
19375
19376    pub fn toggle_line_numbers(
19377        &mut self,
19378        _: &ToggleLineNumbers,
19379        _: &mut Window,
19380        cx: &mut Context<Self>,
19381    ) {
19382        let mut editor_settings = EditorSettings::get_global(cx).clone();
19383        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19384        EditorSettings::override_global(editor_settings, cx);
19385    }
19386
19387    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19388        if let Some(show_line_numbers) = self.show_line_numbers {
19389            return show_line_numbers;
19390        }
19391        EditorSettings::get_global(cx).gutter.line_numbers
19392    }
19393
19394    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19395        self.use_relative_line_numbers
19396            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19397    }
19398
19399    pub fn toggle_relative_line_numbers(
19400        &mut self,
19401        _: &ToggleRelativeLineNumbers,
19402        _: &mut Window,
19403        cx: &mut Context<Self>,
19404    ) {
19405        let is_relative = self.should_use_relative_line_numbers(cx);
19406        self.set_relative_line_number(Some(!is_relative), cx)
19407    }
19408
19409    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19410        self.use_relative_line_numbers = is_relative;
19411        cx.notify();
19412    }
19413
19414    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19415        self.show_gutter = show_gutter;
19416        cx.notify();
19417    }
19418
19419    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19420        self.show_scrollbars = ScrollbarAxes {
19421            horizontal: show,
19422            vertical: show,
19423        };
19424        cx.notify();
19425    }
19426
19427    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19428        self.show_scrollbars.vertical = show;
19429        cx.notify();
19430    }
19431
19432    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19433        self.show_scrollbars.horizontal = show;
19434        cx.notify();
19435    }
19436
19437    pub fn set_minimap_visibility(
19438        &mut self,
19439        minimap_visibility: MinimapVisibility,
19440        window: &mut Window,
19441        cx: &mut Context<Self>,
19442    ) {
19443        if self.minimap_visibility != minimap_visibility {
19444            if minimap_visibility.visible() && self.minimap.is_none() {
19445                let minimap_settings = EditorSettings::get_global(cx).minimap;
19446                self.minimap =
19447                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19448            }
19449            self.minimap_visibility = minimap_visibility;
19450            cx.notify();
19451        }
19452    }
19453
19454    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19455        self.set_show_scrollbars(false, cx);
19456        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19457    }
19458
19459    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19460        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19461    }
19462
19463    /// Normally the text in full mode and auto height editors is padded on the
19464    /// left side by roughly half a character width for improved hit testing.
19465    ///
19466    /// Use this method to disable this for cases where this is not wanted (e.g.
19467    /// if you want to align the editor text with some other text above or below)
19468    /// or if you want to add this padding to single-line editors.
19469    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19470        self.offset_content = offset_content;
19471        cx.notify();
19472    }
19473
19474    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19475        self.show_line_numbers = Some(show_line_numbers);
19476        cx.notify();
19477    }
19478
19479    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19480        self.disable_expand_excerpt_buttons = true;
19481        cx.notify();
19482    }
19483
19484    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19485        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19486        cx.notify();
19487    }
19488
19489    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19490        self.show_code_actions = Some(show_code_actions);
19491        cx.notify();
19492    }
19493
19494    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19495        self.show_runnables = Some(show_runnables);
19496        cx.notify();
19497    }
19498
19499    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19500        self.show_breakpoints = Some(show_breakpoints);
19501        cx.notify();
19502    }
19503
19504    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19505        if self.display_map.read(cx).masked != masked {
19506            self.display_map.update(cx, |map, _| map.masked = masked);
19507        }
19508        cx.notify()
19509    }
19510
19511    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19512        self.show_wrap_guides = Some(show_wrap_guides);
19513        cx.notify();
19514    }
19515
19516    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19517        self.show_indent_guides = Some(show_indent_guides);
19518        cx.notify();
19519    }
19520
19521    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19522        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19523            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19524                && let Some(dir) = file.abs_path(cx).parent()
19525            {
19526                return Some(dir.to_owned());
19527            }
19528        }
19529
19530        None
19531    }
19532
19533    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19534        self.active_excerpt(cx)?
19535            .1
19536            .read(cx)
19537            .file()
19538            .and_then(|f| f.as_local())
19539    }
19540
19541    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19542        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19543            let buffer = buffer.read(cx);
19544            if let Some(project_path) = buffer.project_path(cx) {
19545                let project = self.project()?.read(cx);
19546                project.absolute_path(&project_path, cx)
19547            } else {
19548                buffer
19549                    .file()
19550                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19551            }
19552        })
19553    }
19554
19555    pub fn reveal_in_finder(
19556        &mut self,
19557        _: &RevealInFileManager,
19558        _window: &mut Window,
19559        cx: &mut Context<Self>,
19560    ) {
19561        if let Some(target) = self.target_file(cx) {
19562            cx.reveal_path(&target.abs_path(cx));
19563        }
19564    }
19565
19566    pub fn copy_path(
19567        &mut self,
19568        _: &zed_actions::workspace::CopyPath,
19569        _window: &mut Window,
19570        cx: &mut Context<Self>,
19571    ) {
19572        if let Some(path) = self.target_file_abs_path(cx)
19573            && let Some(path) = path.to_str()
19574        {
19575            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19576        } else {
19577            cx.propagate();
19578        }
19579    }
19580
19581    pub fn copy_relative_path(
19582        &mut self,
19583        _: &zed_actions::workspace::CopyRelativePath,
19584        _window: &mut Window,
19585        cx: &mut Context<Self>,
19586    ) {
19587        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19588            let project = self.project()?.read(cx);
19589            let path = buffer.read(cx).file()?.path();
19590            let path = path.display(project.path_style(cx));
19591            Some(path)
19592        }) {
19593            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19594        } else {
19595            cx.propagate();
19596        }
19597    }
19598
19599    /// Returns the project path for the editor's buffer, if any buffer is
19600    /// opened in the editor.
19601    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19602        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19603            buffer.read(cx).project_path(cx)
19604        } else {
19605            None
19606        }
19607    }
19608
19609    // Returns true if the editor handled a go-to-line request
19610    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19611        maybe!({
19612            let breakpoint_store = self.breakpoint_store.as_ref()?;
19613
19614            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19615            else {
19616                self.clear_row_highlights::<ActiveDebugLine>();
19617                return None;
19618            };
19619
19620            let position = active_stack_frame.position;
19621            let buffer_id = position.buffer_id?;
19622            let snapshot = self
19623                .project
19624                .as_ref()?
19625                .read(cx)
19626                .buffer_for_id(buffer_id, cx)?
19627                .read(cx)
19628                .snapshot();
19629
19630            let mut handled = false;
19631            for (id, ExcerptRange { context, .. }) in
19632                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19633            {
19634                if context.start.cmp(&position, &snapshot).is_ge()
19635                    || context.end.cmp(&position, &snapshot).is_lt()
19636                {
19637                    continue;
19638                }
19639                let snapshot = self.buffer.read(cx).snapshot(cx);
19640                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19641
19642                handled = true;
19643                self.clear_row_highlights::<ActiveDebugLine>();
19644
19645                self.go_to_line::<ActiveDebugLine>(
19646                    multibuffer_anchor,
19647                    Some(cx.theme().colors().editor_debugger_active_line_background),
19648                    window,
19649                    cx,
19650                );
19651
19652                cx.notify();
19653            }
19654
19655            handled.then_some(())
19656        })
19657        .is_some()
19658    }
19659
19660    pub fn copy_file_name_without_extension(
19661        &mut self,
19662        _: &CopyFileNameWithoutExtension,
19663        _: &mut Window,
19664        cx: &mut Context<Self>,
19665    ) {
19666        if let Some(file) = self.target_file(cx)
19667            && let Some(file_stem) = file.path().file_stem()
19668        {
19669            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19670        }
19671    }
19672
19673    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19674        if let Some(file) = self.target_file(cx)
19675            && let Some(name) = file.path().file_name()
19676        {
19677            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19678        }
19679    }
19680
19681    pub fn toggle_git_blame(
19682        &mut self,
19683        _: &::git::Blame,
19684        window: &mut Window,
19685        cx: &mut Context<Self>,
19686    ) {
19687        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19688
19689        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19690            self.start_git_blame(true, window, cx);
19691        }
19692
19693        cx.notify();
19694    }
19695
19696    pub fn toggle_git_blame_inline(
19697        &mut self,
19698        _: &ToggleGitBlameInline,
19699        window: &mut Window,
19700        cx: &mut Context<Self>,
19701    ) {
19702        self.toggle_git_blame_inline_internal(true, window, cx);
19703        cx.notify();
19704    }
19705
19706    pub fn open_git_blame_commit(
19707        &mut self,
19708        _: &OpenGitBlameCommit,
19709        window: &mut Window,
19710        cx: &mut Context<Self>,
19711    ) {
19712        self.open_git_blame_commit_internal(window, cx);
19713    }
19714
19715    fn open_git_blame_commit_internal(
19716        &mut self,
19717        window: &mut Window,
19718        cx: &mut Context<Self>,
19719    ) -> Option<()> {
19720        let blame = self.blame.as_ref()?;
19721        let snapshot = self.snapshot(window, cx);
19722        let cursor = self.selections.newest::<Point>(cx).head();
19723        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19724        let (_, blame_entry) = blame
19725            .update(cx, |blame, cx| {
19726                blame
19727                    .blame_for_rows(
19728                        &[RowInfo {
19729                            buffer_id: Some(buffer.remote_id()),
19730                            buffer_row: Some(point.row),
19731                            ..Default::default()
19732                        }],
19733                        cx,
19734                    )
19735                    .next()
19736            })
19737            .flatten()?;
19738        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19739        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19740        let workspace = self.workspace()?.downgrade();
19741        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19742        None
19743    }
19744
19745    pub fn git_blame_inline_enabled(&self) -> bool {
19746        self.git_blame_inline_enabled
19747    }
19748
19749    pub fn toggle_selection_menu(
19750        &mut self,
19751        _: &ToggleSelectionMenu,
19752        _: &mut Window,
19753        cx: &mut Context<Self>,
19754    ) {
19755        self.show_selection_menu = self
19756            .show_selection_menu
19757            .map(|show_selections_menu| !show_selections_menu)
19758            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19759
19760        cx.notify();
19761    }
19762
19763    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19764        self.show_selection_menu
19765            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19766    }
19767
19768    fn start_git_blame(
19769        &mut self,
19770        user_triggered: bool,
19771        window: &mut Window,
19772        cx: &mut Context<Self>,
19773    ) {
19774        if let Some(project) = self.project() {
19775            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19776                && buffer.read(cx).file().is_none()
19777            {
19778                return;
19779            }
19780
19781            let focused = self.focus_handle(cx).contains_focused(window, cx);
19782
19783            let project = project.clone();
19784            let blame = cx
19785                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19786            self.blame_subscription =
19787                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19788            self.blame = Some(blame);
19789        }
19790    }
19791
19792    fn toggle_git_blame_inline_internal(
19793        &mut self,
19794        user_triggered: bool,
19795        window: &mut Window,
19796        cx: &mut Context<Self>,
19797    ) {
19798        if self.git_blame_inline_enabled {
19799            self.git_blame_inline_enabled = false;
19800            self.show_git_blame_inline = false;
19801            self.show_git_blame_inline_delay_task.take();
19802        } else {
19803            self.git_blame_inline_enabled = true;
19804            self.start_git_blame_inline(user_triggered, window, cx);
19805        }
19806
19807        cx.notify();
19808    }
19809
19810    fn start_git_blame_inline(
19811        &mut self,
19812        user_triggered: bool,
19813        window: &mut Window,
19814        cx: &mut Context<Self>,
19815    ) {
19816        self.start_git_blame(user_triggered, window, cx);
19817
19818        if ProjectSettings::get_global(cx)
19819            .git
19820            .inline_blame_delay()
19821            .is_some()
19822        {
19823            self.start_inline_blame_timer(window, cx);
19824        } else {
19825            self.show_git_blame_inline = true
19826        }
19827    }
19828
19829    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19830        self.blame.as_ref()
19831    }
19832
19833    pub fn show_git_blame_gutter(&self) -> bool {
19834        self.show_git_blame_gutter
19835    }
19836
19837    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19838        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19839    }
19840
19841    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19842        self.show_git_blame_inline
19843            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19844            && !self.newest_selection_head_on_empty_line(cx)
19845            && self.has_blame_entries(cx)
19846    }
19847
19848    fn has_blame_entries(&self, cx: &App) -> bool {
19849        self.blame()
19850            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19851    }
19852
19853    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19854        let cursor_anchor = self.selections.newest_anchor().head();
19855
19856        let snapshot = self.buffer.read(cx).snapshot(cx);
19857        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19858
19859        snapshot.line_len(buffer_row) == 0
19860    }
19861
19862    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19863        let buffer_and_selection = maybe!({
19864            let selection = self.selections.newest::<Point>(cx);
19865            let selection_range = selection.range();
19866
19867            let multi_buffer = self.buffer().read(cx);
19868            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19869            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19870
19871            let (buffer, range, _) = if selection.reversed {
19872                buffer_ranges.first()
19873            } else {
19874                buffer_ranges.last()
19875            }?;
19876
19877            let selection = text::ToPoint::to_point(&range.start, buffer).row
19878                ..text::ToPoint::to_point(&range.end, buffer).row;
19879            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19880        });
19881
19882        let Some((buffer, selection)) = buffer_and_selection else {
19883            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19884        };
19885
19886        let Some(project) = self.project() else {
19887            return Task::ready(Err(anyhow!("editor does not have project")));
19888        };
19889
19890        project.update(cx, |project, cx| {
19891            project.get_permalink_to_line(&buffer, selection, cx)
19892        })
19893    }
19894
19895    pub fn copy_permalink_to_line(
19896        &mut self,
19897        _: &CopyPermalinkToLine,
19898        window: &mut Window,
19899        cx: &mut Context<Self>,
19900    ) {
19901        let permalink_task = self.get_permalink_to_line(cx);
19902        let workspace = self.workspace();
19903
19904        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19905            Ok(permalink) => {
19906                cx.update(|_, cx| {
19907                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19908                })
19909                .ok();
19910            }
19911            Err(err) => {
19912                let message = format!("Failed to copy permalink: {err}");
19913
19914                anyhow::Result::<()>::Err(err).log_err();
19915
19916                if let Some(workspace) = workspace {
19917                    workspace
19918                        .update_in(cx, |workspace, _, cx| {
19919                            struct CopyPermalinkToLine;
19920
19921                            workspace.show_toast(
19922                                Toast::new(
19923                                    NotificationId::unique::<CopyPermalinkToLine>(),
19924                                    message,
19925                                ),
19926                                cx,
19927                            )
19928                        })
19929                        .ok();
19930                }
19931            }
19932        })
19933        .detach();
19934    }
19935
19936    pub fn copy_file_location(
19937        &mut self,
19938        _: &CopyFileLocation,
19939        _: &mut Window,
19940        cx: &mut Context<Self>,
19941    ) {
19942        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19943        if let Some(file) = self.target_file(cx) {
19944            let path = file.path().display(file.path_style(cx));
19945            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19946        }
19947    }
19948
19949    pub fn open_permalink_to_line(
19950        &mut self,
19951        _: &OpenPermalinkToLine,
19952        window: &mut Window,
19953        cx: &mut Context<Self>,
19954    ) {
19955        let permalink_task = self.get_permalink_to_line(cx);
19956        let workspace = self.workspace();
19957
19958        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19959            Ok(permalink) => {
19960                cx.update(|_, cx| {
19961                    cx.open_url(permalink.as_ref());
19962                })
19963                .ok();
19964            }
19965            Err(err) => {
19966                let message = format!("Failed to open permalink: {err}");
19967
19968                anyhow::Result::<()>::Err(err).log_err();
19969
19970                if let Some(workspace) = workspace {
19971                    workspace
19972                        .update(cx, |workspace, cx| {
19973                            struct OpenPermalinkToLine;
19974
19975                            workspace.show_toast(
19976                                Toast::new(
19977                                    NotificationId::unique::<OpenPermalinkToLine>(),
19978                                    message,
19979                                ),
19980                                cx,
19981                            )
19982                        })
19983                        .ok();
19984                }
19985            }
19986        })
19987        .detach();
19988    }
19989
19990    pub fn insert_uuid_v4(
19991        &mut self,
19992        _: &InsertUuidV4,
19993        window: &mut Window,
19994        cx: &mut Context<Self>,
19995    ) {
19996        self.insert_uuid(UuidVersion::V4, window, cx);
19997    }
19998
19999    pub fn insert_uuid_v7(
20000        &mut self,
20001        _: &InsertUuidV7,
20002        window: &mut Window,
20003        cx: &mut Context<Self>,
20004    ) {
20005        self.insert_uuid(UuidVersion::V7, window, cx);
20006    }
20007
20008    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20009        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20010        self.transact(window, cx, |this, window, cx| {
20011            let edits = this
20012                .selections
20013                .all::<Point>(cx)
20014                .into_iter()
20015                .map(|selection| {
20016                    let uuid = match version {
20017                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20018                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20019                    };
20020
20021                    (selection.range(), uuid.to_string())
20022                });
20023            this.edit(edits, cx);
20024            this.refresh_edit_prediction(true, false, window, cx);
20025        });
20026    }
20027
20028    pub fn open_selections_in_multibuffer(
20029        &mut self,
20030        _: &OpenSelectionsInMultibuffer,
20031        window: &mut Window,
20032        cx: &mut Context<Self>,
20033    ) {
20034        let multibuffer = self.buffer.read(cx);
20035
20036        let Some(buffer) = multibuffer.as_singleton() else {
20037            return;
20038        };
20039
20040        let Some(workspace) = self.workspace() else {
20041            return;
20042        };
20043
20044        let title = multibuffer.title(cx).to_string();
20045
20046        let locations = self
20047            .selections
20048            .all_anchors(cx)
20049            .iter()
20050            .map(|selection| {
20051                (
20052                    buffer.clone(),
20053                    (selection.start.text_anchor..selection.end.text_anchor)
20054                        .to_point(buffer.read(cx)),
20055                )
20056            })
20057            .into_group_map();
20058
20059        cx.spawn_in(window, async move |_, cx| {
20060            workspace.update_in(cx, |workspace, window, cx| {
20061                Self::open_locations_in_multibuffer(
20062                    workspace,
20063                    locations,
20064                    format!("Selections for '{title}'"),
20065                    false,
20066                    MultibufferSelectionMode::All,
20067                    window,
20068                    cx,
20069                );
20070            })
20071        })
20072        .detach();
20073    }
20074
20075    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20076    /// last highlight added will be used.
20077    ///
20078    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20079    pub fn highlight_rows<T: 'static>(
20080        &mut self,
20081        range: Range<Anchor>,
20082        color: Hsla,
20083        options: RowHighlightOptions,
20084        cx: &mut Context<Self>,
20085    ) {
20086        let snapshot = self.buffer().read(cx).snapshot(cx);
20087        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20088        let ix = row_highlights.binary_search_by(|highlight| {
20089            Ordering::Equal
20090                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20091                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20092        });
20093
20094        if let Err(mut ix) = ix {
20095            let index = post_inc(&mut self.highlight_order);
20096
20097            // If this range intersects with the preceding highlight, then merge it with
20098            // the preceding highlight. Otherwise insert a new highlight.
20099            let mut merged = false;
20100            if ix > 0 {
20101                let prev_highlight = &mut row_highlights[ix - 1];
20102                if prev_highlight
20103                    .range
20104                    .end
20105                    .cmp(&range.start, &snapshot)
20106                    .is_ge()
20107                {
20108                    ix -= 1;
20109                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20110                        prev_highlight.range.end = range.end;
20111                    }
20112                    merged = true;
20113                    prev_highlight.index = index;
20114                    prev_highlight.color = color;
20115                    prev_highlight.options = options;
20116                }
20117            }
20118
20119            if !merged {
20120                row_highlights.insert(
20121                    ix,
20122                    RowHighlight {
20123                        range,
20124                        index,
20125                        color,
20126                        options,
20127                        type_id: TypeId::of::<T>(),
20128                    },
20129                );
20130            }
20131
20132            // If any of the following highlights intersect with this one, merge them.
20133            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20134                let highlight = &row_highlights[ix];
20135                if next_highlight
20136                    .range
20137                    .start
20138                    .cmp(&highlight.range.end, &snapshot)
20139                    .is_le()
20140                {
20141                    if next_highlight
20142                        .range
20143                        .end
20144                        .cmp(&highlight.range.end, &snapshot)
20145                        .is_gt()
20146                    {
20147                        row_highlights[ix].range.end = next_highlight.range.end;
20148                    }
20149                    row_highlights.remove(ix + 1);
20150                } else {
20151                    break;
20152                }
20153            }
20154        }
20155    }
20156
20157    /// Remove any highlighted row ranges of the given type that intersect the
20158    /// given ranges.
20159    pub fn remove_highlighted_rows<T: 'static>(
20160        &mut self,
20161        ranges_to_remove: Vec<Range<Anchor>>,
20162        cx: &mut Context<Self>,
20163    ) {
20164        let snapshot = self.buffer().read(cx).snapshot(cx);
20165        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20166        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20167        row_highlights.retain(|highlight| {
20168            while let Some(range_to_remove) = ranges_to_remove.peek() {
20169                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20170                    Ordering::Less | Ordering::Equal => {
20171                        ranges_to_remove.next();
20172                    }
20173                    Ordering::Greater => {
20174                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20175                            Ordering::Less | Ordering::Equal => {
20176                                return false;
20177                            }
20178                            Ordering::Greater => break,
20179                        }
20180                    }
20181                }
20182            }
20183
20184            true
20185        })
20186    }
20187
20188    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20189    pub fn clear_row_highlights<T: 'static>(&mut self) {
20190        self.highlighted_rows.remove(&TypeId::of::<T>());
20191    }
20192
20193    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20194    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20195        self.highlighted_rows
20196            .get(&TypeId::of::<T>())
20197            .map_or(&[] as &[_], |vec| vec.as_slice())
20198            .iter()
20199            .map(|highlight| (highlight.range.clone(), highlight.color))
20200    }
20201
20202    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20203    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20204    /// Allows to ignore certain kinds of highlights.
20205    pub fn highlighted_display_rows(
20206        &self,
20207        window: &mut Window,
20208        cx: &mut App,
20209    ) -> BTreeMap<DisplayRow, LineHighlight> {
20210        let snapshot = self.snapshot(window, cx);
20211        let mut used_highlight_orders = HashMap::default();
20212        self.highlighted_rows
20213            .iter()
20214            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20215            .fold(
20216                BTreeMap::<DisplayRow, LineHighlight>::new(),
20217                |mut unique_rows, highlight| {
20218                    let start = highlight.range.start.to_display_point(&snapshot);
20219                    let end = highlight.range.end.to_display_point(&snapshot);
20220                    let start_row = start.row().0;
20221                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20222                        && end.column() == 0
20223                    {
20224                        end.row().0.saturating_sub(1)
20225                    } else {
20226                        end.row().0
20227                    };
20228                    for row in start_row..=end_row {
20229                        let used_index =
20230                            used_highlight_orders.entry(row).or_insert(highlight.index);
20231                        if highlight.index >= *used_index {
20232                            *used_index = highlight.index;
20233                            unique_rows.insert(
20234                                DisplayRow(row),
20235                                LineHighlight {
20236                                    include_gutter: highlight.options.include_gutter,
20237                                    border: None,
20238                                    background: highlight.color.into(),
20239                                    type_id: Some(highlight.type_id),
20240                                },
20241                            );
20242                        }
20243                    }
20244                    unique_rows
20245                },
20246            )
20247    }
20248
20249    pub fn highlighted_display_row_for_autoscroll(
20250        &self,
20251        snapshot: &DisplaySnapshot,
20252    ) -> Option<DisplayRow> {
20253        self.highlighted_rows
20254            .values()
20255            .flat_map(|highlighted_rows| highlighted_rows.iter())
20256            .filter_map(|highlight| {
20257                if highlight.options.autoscroll {
20258                    Some(highlight.range.start.to_display_point(snapshot).row())
20259                } else {
20260                    None
20261                }
20262            })
20263            .min()
20264    }
20265
20266    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20267        self.highlight_background::<SearchWithinRange>(
20268            ranges,
20269            |colors| colors.colors().editor_document_highlight_read_background,
20270            cx,
20271        )
20272    }
20273
20274    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20275        self.breadcrumb_header = Some(new_header);
20276    }
20277
20278    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20279        self.clear_background_highlights::<SearchWithinRange>(cx);
20280    }
20281
20282    pub fn highlight_background<T: 'static>(
20283        &mut self,
20284        ranges: &[Range<Anchor>],
20285        color_fetcher: fn(&Theme) -> Hsla,
20286        cx: &mut Context<Self>,
20287    ) {
20288        self.background_highlights.insert(
20289            HighlightKey::Type(TypeId::of::<T>()),
20290            (color_fetcher, Arc::from(ranges)),
20291        );
20292        self.scrollbar_marker_state.dirty = true;
20293        cx.notify();
20294    }
20295
20296    pub fn highlight_background_key<T: 'static>(
20297        &mut self,
20298        key: usize,
20299        ranges: &[Range<Anchor>],
20300        color_fetcher: fn(&Theme) -> Hsla,
20301        cx: &mut Context<Self>,
20302    ) {
20303        self.background_highlights.insert(
20304            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20305            (color_fetcher, Arc::from(ranges)),
20306        );
20307        self.scrollbar_marker_state.dirty = true;
20308        cx.notify();
20309    }
20310
20311    pub fn clear_background_highlights<T: 'static>(
20312        &mut self,
20313        cx: &mut Context<Self>,
20314    ) -> Option<BackgroundHighlight> {
20315        let text_highlights = self
20316            .background_highlights
20317            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20318        if !text_highlights.1.is_empty() {
20319            self.scrollbar_marker_state.dirty = true;
20320            cx.notify();
20321        }
20322        Some(text_highlights)
20323    }
20324
20325    pub fn highlight_gutter<T: 'static>(
20326        &mut self,
20327        ranges: impl Into<Vec<Range<Anchor>>>,
20328        color_fetcher: fn(&App) -> Hsla,
20329        cx: &mut Context<Self>,
20330    ) {
20331        self.gutter_highlights
20332            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20333        cx.notify();
20334    }
20335
20336    pub fn clear_gutter_highlights<T: 'static>(
20337        &mut self,
20338        cx: &mut Context<Self>,
20339    ) -> Option<GutterHighlight> {
20340        cx.notify();
20341        self.gutter_highlights.remove(&TypeId::of::<T>())
20342    }
20343
20344    pub fn insert_gutter_highlight<T: 'static>(
20345        &mut self,
20346        range: Range<Anchor>,
20347        color_fetcher: fn(&App) -> Hsla,
20348        cx: &mut Context<Self>,
20349    ) {
20350        let snapshot = self.buffer().read(cx).snapshot(cx);
20351        let mut highlights = self
20352            .gutter_highlights
20353            .remove(&TypeId::of::<T>())
20354            .map(|(_, highlights)| highlights)
20355            .unwrap_or_default();
20356        let ix = highlights.binary_search_by(|highlight| {
20357            Ordering::Equal
20358                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20359                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20360        });
20361        if let Err(ix) = ix {
20362            highlights.insert(ix, range);
20363        }
20364        self.gutter_highlights
20365            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20366    }
20367
20368    pub fn remove_gutter_highlights<T: 'static>(
20369        &mut self,
20370        ranges_to_remove: Vec<Range<Anchor>>,
20371        cx: &mut Context<Self>,
20372    ) {
20373        let snapshot = self.buffer().read(cx).snapshot(cx);
20374        let Some((color_fetcher, mut gutter_highlights)) =
20375            self.gutter_highlights.remove(&TypeId::of::<T>())
20376        else {
20377            return;
20378        };
20379        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20380        gutter_highlights.retain(|highlight| {
20381            while let Some(range_to_remove) = ranges_to_remove.peek() {
20382                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20383                    Ordering::Less | Ordering::Equal => {
20384                        ranges_to_remove.next();
20385                    }
20386                    Ordering::Greater => {
20387                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20388                            Ordering::Less | Ordering::Equal => {
20389                                return false;
20390                            }
20391                            Ordering::Greater => break,
20392                        }
20393                    }
20394                }
20395            }
20396
20397            true
20398        });
20399        self.gutter_highlights
20400            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20401    }
20402
20403    #[cfg(feature = "test-support")]
20404    pub fn all_text_highlights(
20405        &self,
20406        window: &mut Window,
20407        cx: &mut Context<Self>,
20408    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20409        let snapshot = self.snapshot(window, cx);
20410        self.display_map.update(cx, |display_map, _| {
20411            display_map
20412                .all_text_highlights()
20413                .map(|highlight| {
20414                    let (style, ranges) = highlight.as_ref();
20415                    (
20416                        *style,
20417                        ranges
20418                            .iter()
20419                            .map(|range| range.clone().to_display_points(&snapshot))
20420                            .collect(),
20421                    )
20422                })
20423                .collect()
20424        })
20425    }
20426
20427    #[cfg(feature = "test-support")]
20428    pub fn all_text_background_highlights(
20429        &self,
20430        window: &mut Window,
20431        cx: &mut Context<Self>,
20432    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20433        let snapshot = self.snapshot(window, cx);
20434        let buffer = &snapshot.buffer_snapshot();
20435        let start = buffer.anchor_before(0);
20436        let end = buffer.anchor_after(buffer.len());
20437        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20438    }
20439
20440    #[cfg(any(test, feature = "test-support"))]
20441    pub fn sorted_background_highlights_in_range(
20442        &self,
20443        search_range: Range<Anchor>,
20444        display_snapshot: &DisplaySnapshot,
20445        theme: &Theme,
20446    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20447        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20448        res.sort_by(|a, b| {
20449            a.0.start
20450                .cmp(&b.0.start)
20451                .then_with(|| a.0.end.cmp(&b.0.end))
20452                .then_with(|| a.1.cmp(&b.1))
20453        });
20454        res
20455    }
20456
20457    #[cfg(feature = "test-support")]
20458    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20459        let snapshot = self.buffer().read(cx).snapshot(cx);
20460
20461        let highlights = self
20462            .background_highlights
20463            .get(&HighlightKey::Type(TypeId::of::<
20464                items::BufferSearchHighlights,
20465            >()));
20466
20467        if let Some((_color, ranges)) = highlights {
20468            ranges
20469                .iter()
20470                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20471                .collect_vec()
20472        } else {
20473            vec![]
20474        }
20475    }
20476
20477    fn document_highlights_for_position<'a>(
20478        &'a self,
20479        position: Anchor,
20480        buffer: &'a MultiBufferSnapshot,
20481    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20482        let read_highlights = self
20483            .background_highlights
20484            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20485            .map(|h| &h.1);
20486        let write_highlights = self
20487            .background_highlights
20488            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20489            .map(|h| &h.1);
20490        let left_position = position.bias_left(buffer);
20491        let right_position = position.bias_right(buffer);
20492        read_highlights
20493            .into_iter()
20494            .chain(write_highlights)
20495            .flat_map(move |ranges| {
20496                let start_ix = match ranges.binary_search_by(|probe| {
20497                    let cmp = probe.end.cmp(&left_position, buffer);
20498                    if cmp.is_ge() {
20499                        Ordering::Greater
20500                    } else {
20501                        Ordering::Less
20502                    }
20503                }) {
20504                    Ok(i) | Err(i) => i,
20505                };
20506
20507                ranges[start_ix..]
20508                    .iter()
20509                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20510            })
20511    }
20512
20513    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20514        self.background_highlights
20515            .get(&HighlightKey::Type(TypeId::of::<T>()))
20516            .is_some_and(|(_, highlights)| !highlights.is_empty())
20517    }
20518
20519    /// Returns all background highlights for a given range.
20520    ///
20521    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20522    pub fn background_highlights_in_range(
20523        &self,
20524        search_range: Range<Anchor>,
20525        display_snapshot: &DisplaySnapshot,
20526        theme: &Theme,
20527    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20528        let mut results = Vec::new();
20529        for (color_fetcher, ranges) in self.background_highlights.values() {
20530            let color = color_fetcher(theme);
20531            let start_ix = match ranges.binary_search_by(|probe| {
20532                let cmp = probe
20533                    .end
20534                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20535                if cmp.is_gt() {
20536                    Ordering::Greater
20537                } else {
20538                    Ordering::Less
20539                }
20540            }) {
20541                Ok(i) | Err(i) => i,
20542            };
20543            for range in &ranges[start_ix..] {
20544                if range
20545                    .start
20546                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20547                    .is_ge()
20548                {
20549                    break;
20550                }
20551
20552                let start = range.start.to_display_point(display_snapshot);
20553                let end = range.end.to_display_point(display_snapshot);
20554                results.push((start..end, color))
20555            }
20556        }
20557        results
20558    }
20559
20560    pub fn gutter_highlights_in_range(
20561        &self,
20562        search_range: Range<Anchor>,
20563        display_snapshot: &DisplaySnapshot,
20564        cx: &App,
20565    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20566        let mut results = Vec::new();
20567        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20568            let color = color_fetcher(cx);
20569            let start_ix = match ranges.binary_search_by(|probe| {
20570                let cmp = probe
20571                    .end
20572                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20573                if cmp.is_gt() {
20574                    Ordering::Greater
20575                } else {
20576                    Ordering::Less
20577                }
20578            }) {
20579                Ok(i) | Err(i) => i,
20580            };
20581            for range in &ranges[start_ix..] {
20582                if range
20583                    .start
20584                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20585                    .is_ge()
20586                {
20587                    break;
20588                }
20589
20590                let start = range.start.to_display_point(display_snapshot);
20591                let end = range.end.to_display_point(display_snapshot);
20592                results.push((start..end, color))
20593            }
20594        }
20595        results
20596    }
20597
20598    /// Get the text ranges corresponding to the redaction query
20599    pub fn redacted_ranges(
20600        &self,
20601        search_range: Range<Anchor>,
20602        display_snapshot: &DisplaySnapshot,
20603        cx: &App,
20604    ) -> Vec<Range<DisplayPoint>> {
20605        display_snapshot
20606            .buffer_snapshot()
20607            .redacted_ranges(search_range, |file| {
20608                if let Some(file) = file {
20609                    file.is_private()
20610                        && EditorSettings::get(
20611                            Some(SettingsLocation {
20612                                worktree_id: file.worktree_id(cx),
20613                                path: file.path().as_ref(),
20614                            }),
20615                            cx,
20616                        )
20617                        .redact_private_values
20618                } else {
20619                    false
20620                }
20621            })
20622            .map(|range| {
20623                range.start.to_display_point(display_snapshot)
20624                    ..range.end.to_display_point(display_snapshot)
20625            })
20626            .collect()
20627    }
20628
20629    pub fn highlight_text_key<T: 'static>(
20630        &mut self,
20631        key: usize,
20632        ranges: Vec<Range<Anchor>>,
20633        style: HighlightStyle,
20634        cx: &mut Context<Self>,
20635    ) {
20636        self.display_map.update(cx, |map, _| {
20637            map.highlight_text(
20638                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20639                ranges,
20640                style,
20641            );
20642        });
20643        cx.notify();
20644    }
20645
20646    pub fn highlight_text<T: 'static>(
20647        &mut self,
20648        ranges: Vec<Range<Anchor>>,
20649        style: HighlightStyle,
20650        cx: &mut Context<Self>,
20651    ) {
20652        self.display_map.update(cx, |map, _| {
20653            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20654        });
20655        cx.notify();
20656    }
20657
20658    pub(crate) fn highlight_inlays<T: 'static>(
20659        &mut self,
20660        highlights: Vec<InlayHighlight>,
20661        style: HighlightStyle,
20662        cx: &mut Context<Self>,
20663    ) {
20664        self.display_map.update(cx, |map, _| {
20665            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20666        });
20667        cx.notify();
20668    }
20669
20670    pub fn text_highlights<'a, T: 'static>(
20671        &'a self,
20672        cx: &'a App,
20673    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20674        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20675    }
20676
20677    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20678        let cleared = self
20679            .display_map
20680            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20681        if cleared {
20682            cx.notify();
20683        }
20684    }
20685
20686    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20687        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20688            && self.focus_handle.is_focused(window)
20689    }
20690
20691    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20692        self.show_cursor_when_unfocused = is_enabled;
20693        cx.notify();
20694    }
20695
20696    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20697        cx.notify();
20698    }
20699
20700    fn on_debug_session_event(
20701        &mut self,
20702        _session: Entity<Session>,
20703        event: &SessionEvent,
20704        cx: &mut Context<Self>,
20705    ) {
20706        if let SessionEvent::InvalidateInlineValue = event {
20707            self.refresh_inline_values(cx);
20708        }
20709    }
20710
20711    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20712        let Some(project) = self.project.clone() else {
20713            return;
20714        };
20715
20716        if !self.inline_value_cache.enabled {
20717            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20718            self.splice_inlays(&inlays, Vec::new(), cx);
20719            return;
20720        }
20721
20722        let current_execution_position = self
20723            .highlighted_rows
20724            .get(&TypeId::of::<ActiveDebugLine>())
20725            .and_then(|lines| lines.last().map(|line| line.range.end));
20726
20727        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20728            let inline_values = editor
20729                .update(cx, |editor, cx| {
20730                    let Some(current_execution_position) = current_execution_position else {
20731                        return Some(Task::ready(Ok(Vec::new())));
20732                    };
20733
20734                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20735                        let snapshot = buffer.snapshot(cx);
20736
20737                        let excerpt = snapshot.excerpt_containing(
20738                            current_execution_position..current_execution_position,
20739                        )?;
20740
20741                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20742                    })?;
20743
20744                    let range =
20745                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20746
20747                    project.inline_values(buffer, range, cx)
20748                })
20749                .ok()
20750                .flatten()?
20751                .await
20752                .context("refreshing debugger inlays")
20753                .log_err()?;
20754
20755            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20756
20757            for (buffer_id, inline_value) in inline_values
20758                .into_iter()
20759                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20760            {
20761                buffer_inline_values
20762                    .entry(buffer_id)
20763                    .or_default()
20764                    .push(inline_value);
20765            }
20766
20767            editor
20768                .update(cx, |editor, cx| {
20769                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20770                    let mut new_inlays = Vec::default();
20771
20772                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20773                        let buffer_id = buffer_snapshot.remote_id();
20774                        buffer_inline_values
20775                            .get(&buffer_id)
20776                            .into_iter()
20777                            .flatten()
20778                            .for_each(|hint| {
20779                                let inlay = Inlay::debugger(
20780                                    post_inc(&mut editor.next_inlay_id),
20781                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20782                                    hint.text(),
20783                                );
20784                                if !inlay.text().chars().contains(&'\n') {
20785                                    new_inlays.push(inlay);
20786                                }
20787                            });
20788                    }
20789
20790                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20791                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20792
20793                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20794                })
20795                .ok()?;
20796            Some(())
20797        });
20798    }
20799
20800    fn on_buffer_event(
20801        &mut self,
20802        multibuffer: &Entity<MultiBuffer>,
20803        event: &multi_buffer::Event,
20804        window: &mut Window,
20805        cx: &mut Context<Self>,
20806    ) {
20807        match event {
20808            multi_buffer::Event::Edited {
20809                singleton_buffer_edited,
20810                edited_buffer,
20811            } => {
20812                self.scrollbar_marker_state.dirty = true;
20813                self.active_indent_guides_state.dirty = true;
20814                self.refresh_active_diagnostics(cx);
20815                self.refresh_code_actions(window, cx);
20816                self.refresh_selected_text_highlights(true, window, cx);
20817                self.refresh_single_line_folds(window, cx);
20818                refresh_matching_bracket_highlights(self, cx);
20819                if self.has_active_edit_prediction() {
20820                    self.update_visible_edit_prediction(window, cx);
20821                }
20822                if let Some(project) = self.project.as_ref()
20823                    && let Some(edited_buffer) = edited_buffer
20824                {
20825                    project.update(cx, |project, cx| {
20826                        self.registered_buffers
20827                            .entry(edited_buffer.read(cx).remote_id())
20828                            .or_insert_with(|| {
20829                                project.register_buffer_with_language_servers(edited_buffer, cx)
20830                            });
20831                    });
20832                }
20833                cx.emit(EditorEvent::BufferEdited);
20834                cx.emit(SearchEvent::MatchesInvalidated);
20835
20836                if let Some(buffer) = edited_buffer {
20837                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20838                }
20839
20840                if *singleton_buffer_edited {
20841                    if let Some(buffer) = edited_buffer
20842                        && buffer.read(cx).file().is_none()
20843                    {
20844                        cx.emit(EditorEvent::TitleChanged);
20845                    }
20846                    if let Some(project) = &self.project {
20847                        #[allow(clippy::mutable_key_type)]
20848                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20849                            multibuffer
20850                                .all_buffers()
20851                                .into_iter()
20852                                .filter_map(|buffer| {
20853                                    buffer.update(cx, |buffer, cx| {
20854                                        let language = buffer.language()?;
20855                                        let should_discard = project.update(cx, |project, cx| {
20856                                            project.is_local()
20857                                                && !project.has_language_servers_for(buffer, cx)
20858                                        });
20859                                        should_discard.not().then_some(language.clone())
20860                                    })
20861                                })
20862                                .collect::<HashSet<_>>()
20863                        });
20864                        if !languages_affected.is_empty() {
20865                            self.refresh_inlay_hints(
20866                                InlayHintRefreshReason::BufferEdited(languages_affected),
20867                                cx,
20868                            );
20869                        }
20870                    }
20871                }
20872
20873                let Some(project) = &self.project else { return };
20874                let (telemetry, is_via_ssh) = {
20875                    let project = project.read(cx);
20876                    let telemetry = project.client().telemetry().clone();
20877                    let is_via_ssh = project.is_via_remote_server();
20878                    (telemetry, is_via_ssh)
20879                };
20880                refresh_linked_ranges(self, window, cx);
20881                telemetry.log_edit_event("editor", is_via_ssh);
20882            }
20883            multi_buffer::Event::ExcerptsAdded {
20884                buffer,
20885                predecessor,
20886                excerpts,
20887            } => {
20888                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20889                let buffer_id = buffer.read(cx).remote_id();
20890                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20891                    && let Some(project) = &self.project
20892                {
20893                    update_uncommitted_diff_for_buffer(
20894                        cx.entity(),
20895                        project,
20896                        [buffer.clone()],
20897                        self.buffer.clone(),
20898                        cx,
20899                    )
20900                    .detach();
20901                }
20902                if self.active_diagnostics != ActiveDiagnostic::All {
20903                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20904                }
20905                cx.emit(EditorEvent::ExcerptsAdded {
20906                    buffer: buffer.clone(),
20907                    predecessor: *predecessor,
20908                    excerpts: excerpts.clone(),
20909                });
20910                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20911            }
20912            multi_buffer::Event::ExcerptsRemoved {
20913                ids,
20914                removed_buffer_ids,
20915            } => {
20916                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20917                let buffer = self.buffer.read(cx);
20918                self.registered_buffers
20919                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20920                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20921                cx.emit(EditorEvent::ExcerptsRemoved {
20922                    ids: ids.clone(),
20923                    removed_buffer_ids: removed_buffer_ids.clone(),
20924                });
20925            }
20926            multi_buffer::Event::ExcerptsEdited {
20927                excerpt_ids,
20928                buffer_ids,
20929            } => {
20930                self.display_map.update(cx, |map, cx| {
20931                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20932                });
20933                cx.emit(EditorEvent::ExcerptsEdited {
20934                    ids: excerpt_ids.clone(),
20935                });
20936            }
20937            multi_buffer::Event::ExcerptsExpanded { ids } => {
20938                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20939                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20940            }
20941            multi_buffer::Event::Reparsed(buffer_id) => {
20942                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20943                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20944
20945                cx.emit(EditorEvent::Reparsed(*buffer_id));
20946            }
20947            multi_buffer::Event::DiffHunksToggled => {
20948                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20949            }
20950            multi_buffer::Event::LanguageChanged(buffer_id) => {
20951                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20952                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20953                cx.emit(EditorEvent::Reparsed(*buffer_id));
20954                cx.notify();
20955            }
20956            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20957            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20958            multi_buffer::Event::FileHandleChanged
20959            | multi_buffer::Event::Reloaded
20960            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20961            multi_buffer::Event::DiagnosticsUpdated => {
20962                self.update_diagnostics_state(window, cx);
20963            }
20964            _ => {}
20965        };
20966    }
20967
20968    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20969        if !self.diagnostics_enabled() {
20970            return;
20971        }
20972        self.refresh_active_diagnostics(cx);
20973        self.refresh_inline_diagnostics(true, window, cx);
20974        self.scrollbar_marker_state.dirty = true;
20975        cx.notify();
20976    }
20977
20978    pub fn start_temporary_diff_override(&mut self) {
20979        self.load_diff_task.take();
20980        self.temporary_diff_override = true;
20981    }
20982
20983    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20984        self.temporary_diff_override = false;
20985        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20986        self.buffer.update(cx, |buffer, cx| {
20987            buffer.set_all_diff_hunks_collapsed(cx);
20988        });
20989
20990        if let Some(project) = self.project.clone() {
20991            self.load_diff_task = Some(
20992                update_uncommitted_diff_for_buffer(
20993                    cx.entity(),
20994                    &project,
20995                    self.buffer.read(cx).all_buffers(),
20996                    self.buffer.clone(),
20997                    cx,
20998                )
20999                .shared(),
21000            );
21001        }
21002    }
21003
21004    fn on_display_map_changed(
21005        &mut self,
21006        _: Entity<DisplayMap>,
21007        _: &mut Window,
21008        cx: &mut Context<Self>,
21009    ) {
21010        cx.notify();
21011    }
21012
21013    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21014        if self.diagnostics_enabled() {
21015            let new_severity = EditorSettings::get_global(cx)
21016                .diagnostics_max_severity
21017                .unwrap_or(DiagnosticSeverity::Hint);
21018            self.set_max_diagnostics_severity(new_severity, cx);
21019        }
21020        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21021        self.update_edit_prediction_settings(cx);
21022        self.refresh_edit_prediction(true, false, window, cx);
21023        self.refresh_inline_values(cx);
21024        self.refresh_inlay_hints(
21025            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21026                self.selections.newest_anchor().head(),
21027                &self.buffer.read(cx).snapshot(cx),
21028                cx,
21029            )),
21030            cx,
21031        );
21032
21033        let old_cursor_shape = self.cursor_shape;
21034        let old_show_breadcrumbs = self.show_breadcrumbs;
21035
21036        {
21037            let editor_settings = EditorSettings::get_global(cx);
21038            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21039            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21040            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21041            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21042        }
21043
21044        if old_cursor_shape != self.cursor_shape {
21045            cx.emit(EditorEvent::CursorShapeChanged);
21046        }
21047
21048        if old_show_breadcrumbs != self.show_breadcrumbs {
21049            cx.emit(EditorEvent::BreadcrumbsChanged);
21050        }
21051
21052        let project_settings = ProjectSettings::get_global(cx);
21053        self.serialize_dirty_buffers =
21054            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21055
21056        if self.mode.is_full() {
21057            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21058            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21059            if self.show_inline_diagnostics != show_inline_diagnostics {
21060                self.show_inline_diagnostics = show_inline_diagnostics;
21061                self.refresh_inline_diagnostics(false, window, cx);
21062            }
21063
21064            if self.git_blame_inline_enabled != inline_blame_enabled {
21065                self.toggle_git_blame_inline_internal(false, window, cx);
21066            }
21067
21068            let minimap_settings = EditorSettings::get_global(cx).minimap;
21069            if self.minimap_visibility != MinimapVisibility::Disabled {
21070                if self.minimap_visibility.settings_visibility()
21071                    != minimap_settings.minimap_enabled()
21072                {
21073                    self.set_minimap_visibility(
21074                        MinimapVisibility::for_mode(self.mode(), cx),
21075                        window,
21076                        cx,
21077                    );
21078                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21079                    minimap_entity.update(cx, |minimap_editor, cx| {
21080                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21081                    })
21082                }
21083            }
21084        }
21085
21086        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21087            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21088        }) {
21089            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21090                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21091            }
21092            self.refresh_colors(false, None, window, cx);
21093        }
21094
21095        cx.notify();
21096    }
21097
21098    pub fn set_searchable(&mut self, searchable: bool) {
21099        self.searchable = searchable;
21100    }
21101
21102    pub fn searchable(&self) -> bool {
21103        self.searchable
21104    }
21105
21106    fn open_proposed_changes_editor(
21107        &mut self,
21108        _: &OpenProposedChangesEditor,
21109        window: &mut Window,
21110        cx: &mut Context<Self>,
21111    ) {
21112        let Some(workspace) = self.workspace() else {
21113            cx.propagate();
21114            return;
21115        };
21116
21117        let selections = self.selections.all::<usize>(cx);
21118        let multi_buffer = self.buffer.read(cx);
21119        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21120        let mut new_selections_by_buffer = HashMap::default();
21121        for selection in selections {
21122            for (buffer, range, _) in
21123                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21124            {
21125                let mut range = range.to_point(buffer);
21126                range.start.column = 0;
21127                range.end.column = buffer.line_len(range.end.row);
21128                new_selections_by_buffer
21129                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21130                    .or_insert(Vec::new())
21131                    .push(range)
21132            }
21133        }
21134
21135        let proposed_changes_buffers = new_selections_by_buffer
21136            .into_iter()
21137            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21138            .collect::<Vec<_>>();
21139        let proposed_changes_editor = cx.new(|cx| {
21140            ProposedChangesEditor::new(
21141                "Proposed changes",
21142                proposed_changes_buffers,
21143                self.project.clone(),
21144                window,
21145                cx,
21146            )
21147        });
21148
21149        window.defer(cx, move |window, cx| {
21150            workspace.update(cx, |workspace, cx| {
21151                workspace.active_pane().update(cx, |pane, cx| {
21152                    pane.add_item(
21153                        Box::new(proposed_changes_editor),
21154                        true,
21155                        true,
21156                        None,
21157                        window,
21158                        cx,
21159                    );
21160                });
21161            });
21162        });
21163    }
21164
21165    pub fn open_excerpts_in_split(
21166        &mut self,
21167        _: &OpenExcerptsSplit,
21168        window: &mut Window,
21169        cx: &mut Context<Self>,
21170    ) {
21171        self.open_excerpts_common(None, true, window, cx)
21172    }
21173
21174    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21175        self.open_excerpts_common(None, false, window, cx)
21176    }
21177
21178    fn open_excerpts_common(
21179        &mut self,
21180        jump_data: Option<JumpData>,
21181        split: bool,
21182        window: &mut Window,
21183        cx: &mut Context<Self>,
21184    ) {
21185        let Some(workspace) = self.workspace() else {
21186            cx.propagate();
21187            return;
21188        };
21189
21190        if self.buffer.read(cx).is_singleton() {
21191            cx.propagate();
21192            return;
21193        }
21194
21195        let mut new_selections_by_buffer = HashMap::default();
21196        match &jump_data {
21197            Some(JumpData::MultiBufferPoint {
21198                excerpt_id,
21199                position,
21200                anchor,
21201                line_offset_from_top,
21202            }) => {
21203                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21204                if let Some(buffer) = multi_buffer_snapshot
21205                    .buffer_id_for_excerpt(*excerpt_id)
21206                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21207                {
21208                    let buffer_snapshot = buffer.read(cx).snapshot();
21209                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21210                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21211                    } else {
21212                        buffer_snapshot.clip_point(*position, Bias::Left)
21213                    };
21214                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21215                    new_selections_by_buffer.insert(
21216                        buffer,
21217                        (
21218                            vec![jump_to_offset..jump_to_offset],
21219                            Some(*line_offset_from_top),
21220                        ),
21221                    );
21222                }
21223            }
21224            Some(JumpData::MultiBufferRow {
21225                row,
21226                line_offset_from_top,
21227            }) => {
21228                let point = MultiBufferPoint::new(row.0, 0);
21229                if let Some((buffer, buffer_point, _)) =
21230                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21231                {
21232                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21233                    new_selections_by_buffer
21234                        .entry(buffer)
21235                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21236                        .0
21237                        .push(buffer_offset..buffer_offset)
21238                }
21239            }
21240            None => {
21241                let selections = self.selections.all::<usize>(cx);
21242                let multi_buffer = self.buffer.read(cx);
21243                for selection in selections {
21244                    for (snapshot, range, _, anchor) in multi_buffer
21245                        .snapshot(cx)
21246                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21247                    {
21248                        if let Some(anchor) = anchor {
21249                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21250                            else {
21251                                continue;
21252                            };
21253                            let offset = text::ToOffset::to_offset(
21254                                &anchor.text_anchor,
21255                                &buffer_handle.read(cx).snapshot(),
21256                            );
21257                            let range = offset..offset;
21258                            new_selections_by_buffer
21259                                .entry(buffer_handle)
21260                                .or_insert((Vec::new(), None))
21261                                .0
21262                                .push(range)
21263                        } else {
21264                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21265                            else {
21266                                continue;
21267                            };
21268                            new_selections_by_buffer
21269                                .entry(buffer_handle)
21270                                .or_insert((Vec::new(), None))
21271                                .0
21272                                .push(range)
21273                        }
21274                    }
21275                }
21276            }
21277        }
21278
21279        new_selections_by_buffer
21280            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21281
21282        if new_selections_by_buffer.is_empty() {
21283            return;
21284        }
21285
21286        // We defer the pane interaction because we ourselves are a workspace item
21287        // and activating a new item causes the pane to call a method on us reentrantly,
21288        // which panics if we're on the stack.
21289        window.defer(cx, move |window, cx| {
21290            workspace.update(cx, |workspace, cx| {
21291                let pane = if split {
21292                    workspace.adjacent_pane(window, cx)
21293                } else {
21294                    workspace.active_pane().clone()
21295                };
21296
21297                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21298                    let editor = buffer
21299                        .read(cx)
21300                        .file()
21301                        .is_none()
21302                        .then(|| {
21303                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21304                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21305                            // Instead, we try to activate the existing editor in the pane first.
21306                            let (editor, pane_item_index) =
21307                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21308                                    let editor = item.downcast::<Editor>()?;
21309                                    let singleton_buffer =
21310                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21311                                    if singleton_buffer == buffer {
21312                                        Some((editor, i))
21313                                    } else {
21314                                        None
21315                                    }
21316                                })?;
21317                            pane.update(cx, |pane, cx| {
21318                                pane.activate_item(pane_item_index, true, true, window, cx)
21319                            });
21320                            Some(editor)
21321                        })
21322                        .flatten()
21323                        .unwrap_or_else(|| {
21324                            workspace.open_project_item::<Self>(
21325                                pane.clone(),
21326                                buffer,
21327                                true,
21328                                true,
21329                                window,
21330                                cx,
21331                            )
21332                        });
21333
21334                    editor.update(cx, |editor, cx| {
21335                        let autoscroll = match scroll_offset {
21336                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21337                            None => Autoscroll::newest(),
21338                        };
21339                        let nav_history = editor.nav_history.take();
21340                        editor.change_selections(
21341                            SelectionEffects::scroll(autoscroll),
21342                            window,
21343                            cx,
21344                            |s| {
21345                                s.select_ranges(ranges);
21346                            },
21347                        );
21348                        editor.nav_history = nav_history;
21349                    });
21350                }
21351            })
21352        });
21353    }
21354
21355    // For now, don't allow opening excerpts in buffers that aren't backed by
21356    // regular project files.
21357    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21358        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21359    }
21360
21361    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21362        let snapshot = self.buffer.read(cx).read(cx);
21363        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21364        Some(
21365            ranges
21366                .iter()
21367                .map(move |range| {
21368                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21369                })
21370                .collect(),
21371        )
21372    }
21373
21374    fn selection_replacement_ranges(
21375        &self,
21376        range: Range<OffsetUtf16>,
21377        cx: &mut App,
21378    ) -> Vec<Range<OffsetUtf16>> {
21379        let selections = self.selections.all::<OffsetUtf16>(cx);
21380        let newest_selection = selections
21381            .iter()
21382            .max_by_key(|selection| selection.id)
21383            .unwrap();
21384        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21385        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21386        let snapshot = self.buffer.read(cx).read(cx);
21387        selections
21388            .into_iter()
21389            .map(|mut selection| {
21390                selection.start.0 =
21391                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21392                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21393                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21394                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21395            })
21396            .collect()
21397    }
21398
21399    fn report_editor_event(
21400        &self,
21401        reported_event: ReportEditorEvent,
21402        file_extension: Option<String>,
21403        cx: &App,
21404    ) {
21405        if cfg!(any(test, feature = "test-support")) {
21406            return;
21407        }
21408
21409        let Some(project) = &self.project else { return };
21410
21411        // If None, we are in a file without an extension
21412        let file = self
21413            .buffer
21414            .read(cx)
21415            .as_singleton()
21416            .and_then(|b| b.read(cx).file());
21417        let file_extension = file_extension.or(file
21418            .as_ref()
21419            .and_then(|file| Path::new(file.file_name(cx)).extension())
21420            .and_then(|e| e.to_str())
21421            .map(|a| a.to_string()));
21422
21423        let vim_mode = vim_enabled(cx);
21424
21425        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21426        let copilot_enabled = edit_predictions_provider
21427            == language::language_settings::EditPredictionProvider::Copilot;
21428        let copilot_enabled_for_language = self
21429            .buffer
21430            .read(cx)
21431            .language_settings(cx)
21432            .show_edit_predictions;
21433
21434        let project = project.read(cx);
21435        let event_type = reported_event.event_type();
21436
21437        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21438            telemetry::event!(
21439                event_type,
21440                type = if auto_saved {"autosave"} else {"manual"},
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        } else {
21449            telemetry::event!(
21450                event_type,
21451                file_extension,
21452                vim_mode,
21453                copilot_enabled,
21454                copilot_enabled_for_language,
21455                edit_predictions_provider,
21456                is_via_ssh = project.is_via_remote_server(),
21457            );
21458        };
21459    }
21460
21461    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21462    /// with each line being an array of {text, highlight} objects.
21463    fn copy_highlight_json(
21464        &mut self,
21465        _: &CopyHighlightJson,
21466        window: &mut Window,
21467        cx: &mut Context<Self>,
21468    ) {
21469        #[derive(Serialize)]
21470        struct Chunk<'a> {
21471            text: String,
21472            highlight: Option<&'a str>,
21473        }
21474
21475        let snapshot = self.buffer.read(cx).snapshot(cx);
21476        let range = self
21477            .selected_text_range(false, window, cx)
21478            .and_then(|selection| {
21479                if selection.range.is_empty() {
21480                    None
21481                } else {
21482                    Some(selection.range)
21483                }
21484            })
21485            .unwrap_or_else(|| 0..snapshot.len());
21486
21487        let chunks = snapshot.chunks(range, true);
21488        let mut lines = Vec::new();
21489        let mut line: VecDeque<Chunk> = VecDeque::new();
21490
21491        let Some(style) = self.style.as_ref() else {
21492            return;
21493        };
21494
21495        for chunk in chunks {
21496            let highlight = chunk
21497                .syntax_highlight_id
21498                .and_then(|id| id.name(&style.syntax));
21499            let mut chunk_lines = chunk.text.split('\n').peekable();
21500            while let Some(text) = chunk_lines.next() {
21501                let mut merged_with_last_token = false;
21502                if let Some(last_token) = line.back_mut()
21503                    && last_token.highlight == highlight
21504                {
21505                    last_token.text.push_str(text);
21506                    merged_with_last_token = true;
21507                }
21508
21509                if !merged_with_last_token {
21510                    line.push_back(Chunk {
21511                        text: text.into(),
21512                        highlight,
21513                    });
21514                }
21515
21516                if chunk_lines.peek().is_some() {
21517                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21518                        line.pop_front();
21519                    }
21520                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21521                        line.pop_back();
21522                    }
21523
21524                    lines.push(mem::take(&mut line));
21525                }
21526            }
21527        }
21528
21529        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21530            return;
21531        };
21532        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21533    }
21534
21535    pub fn open_context_menu(
21536        &mut self,
21537        _: &OpenContextMenu,
21538        window: &mut Window,
21539        cx: &mut Context<Self>,
21540    ) {
21541        self.request_autoscroll(Autoscroll::newest(), cx);
21542        let position = self.selections.newest_display(cx).start;
21543        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21544    }
21545
21546    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21547        &self.inlay_hint_cache
21548    }
21549
21550    pub fn replay_insert_event(
21551        &mut self,
21552        text: &str,
21553        relative_utf16_range: Option<Range<isize>>,
21554        window: &mut Window,
21555        cx: &mut Context<Self>,
21556    ) {
21557        if !self.input_enabled {
21558            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21559            return;
21560        }
21561        if let Some(relative_utf16_range) = relative_utf16_range {
21562            let selections = self.selections.all::<OffsetUtf16>(cx);
21563            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21564                let new_ranges = selections.into_iter().map(|range| {
21565                    let start = OffsetUtf16(
21566                        range
21567                            .head()
21568                            .0
21569                            .saturating_add_signed(relative_utf16_range.start),
21570                    );
21571                    let end = OffsetUtf16(
21572                        range
21573                            .head()
21574                            .0
21575                            .saturating_add_signed(relative_utf16_range.end),
21576                    );
21577                    start..end
21578                });
21579                s.select_ranges(new_ranges);
21580            });
21581        }
21582
21583        self.handle_input(text, window, cx);
21584    }
21585
21586    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21587        let Some(provider) = self.semantics_provider.as_ref() else {
21588            return false;
21589        };
21590
21591        let mut supports = false;
21592        self.buffer().update(cx, |this, cx| {
21593            this.for_each_buffer(|buffer| {
21594                supports |= provider.supports_inlay_hints(buffer, cx);
21595            });
21596        });
21597
21598        supports
21599    }
21600
21601    pub fn is_focused(&self, window: &Window) -> bool {
21602        self.focus_handle.is_focused(window)
21603    }
21604
21605    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21606        cx.emit(EditorEvent::Focused);
21607
21608        if let Some(descendant) = self
21609            .last_focused_descendant
21610            .take()
21611            .and_then(|descendant| descendant.upgrade())
21612        {
21613            window.focus(&descendant);
21614        } else {
21615            if let Some(blame) = self.blame.as_ref() {
21616                blame.update(cx, GitBlame::focus)
21617            }
21618
21619            self.blink_manager.update(cx, BlinkManager::enable);
21620            self.show_cursor_names(window, cx);
21621            self.buffer.update(cx, |buffer, cx| {
21622                buffer.finalize_last_transaction(cx);
21623                if self.leader_id.is_none() {
21624                    buffer.set_active_selections(
21625                        &self.selections.disjoint_anchors_arc(),
21626                        self.selections.line_mode(),
21627                        self.cursor_shape,
21628                        cx,
21629                    );
21630                }
21631            });
21632        }
21633    }
21634
21635    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21636        cx.emit(EditorEvent::FocusedIn)
21637    }
21638
21639    fn handle_focus_out(
21640        &mut self,
21641        event: FocusOutEvent,
21642        _window: &mut Window,
21643        cx: &mut Context<Self>,
21644    ) {
21645        if event.blurred != self.focus_handle {
21646            self.last_focused_descendant = Some(event.blurred);
21647        }
21648        self.selection_drag_state = SelectionDragState::None;
21649        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21650    }
21651
21652    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21653        self.blink_manager.update(cx, BlinkManager::disable);
21654        self.buffer
21655            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21656
21657        if let Some(blame) = self.blame.as_ref() {
21658            blame.update(cx, GitBlame::blur)
21659        }
21660        if !self.hover_state.focused(window, cx) {
21661            hide_hover(self, cx);
21662        }
21663        if !self
21664            .context_menu
21665            .borrow()
21666            .as_ref()
21667            .is_some_and(|context_menu| context_menu.focused(window, cx))
21668        {
21669            self.hide_context_menu(window, cx);
21670        }
21671        self.take_active_edit_prediction(cx);
21672        cx.emit(EditorEvent::Blurred);
21673        cx.notify();
21674    }
21675
21676    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21677        let mut pending: String = window
21678            .pending_input_keystrokes()
21679            .into_iter()
21680            .flatten()
21681            .filter_map(|keystroke| {
21682                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21683                    keystroke.key_char.clone()
21684                } else {
21685                    None
21686                }
21687            })
21688            .collect();
21689
21690        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21691            pending = "".to_string();
21692        }
21693
21694        let existing_pending = self
21695            .text_highlights::<PendingInput>(cx)
21696            .map(|(_, ranges)| ranges.to_vec());
21697        if existing_pending.is_none() && pending.is_empty() {
21698            return;
21699        }
21700        let transaction =
21701            self.transact(window, cx, |this, window, cx| {
21702                let selections = this.selections.all::<usize>(cx);
21703                let edits = selections
21704                    .iter()
21705                    .map(|selection| (selection.end..selection.end, pending.clone()));
21706                this.edit(edits, cx);
21707                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21708                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21709                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21710                    }));
21711                });
21712                if let Some(existing_ranges) = existing_pending {
21713                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21714                    this.edit(edits, cx);
21715                }
21716            });
21717
21718        let snapshot = self.snapshot(window, cx);
21719        let ranges = self
21720            .selections
21721            .all::<usize>(cx)
21722            .into_iter()
21723            .map(|selection| {
21724                snapshot.buffer_snapshot().anchor_after(selection.end)
21725                    ..snapshot
21726                        .buffer_snapshot()
21727                        .anchor_before(selection.end + pending.len())
21728            })
21729            .collect();
21730
21731        if pending.is_empty() {
21732            self.clear_highlights::<PendingInput>(cx);
21733        } else {
21734            self.highlight_text::<PendingInput>(
21735                ranges,
21736                HighlightStyle {
21737                    underline: Some(UnderlineStyle {
21738                        thickness: px(1.),
21739                        color: None,
21740                        wavy: false,
21741                    }),
21742                    ..Default::default()
21743                },
21744                cx,
21745            );
21746        }
21747
21748        self.ime_transaction = self.ime_transaction.or(transaction);
21749        if let Some(transaction) = self.ime_transaction {
21750            self.buffer.update(cx, |buffer, cx| {
21751                buffer.group_until_transaction(transaction, cx);
21752            });
21753        }
21754
21755        if self.text_highlights::<PendingInput>(cx).is_none() {
21756            self.ime_transaction.take();
21757        }
21758    }
21759
21760    pub fn register_action_renderer(
21761        &mut self,
21762        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21763    ) -> Subscription {
21764        let id = self.next_editor_action_id.post_inc();
21765        self.editor_actions
21766            .borrow_mut()
21767            .insert(id, Box::new(listener));
21768
21769        let editor_actions = self.editor_actions.clone();
21770        Subscription::new(move || {
21771            editor_actions.borrow_mut().remove(&id);
21772        })
21773    }
21774
21775    pub fn register_action<A: Action>(
21776        &mut self,
21777        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21778    ) -> Subscription {
21779        let id = self.next_editor_action_id.post_inc();
21780        let listener = Arc::new(listener);
21781        self.editor_actions.borrow_mut().insert(
21782            id,
21783            Box::new(move |_, window, _| {
21784                let listener = listener.clone();
21785                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21786                    let action = action.downcast_ref().unwrap();
21787                    if phase == DispatchPhase::Bubble {
21788                        listener(action, window, cx)
21789                    }
21790                })
21791            }),
21792        );
21793
21794        let editor_actions = self.editor_actions.clone();
21795        Subscription::new(move || {
21796            editor_actions.borrow_mut().remove(&id);
21797        })
21798    }
21799
21800    pub fn file_header_size(&self) -> u32 {
21801        FILE_HEADER_HEIGHT
21802    }
21803
21804    pub fn restore(
21805        &mut self,
21806        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21807        window: &mut Window,
21808        cx: &mut Context<Self>,
21809    ) {
21810        let workspace = self.workspace();
21811        let project = self.project();
21812        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21813            let mut tasks = Vec::new();
21814            for (buffer_id, changes) in revert_changes {
21815                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21816                    buffer.update(cx, |buffer, cx| {
21817                        buffer.edit(
21818                            changes
21819                                .into_iter()
21820                                .map(|(range, text)| (range, text.to_string())),
21821                            None,
21822                            cx,
21823                        );
21824                    });
21825
21826                    if let Some(project) =
21827                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21828                    {
21829                        project.update(cx, |project, cx| {
21830                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21831                        })
21832                    }
21833                }
21834            }
21835            tasks
21836        });
21837        cx.spawn_in(window, async move |_, cx| {
21838            for (buffer, task) in save_tasks {
21839                let result = task.await;
21840                if result.is_err() {
21841                    let Some(path) = buffer
21842                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21843                        .ok()
21844                    else {
21845                        continue;
21846                    };
21847                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21848                        let Some(task) = cx
21849                            .update_window_entity(workspace, |workspace, window, cx| {
21850                                workspace
21851                                    .open_path_preview(path, None, false, false, false, window, cx)
21852                            })
21853                            .ok()
21854                        else {
21855                            continue;
21856                        };
21857                        task.await.log_err();
21858                    }
21859                }
21860            }
21861        })
21862        .detach();
21863        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21864            selections.refresh()
21865        });
21866    }
21867
21868    pub fn to_pixel_point(
21869        &self,
21870        source: multi_buffer::Anchor,
21871        editor_snapshot: &EditorSnapshot,
21872        window: &mut Window,
21873    ) -> Option<gpui::Point<Pixels>> {
21874        let source_point = source.to_display_point(editor_snapshot);
21875        self.display_to_pixel_point(source_point, editor_snapshot, window)
21876    }
21877
21878    pub fn display_to_pixel_point(
21879        &self,
21880        source: DisplayPoint,
21881        editor_snapshot: &EditorSnapshot,
21882        window: &mut Window,
21883    ) -> Option<gpui::Point<Pixels>> {
21884        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21885        let text_layout_details = self.text_layout_details(window);
21886        let scroll_top = text_layout_details
21887            .scroll_anchor
21888            .scroll_position(editor_snapshot)
21889            .y;
21890
21891        if source.row().as_f64() < scroll_top.floor() {
21892            return None;
21893        }
21894        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21895        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21896        Some(gpui::Point::new(source_x, source_y))
21897    }
21898
21899    pub fn has_visible_completions_menu(&self) -> bool {
21900        !self.edit_prediction_preview_is_active()
21901            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21902                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21903            })
21904    }
21905
21906    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21907        if self.mode.is_minimap() {
21908            return;
21909        }
21910        self.addons
21911            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21912    }
21913
21914    pub fn unregister_addon<T: Addon>(&mut self) {
21915        self.addons.remove(&std::any::TypeId::of::<T>());
21916    }
21917
21918    pub fn addon<T: Addon>(&self) -> Option<&T> {
21919        let type_id = std::any::TypeId::of::<T>();
21920        self.addons
21921            .get(&type_id)
21922            .and_then(|item| item.to_any().downcast_ref::<T>())
21923    }
21924
21925    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21926        let type_id = std::any::TypeId::of::<T>();
21927        self.addons
21928            .get_mut(&type_id)
21929            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21930    }
21931
21932    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21933        let text_layout_details = self.text_layout_details(window);
21934        let style = &text_layout_details.editor_style;
21935        let font_id = window.text_system().resolve_font(&style.text.font());
21936        let font_size = style.text.font_size.to_pixels(window.rem_size());
21937        let line_height = style.text.line_height_in_pixels(window.rem_size());
21938        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21939        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21940
21941        CharacterDimensions {
21942            em_width,
21943            em_advance,
21944            line_height,
21945        }
21946    }
21947
21948    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21949        self.load_diff_task.clone()
21950    }
21951
21952    fn read_metadata_from_db(
21953        &mut self,
21954        item_id: u64,
21955        workspace_id: WorkspaceId,
21956        window: &mut Window,
21957        cx: &mut Context<Editor>,
21958    ) {
21959        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21960            && !self.mode.is_minimap()
21961            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21962        {
21963            let buffer_snapshot = OnceCell::new();
21964
21965            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21966                && !folds.is_empty()
21967            {
21968                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21969                self.fold_ranges(
21970                    folds
21971                        .into_iter()
21972                        .map(|(start, end)| {
21973                            snapshot.clip_offset(start, Bias::Left)
21974                                ..snapshot.clip_offset(end, Bias::Right)
21975                        })
21976                        .collect(),
21977                    false,
21978                    window,
21979                    cx,
21980                );
21981            }
21982
21983            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21984                && !selections.is_empty()
21985            {
21986                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21987                // skip adding the initial selection to selection history
21988                self.selection_history.mode = SelectionHistoryMode::Skipping;
21989                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21990                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21991                        snapshot.clip_offset(start, Bias::Left)
21992                            ..snapshot.clip_offset(end, Bias::Right)
21993                    }));
21994                });
21995                self.selection_history.mode = SelectionHistoryMode::Normal;
21996            };
21997        }
21998
21999        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22000    }
22001
22002    fn update_lsp_data(
22003        &mut self,
22004        ignore_cache: bool,
22005        for_buffer: Option<BufferId>,
22006        window: &mut Window,
22007        cx: &mut Context<'_, Self>,
22008    ) {
22009        self.pull_diagnostics(for_buffer, window, cx);
22010        self.refresh_colors(ignore_cache, for_buffer, window, cx);
22011    }
22012}
22013
22014fn edit_for_markdown_paste<'a>(
22015    buffer: &MultiBufferSnapshot,
22016    range: Range<usize>,
22017    to_insert: &'a str,
22018    url: Option<url::Url>,
22019) -> (Range<usize>, Cow<'a, str>) {
22020    if url.is_none() {
22021        return (range, Cow::Borrowed(to_insert));
22022    };
22023
22024    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22025
22026    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22027        Cow::Borrowed(to_insert)
22028    } else {
22029        Cow::Owned(format!("[{old_text}]({to_insert})"))
22030    };
22031    (range, new_text)
22032}
22033
22034fn vim_enabled(cx: &App) -> bool {
22035    vim_mode_setting::VimModeSetting::try_get(cx)
22036        .map(|vim_mode| vim_mode.0)
22037        .unwrap_or(false)
22038}
22039
22040fn process_completion_for_edit(
22041    completion: &Completion,
22042    intent: CompletionIntent,
22043    buffer: &Entity<Buffer>,
22044    cursor_position: &text::Anchor,
22045    cx: &mut Context<Editor>,
22046) -> CompletionEdit {
22047    let buffer = buffer.read(cx);
22048    let buffer_snapshot = buffer.snapshot();
22049    let (snippet, new_text) = if completion.is_snippet() {
22050        let mut snippet_source = completion.new_text.clone();
22051        // Workaround for typescript language server issues so that methods don't expand within
22052        // strings and functions with type expressions. The previous point is used because the query
22053        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22054        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22055        let previous_point = if previous_point.column > 0 {
22056            cursor_position.to_previous_offset(&buffer_snapshot)
22057        } else {
22058            cursor_position.to_offset(&buffer_snapshot)
22059        };
22060        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22061            && scope.prefers_label_for_snippet_in_completion()
22062            && let Some(label) = completion.label()
22063            && matches!(
22064                completion.kind(),
22065                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22066            )
22067        {
22068            snippet_source = label;
22069        }
22070        match Snippet::parse(&snippet_source).log_err() {
22071            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22072            None => (None, completion.new_text.clone()),
22073        }
22074    } else {
22075        (None, completion.new_text.clone())
22076    };
22077
22078    let mut range_to_replace = {
22079        let replace_range = &completion.replace_range;
22080        if let CompletionSource::Lsp {
22081            insert_range: Some(insert_range),
22082            ..
22083        } = &completion.source
22084        {
22085            debug_assert_eq!(
22086                insert_range.start, replace_range.start,
22087                "insert_range and replace_range should start at the same position"
22088            );
22089            debug_assert!(
22090                insert_range
22091                    .start
22092                    .cmp(cursor_position, &buffer_snapshot)
22093                    .is_le(),
22094                "insert_range should start before or at cursor position"
22095            );
22096            debug_assert!(
22097                replace_range
22098                    .start
22099                    .cmp(cursor_position, &buffer_snapshot)
22100                    .is_le(),
22101                "replace_range should start before or at cursor position"
22102            );
22103
22104            let should_replace = match intent {
22105                CompletionIntent::CompleteWithInsert => false,
22106                CompletionIntent::CompleteWithReplace => true,
22107                CompletionIntent::Complete | CompletionIntent::Compose => {
22108                    let insert_mode =
22109                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22110                            .completions
22111                            .lsp_insert_mode;
22112                    match insert_mode {
22113                        LspInsertMode::Insert => false,
22114                        LspInsertMode::Replace => true,
22115                        LspInsertMode::ReplaceSubsequence => {
22116                            let mut text_to_replace = buffer.chars_for_range(
22117                                buffer.anchor_before(replace_range.start)
22118                                    ..buffer.anchor_after(replace_range.end),
22119                            );
22120                            let mut current_needle = text_to_replace.next();
22121                            for haystack_ch in completion.label.text.chars() {
22122                                if let Some(needle_ch) = current_needle
22123                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22124                                {
22125                                    current_needle = text_to_replace.next();
22126                                }
22127                            }
22128                            current_needle.is_none()
22129                        }
22130                        LspInsertMode::ReplaceSuffix => {
22131                            if replace_range
22132                                .end
22133                                .cmp(cursor_position, &buffer_snapshot)
22134                                .is_gt()
22135                            {
22136                                let range_after_cursor = *cursor_position..replace_range.end;
22137                                let text_after_cursor = buffer
22138                                    .text_for_range(
22139                                        buffer.anchor_before(range_after_cursor.start)
22140                                            ..buffer.anchor_after(range_after_cursor.end),
22141                                    )
22142                                    .collect::<String>()
22143                                    .to_ascii_lowercase();
22144                                completion
22145                                    .label
22146                                    .text
22147                                    .to_ascii_lowercase()
22148                                    .ends_with(&text_after_cursor)
22149                            } else {
22150                                true
22151                            }
22152                        }
22153                    }
22154                }
22155            };
22156
22157            if should_replace {
22158                replace_range.clone()
22159            } else {
22160                insert_range.clone()
22161            }
22162        } else {
22163            replace_range.clone()
22164        }
22165    };
22166
22167    if range_to_replace
22168        .end
22169        .cmp(cursor_position, &buffer_snapshot)
22170        .is_lt()
22171    {
22172        range_to_replace.end = *cursor_position;
22173    }
22174
22175    CompletionEdit {
22176        new_text,
22177        replace_range: range_to_replace.to_offset(buffer),
22178        snippet,
22179    }
22180}
22181
22182struct CompletionEdit {
22183    new_text: String,
22184    replace_range: Range<usize>,
22185    snippet: Option<Snippet>,
22186}
22187
22188fn insert_extra_newline_brackets(
22189    buffer: &MultiBufferSnapshot,
22190    range: Range<usize>,
22191    language: &language::LanguageScope,
22192) -> bool {
22193    let leading_whitespace_len = buffer
22194        .reversed_chars_at(range.start)
22195        .take_while(|c| c.is_whitespace() && *c != '\n')
22196        .map(|c| c.len_utf8())
22197        .sum::<usize>();
22198    let trailing_whitespace_len = buffer
22199        .chars_at(range.end)
22200        .take_while(|c| c.is_whitespace() && *c != '\n')
22201        .map(|c| c.len_utf8())
22202        .sum::<usize>();
22203    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22204
22205    language.brackets().any(|(pair, enabled)| {
22206        let pair_start = pair.start.trim_end();
22207        let pair_end = pair.end.trim_start();
22208
22209        enabled
22210            && pair.newline
22211            && buffer.contains_str_at(range.end, pair_end)
22212            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22213    })
22214}
22215
22216fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22217    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22218        [(buffer, range, _)] => (*buffer, range.clone()),
22219        _ => return false,
22220    };
22221    let pair = {
22222        let mut result: Option<BracketMatch> = None;
22223
22224        for pair in buffer
22225            .all_bracket_ranges(range.clone())
22226            .filter(move |pair| {
22227                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22228            })
22229        {
22230            let len = pair.close_range.end - pair.open_range.start;
22231
22232            if let Some(existing) = &result {
22233                let existing_len = existing.close_range.end - existing.open_range.start;
22234                if len > existing_len {
22235                    continue;
22236                }
22237            }
22238
22239            result = Some(pair);
22240        }
22241
22242        result
22243    };
22244    let Some(pair) = pair else {
22245        return false;
22246    };
22247    pair.newline_only
22248        && buffer
22249            .chars_for_range(pair.open_range.end..range.start)
22250            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22251            .all(|c| c.is_whitespace() && c != '\n')
22252}
22253
22254fn update_uncommitted_diff_for_buffer(
22255    editor: Entity<Editor>,
22256    project: &Entity<Project>,
22257    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22258    buffer: Entity<MultiBuffer>,
22259    cx: &mut App,
22260) -> Task<()> {
22261    let mut tasks = Vec::new();
22262    project.update(cx, |project, cx| {
22263        for buffer in buffers {
22264            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22265                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22266            }
22267        }
22268    });
22269    cx.spawn(async move |cx| {
22270        let diffs = future::join_all(tasks).await;
22271        if editor
22272            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22273            .unwrap_or(false)
22274        {
22275            return;
22276        }
22277
22278        buffer
22279            .update(cx, |buffer, cx| {
22280                for diff in diffs.into_iter().flatten() {
22281                    buffer.add_diff(diff, cx);
22282                }
22283            })
22284            .ok();
22285    })
22286}
22287
22288fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22289    let tab_size = tab_size.get() as usize;
22290    let mut width = offset;
22291
22292    for ch in text.chars() {
22293        width += if ch == '\t' {
22294            tab_size - (width % tab_size)
22295        } else {
22296            1
22297        };
22298    }
22299
22300    width - offset
22301}
22302
22303#[cfg(test)]
22304mod tests {
22305    use super::*;
22306
22307    #[test]
22308    fn test_string_size_with_expanded_tabs() {
22309        let nz = |val| NonZeroU32::new(val).unwrap();
22310        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22311        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22312        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22313        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22314        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22315        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22316        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22317        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22318    }
22319}
22320
22321/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22322struct WordBreakingTokenizer<'a> {
22323    input: &'a str,
22324}
22325
22326impl<'a> WordBreakingTokenizer<'a> {
22327    fn new(input: &'a str) -> Self {
22328        Self { input }
22329    }
22330}
22331
22332fn is_char_ideographic(ch: char) -> bool {
22333    use unicode_script::Script::*;
22334    use unicode_script::UnicodeScript;
22335    matches!(ch.script(), Han | Tangut | Yi)
22336}
22337
22338fn is_grapheme_ideographic(text: &str) -> bool {
22339    text.chars().any(is_char_ideographic)
22340}
22341
22342fn is_grapheme_whitespace(text: &str) -> bool {
22343    text.chars().any(|x| x.is_whitespace())
22344}
22345
22346fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22347    text.chars()
22348        .next()
22349        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22350}
22351
22352#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22353enum WordBreakToken<'a> {
22354    Word { token: &'a str, grapheme_len: usize },
22355    InlineWhitespace { token: &'a str, grapheme_len: usize },
22356    Newline,
22357}
22358
22359impl<'a> Iterator for WordBreakingTokenizer<'a> {
22360    /// Yields a span, the count of graphemes in the token, and whether it was
22361    /// whitespace. Note that it also breaks at word boundaries.
22362    type Item = WordBreakToken<'a>;
22363
22364    fn next(&mut self) -> Option<Self::Item> {
22365        use unicode_segmentation::UnicodeSegmentation;
22366        if self.input.is_empty() {
22367            return None;
22368        }
22369
22370        let mut iter = self.input.graphemes(true).peekable();
22371        let mut offset = 0;
22372        let mut grapheme_len = 0;
22373        if let Some(first_grapheme) = iter.next() {
22374            let is_newline = first_grapheme == "\n";
22375            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22376            offset += first_grapheme.len();
22377            grapheme_len += 1;
22378            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22379                if let Some(grapheme) = iter.peek().copied()
22380                    && should_stay_with_preceding_ideograph(grapheme)
22381                {
22382                    offset += grapheme.len();
22383                    grapheme_len += 1;
22384                }
22385            } else {
22386                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22387                let mut next_word_bound = words.peek().copied();
22388                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22389                    next_word_bound = words.next();
22390                }
22391                while let Some(grapheme) = iter.peek().copied() {
22392                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22393                        break;
22394                    };
22395                    if is_grapheme_whitespace(grapheme) != is_whitespace
22396                        || (grapheme == "\n") != is_newline
22397                    {
22398                        break;
22399                    };
22400                    offset += grapheme.len();
22401                    grapheme_len += 1;
22402                    iter.next();
22403                }
22404            }
22405            let token = &self.input[..offset];
22406            self.input = &self.input[offset..];
22407            if token == "\n" {
22408                Some(WordBreakToken::Newline)
22409            } else if is_whitespace {
22410                Some(WordBreakToken::InlineWhitespace {
22411                    token,
22412                    grapheme_len,
22413                })
22414            } else {
22415                Some(WordBreakToken::Word {
22416                    token,
22417                    grapheme_len,
22418                })
22419            }
22420        } else {
22421            None
22422        }
22423    }
22424}
22425
22426#[test]
22427fn test_word_breaking_tokenizer() {
22428    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22429        ("", &[]),
22430        ("  ", &[whitespace("  ", 2)]),
22431        ("Ʒ", &[word("Ʒ", 1)]),
22432        ("Ǽ", &[word("Ǽ", 1)]),
22433        ("", &[word("", 1)]),
22434        ("⋑⋑", &[word("⋑⋑", 2)]),
22435        (
22436            "原理,进而",
22437            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22438        ),
22439        (
22440            "hello world",
22441            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22442        ),
22443        (
22444            "hello, world",
22445            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22446        ),
22447        (
22448            "  hello world",
22449            &[
22450                whitespace("  ", 2),
22451                word("hello", 5),
22452                whitespace(" ", 1),
22453                word("world", 5),
22454            ],
22455        ),
22456        (
22457            "这是什么 \n 钢笔",
22458            &[
22459                word("", 1),
22460                word("", 1),
22461                word("", 1),
22462                word("", 1),
22463                whitespace(" ", 1),
22464                newline(),
22465                whitespace(" ", 1),
22466                word("", 1),
22467                word("", 1),
22468            ],
22469        ),
22470        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22471    ];
22472
22473    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22474        WordBreakToken::Word {
22475            token,
22476            grapheme_len,
22477        }
22478    }
22479
22480    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22481        WordBreakToken::InlineWhitespace {
22482            token,
22483            grapheme_len,
22484        }
22485    }
22486
22487    fn newline() -> WordBreakToken<'static> {
22488        WordBreakToken::Newline
22489    }
22490
22491    for (input, result) in tests {
22492        assert_eq!(
22493            WordBreakingTokenizer::new(input)
22494                .collect::<Vec<_>>()
22495                .as_slice(),
22496            *result,
22497        );
22498    }
22499}
22500
22501fn wrap_with_prefix(
22502    first_line_prefix: String,
22503    subsequent_lines_prefix: String,
22504    unwrapped_text: String,
22505    wrap_column: usize,
22506    tab_size: NonZeroU32,
22507    preserve_existing_whitespace: bool,
22508) -> String {
22509    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22510    let subsequent_lines_prefix_len =
22511        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22512    let mut wrapped_text = String::new();
22513    let mut current_line = first_line_prefix;
22514    let mut is_first_line = true;
22515
22516    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22517    let mut current_line_len = first_line_prefix_len;
22518    let mut in_whitespace = false;
22519    for token in tokenizer {
22520        let have_preceding_whitespace = in_whitespace;
22521        match token {
22522            WordBreakToken::Word {
22523                token,
22524                grapheme_len,
22525            } => {
22526                in_whitespace = false;
22527                let current_prefix_len = if is_first_line {
22528                    first_line_prefix_len
22529                } else {
22530                    subsequent_lines_prefix_len
22531                };
22532                if current_line_len + grapheme_len > wrap_column
22533                    && current_line_len != current_prefix_len
22534                {
22535                    wrapped_text.push_str(current_line.trim_end());
22536                    wrapped_text.push('\n');
22537                    is_first_line = false;
22538                    current_line = subsequent_lines_prefix.clone();
22539                    current_line_len = subsequent_lines_prefix_len;
22540                }
22541                current_line.push_str(token);
22542                current_line_len += grapheme_len;
22543            }
22544            WordBreakToken::InlineWhitespace {
22545                mut token,
22546                mut grapheme_len,
22547            } => {
22548                in_whitespace = true;
22549                if have_preceding_whitespace && !preserve_existing_whitespace {
22550                    continue;
22551                }
22552                if !preserve_existing_whitespace {
22553                    // Keep a single whitespace grapheme as-is
22554                    if let Some(first) =
22555                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22556                    {
22557                        token = first;
22558                    } else {
22559                        token = " ";
22560                    }
22561                    grapheme_len = 1;
22562                }
22563                let current_prefix_len = if is_first_line {
22564                    first_line_prefix_len
22565                } else {
22566                    subsequent_lines_prefix_len
22567                };
22568                if current_line_len + grapheme_len > wrap_column {
22569                    wrapped_text.push_str(current_line.trim_end());
22570                    wrapped_text.push('\n');
22571                    is_first_line = false;
22572                    current_line = subsequent_lines_prefix.clone();
22573                    current_line_len = subsequent_lines_prefix_len;
22574                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22575                    current_line.push_str(token);
22576                    current_line_len += grapheme_len;
22577                }
22578            }
22579            WordBreakToken::Newline => {
22580                in_whitespace = true;
22581                let current_prefix_len = if is_first_line {
22582                    first_line_prefix_len
22583                } else {
22584                    subsequent_lines_prefix_len
22585                };
22586                if preserve_existing_whitespace {
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 have_preceding_whitespace {
22593                    continue;
22594                } else if current_line_len + 1 > wrap_column
22595                    && current_line_len != current_prefix_len
22596                {
22597                    wrapped_text.push_str(current_line.trim_end());
22598                    wrapped_text.push('\n');
22599                    is_first_line = false;
22600                    current_line = subsequent_lines_prefix.clone();
22601                    current_line_len = subsequent_lines_prefix_len;
22602                } else if current_line_len != current_prefix_len {
22603                    current_line.push(' ');
22604                    current_line_len += 1;
22605                }
22606            }
22607        }
22608    }
22609
22610    if !current_line.is_empty() {
22611        wrapped_text.push_str(&current_line);
22612    }
22613    wrapped_text
22614}
22615
22616#[test]
22617fn test_wrap_with_prefix() {
22618    assert_eq!(
22619        wrap_with_prefix(
22620            "# ".to_string(),
22621            "# ".to_string(),
22622            "abcdefg".to_string(),
22623            4,
22624            NonZeroU32::new(4).unwrap(),
22625            false,
22626        ),
22627        "# abcdefg"
22628    );
22629    assert_eq!(
22630        wrap_with_prefix(
22631            "".to_string(),
22632            "".to_string(),
22633            "\thello world".to_string(),
22634            8,
22635            NonZeroU32::new(4).unwrap(),
22636            false,
22637        ),
22638        "hello\nworld"
22639    );
22640    assert_eq!(
22641        wrap_with_prefix(
22642            "// ".to_string(),
22643            "// ".to_string(),
22644            "xx \nyy zz aa bb cc".to_string(),
22645            12,
22646            NonZeroU32::new(4).unwrap(),
22647            false,
22648        ),
22649        "// xx yy zz\n// aa bb cc"
22650    );
22651    assert_eq!(
22652        wrap_with_prefix(
22653            String::new(),
22654            String::new(),
22655            "这是什么 \n 钢笔".to_string(),
22656            3,
22657            NonZeroU32::new(4).unwrap(),
22658            false,
22659        ),
22660        "这是什\n么 钢\n"
22661    );
22662    assert_eq!(
22663        wrap_with_prefix(
22664            String::new(),
22665            String::new(),
22666            format!("foo{}bar", '\u{2009}'), // thin space
22667            80,
22668            NonZeroU32::new(4).unwrap(),
22669            false,
22670        ),
22671        format!("foo{}bar", '\u{2009}')
22672    );
22673}
22674
22675pub trait CollaborationHub {
22676    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22677    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22678    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22679}
22680
22681impl CollaborationHub for Entity<Project> {
22682    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22683        self.read(cx).collaborators()
22684    }
22685
22686    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22687        self.read(cx).user_store().read(cx).participant_indices()
22688    }
22689
22690    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22691        let this = self.read(cx);
22692        let user_ids = this.collaborators().values().map(|c| c.user_id);
22693        this.user_store().read(cx).participant_names(user_ids, cx)
22694    }
22695}
22696
22697pub trait SemanticsProvider {
22698    fn hover(
22699        &self,
22700        buffer: &Entity<Buffer>,
22701        position: text::Anchor,
22702        cx: &mut App,
22703    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22704
22705    fn inline_values(
22706        &self,
22707        buffer_handle: Entity<Buffer>,
22708        range: Range<text::Anchor>,
22709        cx: &mut App,
22710    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22711
22712    fn inlay_hints(
22713        &self,
22714        buffer_handle: Entity<Buffer>,
22715        range: Range<text::Anchor>,
22716        cx: &mut App,
22717    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22718
22719    fn resolve_inlay_hint(
22720        &self,
22721        hint: InlayHint,
22722        buffer_handle: Entity<Buffer>,
22723        server_id: LanguageServerId,
22724        cx: &mut App,
22725    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22726
22727    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22728
22729    fn document_highlights(
22730        &self,
22731        buffer: &Entity<Buffer>,
22732        position: text::Anchor,
22733        cx: &mut App,
22734    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22735
22736    fn definitions(
22737        &self,
22738        buffer: &Entity<Buffer>,
22739        position: text::Anchor,
22740        kind: GotoDefinitionKind,
22741        cx: &mut App,
22742    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22743
22744    fn range_for_rename(
22745        &self,
22746        buffer: &Entity<Buffer>,
22747        position: text::Anchor,
22748        cx: &mut App,
22749    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22750
22751    fn perform_rename(
22752        &self,
22753        buffer: &Entity<Buffer>,
22754        position: text::Anchor,
22755        new_name: String,
22756        cx: &mut App,
22757    ) -> Option<Task<Result<ProjectTransaction>>>;
22758}
22759
22760pub trait CompletionProvider {
22761    fn completions(
22762        &self,
22763        excerpt_id: ExcerptId,
22764        buffer: &Entity<Buffer>,
22765        buffer_position: text::Anchor,
22766        trigger: CompletionContext,
22767        window: &mut Window,
22768        cx: &mut Context<Editor>,
22769    ) -> Task<Result<Vec<CompletionResponse>>>;
22770
22771    fn resolve_completions(
22772        &self,
22773        _buffer: Entity<Buffer>,
22774        _completion_indices: Vec<usize>,
22775        _completions: Rc<RefCell<Box<[Completion]>>>,
22776        _cx: &mut Context<Editor>,
22777    ) -> Task<Result<bool>> {
22778        Task::ready(Ok(false))
22779    }
22780
22781    fn apply_additional_edits_for_completion(
22782        &self,
22783        _buffer: Entity<Buffer>,
22784        _completions: Rc<RefCell<Box<[Completion]>>>,
22785        _completion_index: usize,
22786        _push_to_history: bool,
22787        _cx: &mut Context<Editor>,
22788    ) -> Task<Result<Option<language::Transaction>>> {
22789        Task::ready(Ok(None))
22790    }
22791
22792    fn is_completion_trigger(
22793        &self,
22794        buffer: &Entity<Buffer>,
22795        position: language::Anchor,
22796        text: &str,
22797        trigger_in_words: bool,
22798        menu_is_open: bool,
22799        cx: &mut Context<Editor>,
22800    ) -> bool;
22801
22802    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22803
22804    fn sort_completions(&self) -> bool {
22805        true
22806    }
22807
22808    fn filter_completions(&self) -> bool {
22809        true
22810    }
22811}
22812
22813pub trait CodeActionProvider {
22814    fn id(&self) -> Arc<str>;
22815
22816    fn code_actions(
22817        &self,
22818        buffer: &Entity<Buffer>,
22819        range: Range<text::Anchor>,
22820        window: &mut Window,
22821        cx: &mut App,
22822    ) -> Task<Result<Vec<CodeAction>>>;
22823
22824    fn apply_code_action(
22825        &self,
22826        buffer_handle: Entity<Buffer>,
22827        action: CodeAction,
22828        excerpt_id: ExcerptId,
22829        push_to_history: bool,
22830        window: &mut Window,
22831        cx: &mut App,
22832    ) -> Task<Result<ProjectTransaction>>;
22833}
22834
22835impl CodeActionProvider for Entity<Project> {
22836    fn id(&self) -> Arc<str> {
22837        "project".into()
22838    }
22839
22840    fn code_actions(
22841        &self,
22842        buffer: &Entity<Buffer>,
22843        range: Range<text::Anchor>,
22844        _window: &mut Window,
22845        cx: &mut App,
22846    ) -> Task<Result<Vec<CodeAction>>> {
22847        self.update(cx, |project, cx| {
22848            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22849            let code_actions = project.code_actions(buffer, range, None, cx);
22850            cx.background_spawn(async move {
22851                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22852                Ok(code_lens_actions
22853                    .context("code lens fetch")?
22854                    .into_iter()
22855                    .flatten()
22856                    .chain(
22857                        code_actions
22858                            .context("code action fetch")?
22859                            .into_iter()
22860                            .flatten(),
22861                    )
22862                    .collect())
22863            })
22864        })
22865    }
22866
22867    fn apply_code_action(
22868        &self,
22869        buffer_handle: Entity<Buffer>,
22870        action: CodeAction,
22871        _excerpt_id: ExcerptId,
22872        push_to_history: bool,
22873        _window: &mut Window,
22874        cx: &mut App,
22875    ) -> Task<Result<ProjectTransaction>> {
22876        self.update(cx, |project, cx| {
22877            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22878        })
22879    }
22880}
22881
22882fn snippet_completions(
22883    project: &Project,
22884    buffer: &Entity<Buffer>,
22885    buffer_position: text::Anchor,
22886    cx: &mut App,
22887) -> Task<Result<CompletionResponse>> {
22888    let languages = buffer.read(cx).languages_at(buffer_position);
22889    let snippet_store = project.snippets().read(cx);
22890
22891    let scopes: Vec<_> = languages
22892        .iter()
22893        .filter_map(|language| {
22894            let language_name = language.lsp_id();
22895            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22896
22897            if snippets.is_empty() {
22898                None
22899            } else {
22900                Some((language.default_scope(), snippets))
22901            }
22902        })
22903        .collect();
22904
22905    if scopes.is_empty() {
22906        return Task::ready(Ok(CompletionResponse {
22907            completions: vec![],
22908            display_options: CompletionDisplayOptions::default(),
22909            is_incomplete: false,
22910        }));
22911    }
22912
22913    let snapshot = buffer.read(cx).text_snapshot();
22914    let executor = cx.background_executor().clone();
22915
22916    cx.background_spawn(async move {
22917        let mut is_incomplete = false;
22918        let mut completions: Vec<Completion> = Vec::new();
22919        for (scope, snippets) in scopes.into_iter() {
22920            let classifier =
22921                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22922
22923            const MAX_WORD_PREFIX_LEN: usize = 128;
22924            let last_word: String = snapshot
22925                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22926                .take(MAX_WORD_PREFIX_LEN)
22927                .take_while(|c| classifier.is_word(*c))
22928                .collect::<String>()
22929                .chars()
22930                .rev()
22931                .collect();
22932
22933            if last_word.is_empty() {
22934                return Ok(CompletionResponse {
22935                    completions: vec![],
22936                    display_options: CompletionDisplayOptions::default(),
22937                    is_incomplete: true,
22938                });
22939            }
22940
22941            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22942            let to_lsp = |point: &text::Anchor| {
22943                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22944                point_to_lsp(end)
22945            };
22946            let lsp_end = to_lsp(&buffer_position);
22947
22948            let candidates = snippets
22949                .iter()
22950                .enumerate()
22951                .flat_map(|(ix, snippet)| {
22952                    snippet
22953                        .prefix
22954                        .iter()
22955                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22956                })
22957                .collect::<Vec<StringMatchCandidate>>();
22958
22959            const MAX_RESULTS: usize = 100;
22960            let mut matches = fuzzy::match_strings(
22961                &candidates,
22962                &last_word,
22963                last_word.chars().any(|c| c.is_uppercase()),
22964                true,
22965                MAX_RESULTS,
22966                &Default::default(),
22967                executor.clone(),
22968            )
22969            .await;
22970
22971            if matches.len() >= MAX_RESULTS {
22972                is_incomplete = true;
22973            }
22974
22975            // Remove all candidates where the query's start does not match the start of any word in the candidate
22976            if let Some(query_start) = last_word.chars().next() {
22977                matches.retain(|string_match| {
22978                    split_words(&string_match.string).any(|word| {
22979                        // Check that the first codepoint of the word as lowercase matches the first
22980                        // codepoint of the query as lowercase
22981                        word.chars()
22982                            .flat_map(|codepoint| codepoint.to_lowercase())
22983                            .zip(query_start.to_lowercase())
22984                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22985                    })
22986                });
22987            }
22988
22989            let matched_strings = matches
22990                .into_iter()
22991                .map(|m| m.string)
22992                .collect::<HashSet<_>>();
22993
22994            completions.extend(snippets.iter().filter_map(|snippet| {
22995                let matching_prefix = snippet
22996                    .prefix
22997                    .iter()
22998                    .find(|prefix| matched_strings.contains(*prefix))?;
22999                let start = as_offset - last_word.len();
23000                let start = snapshot.anchor_before(start);
23001                let range = start..buffer_position;
23002                let lsp_start = to_lsp(&start);
23003                let lsp_range = lsp::Range {
23004                    start: lsp_start,
23005                    end: lsp_end,
23006                };
23007                Some(Completion {
23008                    replace_range: range,
23009                    new_text: snippet.body.clone(),
23010                    source: CompletionSource::Lsp {
23011                        insert_range: None,
23012                        server_id: LanguageServerId(usize::MAX),
23013                        resolved: true,
23014                        lsp_completion: Box::new(lsp::CompletionItem {
23015                            label: snippet.prefix.first().unwrap().clone(),
23016                            kind: Some(CompletionItemKind::SNIPPET),
23017                            label_details: snippet.description.as_ref().map(|description| {
23018                                lsp::CompletionItemLabelDetails {
23019                                    detail: Some(description.clone()),
23020                                    description: None,
23021                                }
23022                            }),
23023                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23024                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23025                                lsp::InsertReplaceEdit {
23026                                    new_text: snippet.body.clone(),
23027                                    insert: lsp_range,
23028                                    replace: lsp_range,
23029                                },
23030                            )),
23031                            filter_text: Some(snippet.body.clone()),
23032                            sort_text: Some(char::MAX.to_string()),
23033                            ..lsp::CompletionItem::default()
23034                        }),
23035                        lsp_defaults: None,
23036                    },
23037                    label: CodeLabel {
23038                        text: matching_prefix.clone(),
23039                        runs: Vec::new(),
23040                        filter_range: 0..matching_prefix.len(),
23041                    },
23042                    icon_path: None,
23043                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23044                        single_line: snippet.name.clone().into(),
23045                        plain_text: snippet
23046                            .description
23047                            .clone()
23048                            .map(|description| description.into()),
23049                    }),
23050                    insert_text_mode: None,
23051                    confirm: None,
23052                })
23053            }))
23054        }
23055
23056        Ok(CompletionResponse {
23057            completions,
23058            display_options: CompletionDisplayOptions::default(),
23059            is_incomplete,
23060        })
23061    })
23062}
23063
23064impl CompletionProvider for Entity<Project> {
23065    fn completions(
23066        &self,
23067        _excerpt_id: ExcerptId,
23068        buffer: &Entity<Buffer>,
23069        buffer_position: text::Anchor,
23070        options: CompletionContext,
23071        _window: &mut Window,
23072        cx: &mut Context<Editor>,
23073    ) -> Task<Result<Vec<CompletionResponse>>> {
23074        self.update(cx, |project, cx| {
23075            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23076            let project_completions = project.completions(buffer, buffer_position, options, cx);
23077            cx.background_spawn(async move {
23078                let mut responses = project_completions.await?;
23079                let snippets = snippets.await?;
23080                if !snippets.completions.is_empty() {
23081                    responses.push(snippets);
23082                }
23083                Ok(responses)
23084            })
23085        })
23086    }
23087
23088    fn resolve_completions(
23089        &self,
23090        buffer: Entity<Buffer>,
23091        completion_indices: Vec<usize>,
23092        completions: Rc<RefCell<Box<[Completion]>>>,
23093        cx: &mut Context<Editor>,
23094    ) -> Task<Result<bool>> {
23095        self.update(cx, |project, cx| {
23096            project.lsp_store().update(cx, |lsp_store, cx| {
23097                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23098            })
23099        })
23100    }
23101
23102    fn apply_additional_edits_for_completion(
23103        &self,
23104        buffer: Entity<Buffer>,
23105        completions: Rc<RefCell<Box<[Completion]>>>,
23106        completion_index: usize,
23107        push_to_history: bool,
23108        cx: &mut Context<Editor>,
23109    ) -> Task<Result<Option<language::Transaction>>> {
23110        self.update(cx, |project, cx| {
23111            project.lsp_store().update(cx, |lsp_store, cx| {
23112                lsp_store.apply_additional_edits_for_completion(
23113                    buffer,
23114                    completions,
23115                    completion_index,
23116                    push_to_history,
23117                    cx,
23118                )
23119            })
23120        })
23121    }
23122
23123    fn is_completion_trigger(
23124        &self,
23125        buffer: &Entity<Buffer>,
23126        position: language::Anchor,
23127        text: &str,
23128        trigger_in_words: bool,
23129        menu_is_open: bool,
23130        cx: &mut Context<Editor>,
23131    ) -> bool {
23132        let mut chars = text.chars();
23133        let char = if let Some(char) = chars.next() {
23134            char
23135        } else {
23136            return false;
23137        };
23138        if chars.next().is_some() {
23139            return false;
23140        }
23141
23142        let buffer = buffer.read(cx);
23143        let snapshot = buffer.snapshot();
23144        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23145            return false;
23146        }
23147        let classifier = snapshot
23148            .char_classifier_at(position)
23149            .scope_context(Some(CharScopeContext::Completion));
23150        if trigger_in_words && classifier.is_word(char) {
23151            return true;
23152        }
23153
23154        buffer.completion_triggers().contains(text)
23155    }
23156}
23157
23158impl SemanticsProvider for Entity<Project> {
23159    fn hover(
23160        &self,
23161        buffer: &Entity<Buffer>,
23162        position: text::Anchor,
23163        cx: &mut App,
23164    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23165        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23166    }
23167
23168    fn document_highlights(
23169        &self,
23170        buffer: &Entity<Buffer>,
23171        position: text::Anchor,
23172        cx: &mut App,
23173    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23174        Some(self.update(cx, |project, cx| {
23175            project.document_highlights(buffer, position, cx)
23176        }))
23177    }
23178
23179    fn definitions(
23180        &self,
23181        buffer: &Entity<Buffer>,
23182        position: text::Anchor,
23183        kind: GotoDefinitionKind,
23184        cx: &mut App,
23185    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23186        Some(self.update(cx, |project, cx| match kind {
23187            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23188            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23189            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23190            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23191        }))
23192    }
23193
23194    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23195        self.update(cx, |project, cx| {
23196            if project
23197                .active_debug_session(cx)
23198                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23199            {
23200                return true;
23201            }
23202
23203            buffer.update(cx, |buffer, cx| {
23204                project.any_language_server_supports_inlay_hints(buffer, cx)
23205            })
23206        })
23207    }
23208
23209    fn inline_values(
23210        &self,
23211        buffer_handle: Entity<Buffer>,
23212        range: Range<text::Anchor>,
23213        cx: &mut App,
23214    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23215        self.update(cx, |project, cx| {
23216            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23217
23218            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23219        })
23220    }
23221
23222    fn inlay_hints(
23223        &self,
23224        buffer_handle: Entity<Buffer>,
23225        range: Range<text::Anchor>,
23226        cx: &mut App,
23227    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23228        Some(self.update(cx, |project, cx| {
23229            project.inlay_hints(buffer_handle, range, cx)
23230        }))
23231    }
23232
23233    fn resolve_inlay_hint(
23234        &self,
23235        hint: InlayHint,
23236        buffer_handle: Entity<Buffer>,
23237        server_id: LanguageServerId,
23238        cx: &mut App,
23239    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23240        Some(self.update(cx, |project, cx| {
23241            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23242        }))
23243    }
23244
23245    fn range_for_rename(
23246        &self,
23247        buffer: &Entity<Buffer>,
23248        position: text::Anchor,
23249        cx: &mut App,
23250    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23251        Some(self.update(cx, |project, cx| {
23252            let buffer = buffer.clone();
23253            let task = project.prepare_rename(buffer.clone(), position, cx);
23254            cx.spawn(async move |_, cx| {
23255                Ok(match task.await? {
23256                    PrepareRenameResponse::Success(range) => Some(range),
23257                    PrepareRenameResponse::InvalidPosition => None,
23258                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23259                        // Fallback on using TreeSitter info to determine identifier range
23260                        buffer.read_with(cx, |buffer, _| {
23261                            let snapshot = buffer.snapshot();
23262                            let (range, kind) = snapshot.surrounding_word(position, None);
23263                            if kind != Some(CharKind::Word) {
23264                                return None;
23265                            }
23266                            Some(
23267                                snapshot.anchor_before(range.start)
23268                                    ..snapshot.anchor_after(range.end),
23269                            )
23270                        })?
23271                    }
23272                })
23273            })
23274        }))
23275    }
23276
23277    fn perform_rename(
23278        &self,
23279        buffer: &Entity<Buffer>,
23280        position: text::Anchor,
23281        new_name: String,
23282        cx: &mut App,
23283    ) -> Option<Task<Result<ProjectTransaction>>> {
23284        Some(self.update(cx, |project, cx| {
23285            project.perform_rename(buffer.clone(), position, new_name, cx)
23286        }))
23287    }
23288}
23289
23290fn inlay_hint_settings(
23291    location: Anchor,
23292    snapshot: &MultiBufferSnapshot,
23293    cx: &mut Context<Editor>,
23294) -> InlayHintSettings {
23295    let file = snapshot.file_at(location);
23296    let language = snapshot.language_at(location).map(|l| l.name());
23297    language_settings(language, file, cx).inlay_hints
23298}
23299
23300fn consume_contiguous_rows(
23301    contiguous_row_selections: &mut Vec<Selection<Point>>,
23302    selection: &Selection<Point>,
23303    display_map: &DisplaySnapshot,
23304    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23305) -> (MultiBufferRow, MultiBufferRow) {
23306    contiguous_row_selections.push(selection.clone());
23307    let start_row = starting_row(selection, display_map);
23308    let mut end_row = ending_row(selection, display_map);
23309
23310    while let Some(next_selection) = selections.peek() {
23311        if next_selection.start.row <= end_row.0 {
23312            end_row = ending_row(next_selection, display_map);
23313            contiguous_row_selections.push(selections.next().unwrap().clone());
23314        } else {
23315            break;
23316        }
23317    }
23318    (start_row, end_row)
23319}
23320
23321fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23322    if selection.start.column > 0 {
23323        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23324    } else {
23325        MultiBufferRow(selection.start.row)
23326    }
23327}
23328
23329fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23330    if next_selection.end.column > 0 || next_selection.is_empty() {
23331        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23332    } else {
23333        MultiBufferRow(next_selection.end.row)
23334    }
23335}
23336
23337impl EditorSnapshot {
23338    pub fn remote_selections_in_range<'a>(
23339        &'a self,
23340        range: &'a Range<Anchor>,
23341        collaboration_hub: &dyn CollaborationHub,
23342        cx: &'a App,
23343    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23344        let participant_names = collaboration_hub.user_names(cx);
23345        let participant_indices = collaboration_hub.user_participant_indices(cx);
23346        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23347        let collaborators_by_replica_id = collaborators_by_peer_id
23348            .values()
23349            .map(|collaborator| (collaborator.replica_id, collaborator))
23350            .collect::<HashMap<_, _>>();
23351        self.buffer_snapshot()
23352            .selections_in_range(range, false)
23353            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23354                if replica_id == AGENT_REPLICA_ID {
23355                    Some(RemoteSelection {
23356                        replica_id,
23357                        selection,
23358                        cursor_shape,
23359                        line_mode,
23360                        collaborator_id: CollaboratorId::Agent,
23361                        user_name: Some("Agent".into()),
23362                        color: cx.theme().players().agent(),
23363                    })
23364                } else {
23365                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23366                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23367                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23368                    Some(RemoteSelection {
23369                        replica_id,
23370                        selection,
23371                        cursor_shape,
23372                        line_mode,
23373                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23374                        user_name,
23375                        color: if let Some(index) = participant_index {
23376                            cx.theme().players().color_for_participant(index.0)
23377                        } else {
23378                            cx.theme().players().absent()
23379                        },
23380                    })
23381                }
23382            })
23383    }
23384
23385    pub fn hunks_for_ranges(
23386        &self,
23387        ranges: impl IntoIterator<Item = Range<Point>>,
23388    ) -> Vec<MultiBufferDiffHunk> {
23389        let mut hunks = Vec::new();
23390        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23391            HashMap::default();
23392        for query_range in ranges {
23393            let query_rows =
23394                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23395            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23396                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23397            ) {
23398                // Include deleted hunks that are adjacent to the query range, because
23399                // otherwise they would be missed.
23400                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23401                if hunk.status().is_deleted() {
23402                    intersects_range |= hunk.row_range.start == query_rows.end;
23403                    intersects_range |= hunk.row_range.end == query_rows.start;
23404                }
23405                if intersects_range {
23406                    if !processed_buffer_rows
23407                        .entry(hunk.buffer_id)
23408                        .or_default()
23409                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23410                    {
23411                        continue;
23412                    }
23413                    hunks.push(hunk);
23414                }
23415            }
23416        }
23417
23418        hunks
23419    }
23420
23421    fn display_diff_hunks_for_rows<'a>(
23422        &'a self,
23423        display_rows: Range<DisplayRow>,
23424        folded_buffers: &'a HashSet<BufferId>,
23425    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23426        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23427        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23428
23429        self.buffer_snapshot()
23430            .diff_hunks_in_range(buffer_start..buffer_end)
23431            .filter_map(|hunk| {
23432                if folded_buffers.contains(&hunk.buffer_id) {
23433                    return None;
23434                }
23435
23436                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23437                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23438
23439                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23440                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23441
23442                let display_hunk = if hunk_display_start.column() != 0 {
23443                    DisplayDiffHunk::Folded {
23444                        display_row: hunk_display_start.row(),
23445                    }
23446                } else {
23447                    let mut end_row = hunk_display_end.row();
23448                    if hunk_display_end.column() > 0 {
23449                        end_row.0 += 1;
23450                    }
23451                    let is_created_file = hunk.is_created_file();
23452                    DisplayDiffHunk::Unfolded {
23453                        status: hunk.status(),
23454                        diff_base_byte_range: hunk.diff_base_byte_range,
23455                        display_row_range: hunk_display_start.row()..end_row,
23456                        multi_buffer_range: Anchor::range_in_buffer(
23457                            hunk.excerpt_id,
23458                            hunk.buffer_id,
23459                            hunk.buffer_range,
23460                        ),
23461                        is_created_file,
23462                    }
23463                };
23464
23465                Some(display_hunk)
23466            })
23467    }
23468
23469    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23470        self.display_snapshot
23471            .buffer_snapshot()
23472            .language_at(position)
23473    }
23474
23475    pub fn is_focused(&self) -> bool {
23476        self.is_focused
23477    }
23478
23479    pub fn placeholder_text(&self) -> Option<String> {
23480        self.placeholder_display_snapshot
23481            .as_ref()
23482            .map(|display_map| display_map.text())
23483    }
23484
23485    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23486        self.scroll_anchor.scroll_position(&self.display_snapshot)
23487    }
23488
23489    fn gutter_dimensions(
23490        &self,
23491        font_id: FontId,
23492        font_size: Pixels,
23493        max_line_number_width: Pixels,
23494        cx: &App,
23495    ) -> Option<GutterDimensions> {
23496        if !self.show_gutter {
23497            return None;
23498        }
23499
23500        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23501        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23502
23503        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23504            matches!(
23505                ProjectSettings::get_global(cx).git.git_gutter,
23506                GitGutterSetting::TrackedFiles
23507            )
23508        });
23509        let gutter_settings = EditorSettings::get_global(cx).gutter;
23510        let show_line_numbers = self
23511            .show_line_numbers
23512            .unwrap_or(gutter_settings.line_numbers);
23513        let line_gutter_width = if show_line_numbers {
23514            // Avoid flicker-like gutter resizes when the line number gains another digit by
23515            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23516            let min_width_for_number_on_gutter =
23517                ch_advance * gutter_settings.min_line_number_digits as f32;
23518            max_line_number_width.max(min_width_for_number_on_gutter)
23519        } else {
23520            0.0.into()
23521        };
23522
23523        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23524        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23525
23526        let git_blame_entries_width =
23527            self.git_blame_gutter_max_author_length
23528                .map(|max_author_length| {
23529                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23530                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23531
23532                    /// The number of characters to dedicate to gaps and margins.
23533                    const SPACING_WIDTH: usize = 4;
23534
23535                    let max_char_count = max_author_length.min(renderer.max_author_length())
23536                        + ::git::SHORT_SHA_LENGTH
23537                        + MAX_RELATIVE_TIMESTAMP.len()
23538                        + SPACING_WIDTH;
23539
23540                    ch_advance * max_char_count
23541                });
23542
23543        let is_singleton = self.buffer_snapshot().is_singleton();
23544
23545        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23546        left_padding += if !is_singleton {
23547            ch_width * 4.0
23548        } else if show_runnables || show_breakpoints {
23549            ch_width * 3.0
23550        } else if show_git_gutter && show_line_numbers {
23551            ch_width * 2.0
23552        } else if show_git_gutter || show_line_numbers {
23553            ch_width
23554        } else {
23555            px(0.)
23556        };
23557
23558        let shows_folds = is_singleton && gutter_settings.folds;
23559
23560        let right_padding = if shows_folds && show_line_numbers {
23561            ch_width * 4.0
23562        } else if shows_folds || (!is_singleton && show_line_numbers) {
23563            ch_width * 3.0
23564        } else if show_line_numbers {
23565            ch_width
23566        } else {
23567            px(0.)
23568        };
23569
23570        Some(GutterDimensions {
23571            left_padding,
23572            right_padding,
23573            width: line_gutter_width + left_padding + right_padding,
23574            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23575            git_blame_entries_width,
23576        })
23577    }
23578
23579    pub fn render_crease_toggle(
23580        &self,
23581        buffer_row: MultiBufferRow,
23582        row_contains_cursor: bool,
23583        editor: Entity<Editor>,
23584        window: &mut Window,
23585        cx: &mut App,
23586    ) -> Option<AnyElement> {
23587        let folded = self.is_line_folded(buffer_row);
23588        let mut is_foldable = false;
23589
23590        if let Some(crease) = self
23591            .crease_snapshot
23592            .query_row(buffer_row, self.buffer_snapshot())
23593        {
23594            is_foldable = true;
23595            match crease {
23596                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23597                    if let Some(render_toggle) = render_toggle {
23598                        let toggle_callback =
23599                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23600                                if folded {
23601                                    editor.update(cx, |editor, cx| {
23602                                        editor.fold_at(buffer_row, window, cx)
23603                                    });
23604                                } else {
23605                                    editor.update(cx, |editor, cx| {
23606                                        editor.unfold_at(buffer_row, window, cx)
23607                                    });
23608                                }
23609                            });
23610                        return Some((render_toggle)(
23611                            buffer_row,
23612                            folded,
23613                            toggle_callback,
23614                            window,
23615                            cx,
23616                        ));
23617                    }
23618                }
23619            }
23620        }
23621
23622        is_foldable |= self.starts_indent(buffer_row);
23623
23624        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23625            Some(
23626                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23627                    .toggle_state(folded)
23628                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23629                        if folded {
23630                            this.unfold_at(buffer_row, window, cx);
23631                        } else {
23632                            this.fold_at(buffer_row, window, cx);
23633                        }
23634                    }))
23635                    .into_any_element(),
23636            )
23637        } else {
23638            None
23639        }
23640    }
23641
23642    pub fn render_crease_trailer(
23643        &self,
23644        buffer_row: MultiBufferRow,
23645        window: &mut Window,
23646        cx: &mut App,
23647    ) -> Option<AnyElement> {
23648        let folded = self.is_line_folded(buffer_row);
23649        if let Crease::Inline { render_trailer, .. } = self
23650            .crease_snapshot
23651            .query_row(buffer_row, self.buffer_snapshot())?
23652        {
23653            let render_trailer = render_trailer.as_ref()?;
23654            Some(render_trailer(buffer_row, folded, window, cx))
23655        } else {
23656            None
23657        }
23658    }
23659}
23660
23661impl Deref for EditorSnapshot {
23662    type Target = DisplaySnapshot;
23663
23664    fn deref(&self) -> &Self::Target {
23665        &self.display_snapshot
23666    }
23667}
23668
23669#[derive(Clone, Debug, PartialEq, Eq)]
23670pub enum EditorEvent {
23671    InputIgnored {
23672        text: Arc<str>,
23673    },
23674    InputHandled {
23675        utf16_range_to_replace: Option<Range<isize>>,
23676        text: Arc<str>,
23677    },
23678    ExcerptsAdded {
23679        buffer: Entity<Buffer>,
23680        predecessor: ExcerptId,
23681        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23682    },
23683    ExcerptsRemoved {
23684        ids: Vec<ExcerptId>,
23685        removed_buffer_ids: Vec<BufferId>,
23686    },
23687    BufferFoldToggled {
23688        ids: Vec<ExcerptId>,
23689        folded: bool,
23690    },
23691    ExcerptsEdited {
23692        ids: Vec<ExcerptId>,
23693    },
23694    ExcerptsExpanded {
23695        ids: Vec<ExcerptId>,
23696    },
23697    BufferEdited,
23698    Edited {
23699        transaction_id: clock::Lamport,
23700    },
23701    Reparsed(BufferId),
23702    Focused,
23703    FocusedIn,
23704    Blurred,
23705    DirtyChanged,
23706    Saved,
23707    TitleChanged,
23708    SelectionsChanged {
23709        local: bool,
23710    },
23711    ScrollPositionChanged {
23712        local: bool,
23713        autoscroll: bool,
23714    },
23715    TransactionUndone {
23716        transaction_id: clock::Lamport,
23717    },
23718    TransactionBegun {
23719        transaction_id: clock::Lamport,
23720    },
23721    CursorShapeChanged,
23722    BreadcrumbsChanged,
23723    PushedToNavHistory {
23724        anchor: Anchor,
23725        is_deactivate: bool,
23726    },
23727}
23728
23729impl EventEmitter<EditorEvent> for Editor {}
23730
23731impl Focusable for Editor {
23732    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23733        self.focus_handle.clone()
23734    }
23735}
23736
23737impl Render for Editor {
23738    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23739        let settings = ThemeSettings::get_global(cx);
23740
23741        let mut text_style = match self.mode {
23742            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23743                color: cx.theme().colors().editor_foreground,
23744                font_family: settings.ui_font.family.clone(),
23745                font_features: settings.ui_font.features.clone(),
23746                font_fallbacks: settings.ui_font.fallbacks.clone(),
23747                font_size: rems(0.875).into(),
23748                font_weight: settings.ui_font.weight,
23749                line_height: relative(settings.buffer_line_height.value()),
23750                ..Default::default()
23751            },
23752            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23753                color: cx.theme().colors().editor_foreground,
23754                font_family: settings.buffer_font.family.clone(),
23755                font_features: settings.buffer_font.features.clone(),
23756                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23757                font_size: settings.buffer_font_size(cx).into(),
23758                font_weight: settings.buffer_font.weight,
23759                line_height: relative(settings.buffer_line_height.value()),
23760                ..Default::default()
23761            },
23762        };
23763        if let Some(text_style_refinement) = &self.text_style_refinement {
23764            text_style.refine(text_style_refinement)
23765        }
23766
23767        let background = match self.mode {
23768            EditorMode::SingleLine => cx.theme().system().transparent,
23769            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23770            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23771            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23772        };
23773
23774        EditorElement::new(
23775            &cx.entity(),
23776            EditorStyle {
23777                background,
23778                border: cx.theme().colors().border,
23779                local_player: cx.theme().players().local(),
23780                text: text_style,
23781                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23782                syntax: cx.theme().syntax().clone(),
23783                status: cx.theme().status().clone(),
23784                inlay_hints_style: make_inlay_hints_style(cx),
23785                edit_prediction_styles: make_suggestion_styles(cx),
23786                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23787                show_underlines: self.diagnostics_enabled(),
23788            },
23789        )
23790    }
23791}
23792
23793impl EntityInputHandler for Editor {
23794    fn text_for_range(
23795        &mut self,
23796        range_utf16: Range<usize>,
23797        adjusted_range: &mut Option<Range<usize>>,
23798        _: &mut Window,
23799        cx: &mut Context<Self>,
23800    ) -> Option<String> {
23801        let snapshot = self.buffer.read(cx).read(cx);
23802        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23803        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23804        if (start.0..end.0) != range_utf16 {
23805            adjusted_range.replace(start.0..end.0);
23806        }
23807        Some(snapshot.text_for_range(start..end).collect())
23808    }
23809
23810    fn selected_text_range(
23811        &mut self,
23812        ignore_disabled_input: bool,
23813        _: &mut Window,
23814        cx: &mut Context<Self>,
23815    ) -> Option<UTF16Selection> {
23816        // Prevent the IME menu from appearing when holding down an alphabetic key
23817        // while input is disabled.
23818        if !ignore_disabled_input && !self.input_enabled {
23819            return None;
23820        }
23821
23822        let selection = self.selections.newest::<OffsetUtf16>(cx);
23823        let range = selection.range();
23824
23825        Some(UTF16Selection {
23826            range: range.start.0..range.end.0,
23827            reversed: selection.reversed,
23828        })
23829    }
23830
23831    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23832        let snapshot = self.buffer.read(cx).read(cx);
23833        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23834        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23835    }
23836
23837    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23838        self.clear_highlights::<InputComposition>(cx);
23839        self.ime_transaction.take();
23840    }
23841
23842    fn replace_text_in_range(
23843        &mut self,
23844        range_utf16: Option<Range<usize>>,
23845        text: &str,
23846        window: &mut Window,
23847        cx: &mut Context<Self>,
23848    ) {
23849        if !self.input_enabled {
23850            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23851            return;
23852        }
23853
23854        self.transact(window, cx, |this, window, cx| {
23855            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23856                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23857                Some(this.selection_replacement_ranges(range_utf16, cx))
23858            } else {
23859                this.marked_text_ranges(cx)
23860            };
23861
23862            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23863                let newest_selection_id = this.selections.newest_anchor().id;
23864                this.selections
23865                    .all::<OffsetUtf16>(cx)
23866                    .iter()
23867                    .zip(ranges_to_replace.iter())
23868                    .find_map(|(selection, range)| {
23869                        if selection.id == newest_selection_id {
23870                            Some(
23871                                (range.start.0 as isize - selection.head().0 as isize)
23872                                    ..(range.end.0 as isize - selection.head().0 as isize),
23873                            )
23874                        } else {
23875                            None
23876                        }
23877                    })
23878            });
23879
23880            cx.emit(EditorEvent::InputHandled {
23881                utf16_range_to_replace: range_to_replace,
23882                text: text.into(),
23883            });
23884
23885            if let Some(new_selected_ranges) = new_selected_ranges {
23886                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23887                    selections.select_ranges(new_selected_ranges)
23888                });
23889                this.backspace(&Default::default(), window, cx);
23890            }
23891
23892            this.handle_input(text, window, cx);
23893        });
23894
23895        if let Some(transaction) = self.ime_transaction {
23896            self.buffer.update(cx, |buffer, cx| {
23897                buffer.group_until_transaction(transaction, cx);
23898            });
23899        }
23900
23901        self.unmark_text(window, cx);
23902    }
23903
23904    fn replace_and_mark_text_in_range(
23905        &mut self,
23906        range_utf16: Option<Range<usize>>,
23907        text: &str,
23908        new_selected_range_utf16: Option<Range<usize>>,
23909        window: &mut Window,
23910        cx: &mut Context<Self>,
23911    ) {
23912        if !self.input_enabled {
23913            return;
23914        }
23915
23916        let transaction = self.transact(window, cx, |this, window, cx| {
23917            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23918                let snapshot = this.buffer.read(cx).read(cx);
23919                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23920                    for marked_range in &mut marked_ranges {
23921                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23922                        marked_range.start.0 += relative_range_utf16.start;
23923                        marked_range.start =
23924                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23925                        marked_range.end =
23926                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23927                    }
23928                }
23929                Some(marked_ranges)
23930            } else if let Some(range_utf16) = range_utf16 {
23931                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23932                Some(this.selection_replacement_ranges(range_utf16, cx))
23933            } else {
23934                None
23935            };
23936
23937            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23938                let newest_selection_id = this.selections.newest_anchor().id;
23939                this.selections
23940                    .all::<OffsetUtf16>(cx)
23941                    .iter()
23942                    .zip(ranges_to_replace.iter())
23943                    .find_map(|(selection, range)| {
23944                        if selection.id == newest_selection_id {
23945                            Some(
23946                                (range.start.0 as isize - selection.head().0 as isize)
23947                                    ..(range.end.0 as isize - selection.head().0 as isize),
23948                            )
23949                        } else {
23950                            None
23951                        }
23952                    })
23953            });
23954
23955            cx.emit(EditorEvent::InputHandled {
23956                utf16_range_to_replace: range_to_replace,
23957                text: text.into(),
23958            });
23959
23960            if let Some(ranges) = ranges_to_replace {
23961                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23962                    s.select_ranges(ranges)
23963                });
23964            }
23965
23966            let marked_ranges = {
23967                let snapshot = this.buffer.read(cx).read(cx);
23968                this.selections
23969                    .disjoint_anchors_arc()
23970                    .iter()
23971                    .map(|selection| {
23972                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23973                    })
23974                    .collect::<Vec<_>>()
23975            };
23976
23977            if text.is_empty() {
23978                this.unmark_text(window, cx);
23979            } else {
23980                this.highlight_text::<InputComposition>(
23981                    marked_ranges.clone(),
23982                    HighlightStyle {
23983                        underline: Some(UnderlineStyle {
23984                            thickness: px(1.),
23985                            color: None,
23986                            wavy: false,
23987                        }),
23988                        ..Default::default()
23989                    },
23990                    cx,
23991                );
23992            }
23993
23994            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23995            let use_autoclose = this.use_autoclose;
23996            let use_auto_surround = this.use_auto_surround;
23997            this.set_use_autoclose(false);
23998            this.set_use_auto_surround(false);
23999            this.handle_input(text, window, cx);
24000            this.set_use_autoclose(use_autoclose);
24001            this.set_use_auto_surround(use_auto_surround);
24002
24003            if let Some(new_selected_range) = new_selected_range_utf16 {
24004                let snapshot = this.buffer.read(cx).read(cx);
24005                let new_selected_ranges = marked_ranges
24006                    .into_iter()
24007                    .map(|marked_range| {
24008                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24009                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24010                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24011                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24012                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24013                    })
24014                    .collect::<Vec<_>>();
24015
24016                drop(snapshot);
24017                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24018                    selections.select_ranges(new_selected_ranges)
24019                });
24020            }
24021        });
24022
24023        self.ime_transaction = self.ime_transaction.or(transaction);
24024        if let Some(transaction) = self.ime_transaction {
24025            self.buffer.update(cx, |buffer, cx| {
24026                buffer.group_until_transaction(transaction, cx);
24027            });
24028        }
24029
24030        if self.text_highlights::<InputComposition>(cx).is_none() {
24031            self.ime_transaction.take();
24032        }
24033    }
24034
24035    fn bounds_for_range(
24036        &mut self,
24037        range_utf16: Range<usize>,
24038        element_bounds: gpui::Bounds<Pixels>,
24039        window: &mut Window,
24040        cx: &mut Context<Self>,
24041    ) -> Option<gpui::Bounds<Pixels>> {
24042        let text_layout_details = self.text_layout_details(window);
24043        let CharacterDimensions {
24044            em_width,
24045            em_advance,
24046            line_height,
24047        } = self.character_dimensions(window);
24048
24049        let snapshot = self.snapshot(window, cx);
24050        let scroll_position = snapshot.scroll_position();
24051        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24052
24053        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24054        let x = Pixels::from(
24055            ScrollOffset::from(
24056                snapshot.x_for_display_point(start, &text_layout_details)
24057                    + self.gutter_dimensions.full_width(),
24058            ) - scroll_left,
24059        );
24060        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24061
24062        Some(Bounds {
24063            origin: element_bounds.origin + point(x, y),
24064            size: size(em_width, line_height),
24065        })
24066    }
24067
24068    fn character_index_for_point(
24069        &mut self,
24070        point: gpui::Point<Pixels>,
24071        _window: &mut Window,
24072        _cx: &mut Context<Self>,
24073    ) -> Option<usize> {
24074        let position_map = self.last_position_map.as_ref()?;
24075        if !position_map.text_hitbox.contains(&point) {
24076            return None;
24077        }
24078        let display_point = position_map.point_for_position(point).previous_valid;
24079        let anchor = position_map
24080            .snapshot
24081            .display_point_to_anchor(display_point, Bias::Left);
24082        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24083        Some(utf16_offset.0)
24084    }
24085}
24086
24087trait SelectionExt {
24088    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24089    fn spanned_rows(
24090        &self,
24091        include_end_if_at_line_start: bool,
24092        map: &DisplaySnapshot,
24093    ) -> Range<MultiBufferRow>;
24094}
24095
24096impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24097    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24098        let start = self
24099            .start
24100            .to_point(map.buffer_snapshot())
24101            .to_display_point(map);
24102        let end = self
24103            .end
24104            .to_point(map.buffer_snapshot())
24105            .to_display_point(map);
24106        if self.reversed {
24107            end..start
24108        } else {
24109            start..end
24110        }
24111    }
24112
24113    fn spanned_rows(
24114        &self,
24115        include_end_if_at_line_start: bool,
24116        map: &DisplaySnapshot,
24117    ) -> Range<MultiBufferRow> {
24118        let start = self.start.to_point(map.buffer_snapshot());
24119        let mut end = self.end.to_point(map.buffer_snapshot());
24120        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24121            end.row -= 1;
24122        }
24123
24124        let buffer_start = map.prev_line_boundary(start).0;
24125        let buffer_end = map.next_line_boundary(end).0;
24126        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24127    }
24128}
24129
24130impl<T: InvalidationRegion> InvalidationStack<T> {
24131    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24132    where
24133        S: Clone + ToOffset,
24134    {
24135        while let Some(region) = self.last() {
24136            let all_selections_inside_invalidation_ranges =
24137                if selections.len() == region.ranges().len() {
24138                    selections
24139                        .iter()
24140                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24141                        .all(|(selection, invalidation_range)| {
24142                            let head = selection.head().to_offset(buffer);
24143                            invalidation_range.start <= head && invalidation_range.end >= head
24144                        })
24145                } else {
24146                    false
24147                };
24148
24149            if all_selections_inside_invalidation_ranges {
24150                break;
24151            } else {
24152                self.pop();
24153            }
24154        }
24155    }
24156}
24157
24158impl<T> Default for InvalidationStack<T> {
24159    fn default() -> Self {
24160        Self(Default::default())
24161    }
24162}
24163
24164impl<T> Deref for InvalidationStack<T> {
24165    type Target = Vec<T>;
24166
24167    fn deref(&self) -> &Self::Target {
24168        &self.0
24169    }
24170}
24171
24172impl<T> DerefMut for InvalidationStack<T> {
24173    fn deref_mut(&mut self) -> &mut Self::Target {
24174        &mut self.0
24175    }
24176}
24177
24178impl InvalidationRegion for SnippetState {
24179    fn ranges(&self) -> &[Range<Anchor>] {
24180        &self.ranges[self.active_index]
24181    }
24182}
24183
24184fn edit_prediction_edit_text(
24185    current_snapshot: &BufferSnapshot,
24186    edits: &[(Range<Anchor>, String)],
24187    edit_preview: &EditPreview,
24188    include_deletions: bool,
24189    cx: &App,
24190) -> HighlightedText {
24191    let edits = edits
24192        .iter()
24193        .map(|(anchor, text)| {
24194            (
24195                anchor.start.text_anchor..anchor.end.text_anchor,
24196                text.clone(),
24197            )
24198        })
24199        .collect::<Vec<_>>();
24200
24201    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24202}
24203
24204fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24205    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24206    // Just show the raw edit text with basic styling
24207    let mut text = String::new();
24208    let mut highlights = Vec::new();
24209
24210    let insertion_highlight_style = HighlightStyle {
24211        color: Some(cx.theme().colors().text),
24212        ..Default::default()
24213    };
24214
24215    for (_, edit_text) in edits {
24216        let start_offset = text.len();
24217        text.push_str(edit_text);
24218        let end_offset = text.len();
24219
24220        if start_offset < end_offset {
24221            highlights.push((start_offset..end_offset, insertion_highlight_style));
24222        }
24223    }
24224
24225    HighlightedText {
24226        text: text.into(),
24227        highlights,
24228    }
24229}
24230
24231pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24232    match severity {
24233        lsp::DiagnosticSeverity::ERROR => colors.error,
24234        lsp::DiagnosticSeverity::WARNING => colors.warning,
24235        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24236        lsp::DiagnosticSeverity::HINT => colors.info,
24237        _ => colors.ignored,
24238    }
24239}
24240
24241pub fn styled_runs_for_code_label<'a>(
24242    label: &'a CodeLabel,
24243    syntax_theme: &'a theme::SyntaxTheme,
24244) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24245    let fade_out = HighlightStyle {
24246        fade_out: Some(0.35),
24247        ..Default::default()
24248    };
24249
24250    let mut prev_end = label.filter_range.end;
24251    label
24252        .runs
24253        .iter()
24254        .enumerate()
24255        .flat_map(move |(ix, (range, highlight_id))| {
24256            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24257                style
24258            } else {
24259                return Default::default();
24260            };
24261            let muted_style = style.highlight(fade_out);
24262
24263            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24264            if range.start >= label.filter_range.end {
24265                if range.start > prev_end {
24266                    runs.push((prev_end..range.start, fade_out));
24267                }
24268                runs.push((range.clone(), muted_style));
24269            } else if range.end <= label.filter_range.end {
24270                runs.push((range.clone(), style));
24271            } else {
24272                runs.push((range.start..label.filter_range.end, style));
24273                runs.push((label.filter_range.end..range.end, muted_style));
24274            }
24275            prev_end = cmp::max(prev_end, range.end);
24276
24277            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24278                runs.push((prev_end..label.text.len(), fade_out));
24279            }
24280
24281            runs
24282        })
24283}
24284
24285pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24286    let mut prev_index = 0;
24287    let mut prev_codepoint: Option<char> = None;
24288    text.char_indices()
24289        .chain([(text.len(), '\0')])
24290        .filter_map(move |(index, codepoint)| {
24291            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24292            let is_boundary = index == text.len()
24293                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24294                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24295            if is_boundary {
24296                let chunk = &text[prev_index..index];
24297                prev_index = index;
24298                Some(chunk)
24299            } else {
24300                None
24301            }
24302        })
24303}
24304
24305pub trait RangeToAnchorExt: Sized {
24306    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24307
24308    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24309        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24310        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24311    }
24312}
24313
24314impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24315    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24316        let start_offset = self.start.to_offset(snapshot);
24317        let end_offset = self.end.to_offset(snapshot);
24318        if start_offset == end_offset {
24319            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24320        } else {
24321            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24322        }
24323    }
24324}
24325
24326pub trait RowExt {
24327    fn as_f64(&self) -> f64;
24328
24329    fn next_row(&self) -> Self;
24330
24331    fn previous_row(&self) -> Self;
24332
24333    fn minus(&self, other: Self) -> u32;
24334}
24335
24336impl RowExt for DisplayRow {
24337    fn as_f64(&self) -> f64 {
24338        self.0 as _
24339    }
24340
24341    fn next_row(&self) -> Self {
24342        Self(self.0 + 1)
24343    }
24344
24345    fn previous_row(&self) -> Self {
24346        Self(self.0.saturating_sub(1))
24347    }
24348
24349    fn minus(&self, other: Self) -> u32 {
24350        self.0 - other.0
24351    }
24352}
24353
24354impl RowExt for MultiBufferRow {
24355    fn as_f64(&self) -> f64 {
24356        self.0 as _
24357    }
24358
24359    fn next_row(&self) -> Self {
24360        Self(self.0 + 1)
24361    }
24362
24363    fn previous_row(&self) -> Self {
24364        Self(self.0.saturating_sub(1))
24365    }
24366
24367    fn minus(&self, other: Self) -> u32 {
24368        self.0 - other.0
24369    }
24370}
24371
24372trait RowRangeExt {
24373    type Row;
24374
24375    fn len(&self) -> usize;
24376
24377    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24378}
24379
24380impl RowRangeExt for Range<MultiBufferRow> {
24381    type Row = MultiBufferRow;
24382
24383    fn len(&self) -> usize {
24384        (self.end.0 - self.start.0) as usize
24385    }
24386
24387    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24388        (self.start.0..self.end.0).map(MultiBufferRow)
24389    }
24390}
24391
24392impl RowRangeExt for Range<DisplayRow> {
24393    type Row = DisplayRow;
24394
24395    fn len(&self) -> usize {
24396        (self.end.0 - self.start.0) as usize
24397    }
24398
24399    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24400        (self.start.0..self.end.0).map(DisplayRow)
24401    }
24402}
24403
24404/// If select range has more than one line, we
24405/// just point the cursor to range.start.
24406fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24407    if range.start.row == range.end.row {
24408        range
24409    } else {
24410        range.start..range.start
24411    }
24412}
24413pub struct KillRing(ClipboardItem);
24414impl Global for KillRing {}
24415
24416const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24417
24418enum BreakpointPromptEditAction {
24419    Log,
24420    Condition,
24421    HitCondition,
24422}
24423
24424struct BreakpointPromptEditor {
24425    pub(crate) prompt: Entity<Editor>,
24426    editor: WeakEntity<Editor>,
24427    breakpoint_anchor: Anchor,
24428    breakpoint: Breakpoint,
24429    edit_action: BreakpointPromptEditAction,
24430    block_ids: HashSet<CustomBlockId>,
24431    editor_margins: Arc<Mutex<EditorMargins>>,
24432    _subscriptions: Vec<Subscription>,
24433}
24434
24435impl BreakpointPromptEditor {
24436    const MAX_LINES: u8 = 4;
24437
24438    fn new(
24439        editor: WeakEntity<Editor>,
24440        breakpoint_anchor: Anchor,
24441        breakpoint: Breakpoint,
24442        edit_action: BreakpointPromptEditAction,
24443        window: &mut Window,
24444        cx: &mut Context<Self>,
24445    ) -> Self {
24446        let base_text = match edit_action {
24447            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24448            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24449            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24450        }
24451        .map(|msg| msg.to_string())
24452        .unwrap_or_default();
24453
24454        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24455        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24456
24457        let prompt = cx.new(|cx| {
24458            let mut prompt = Editor::new(
24459                EditorMode::AutoHeight {
24460                    min_lines: 1,
24461                    max_lines: Some(Self::MAX_LINES as usize),
24462                },
24463                buffer,
24464                None,
24465                window,
24466                cx,
24467            );
24468            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24469            prompt.set_show_cursor_when_unfocused(false, cx);
24470            prompt.set_placeholder_text(
24471                match edit_action {
24472                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24473                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24474                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24475                },
24476                window,
24477                cx,
24478            );
24479
24480            prompt
24481        });
24482
24483        Self {
24484            prompt,
24485            editor,
24486            breakpoint_anchor,
24487            breakpoint,
24488            edit_action,
24489            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24490            block_ids: Default::default(),
24491            _subscriptions: vec![],
24492        }
24493    }
24494
24495    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24496        self.block_ids.extend(block_ids)
24497    }
24498
24499    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24500        if let Some(editor) = self.editor.upgrade() {
24501            let message = self
24502                .prompt
24503                .read(cx)
24504                .buffer
24505                .read(cx)
24506                .as_singleton()
24507                .expect("A multi buffer in breakpoint prompt isn't possible")
24508                .read(cx)
24509                .as_rope()
24510                .to_string();
24511
24512            editor.update(cx, |editor, cx| {
24513                editor.edit_breakpoint_at_anchor(
24514                    self.breakpoint_anchor,
24515                    self.breakpoint.clone(),
24516                    match self.edit_action {
24517                        BreakpointPromptEditAction::Log => {
24518                            BreakpointEditAction::EditLogMessage(message.into())
24519                        }
24520                        BreakpointPromptEditAction::Condition => {
24521                            BreakpointEditAction::EditCondition(message.into())
24522                        }
24523                        BreakpointPromptEditAction::HitCondition => {
24524                            BreakpointEditAction::EditHitCondition(message.into())
24525                        }
24526                    },
24527                    cx,
24528                );
24529
24530                editor.remove_blocks(self.block_ids.clone(), None, cx);
24531                cx.focus_self(window);
24532            });
24533        }
24534    }
24535
24536    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24537        self.editor
24538            .update(cx, |editor, cx| {
24539                editor.remove_blocks(self.block_ids.clone(), None, cx);
24540                window.focus(&editor.focus_handle);
24541            })
24542            .log_err();
24543    }
24544
24545    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24546        let settings = ThemeSettings::get_global(cx);
24547        let text_style = TextStyle {
24548            color: if self.prompt.read(cx).read_only(cx) {
24549                cx.theme().colors().text_disabled
24550            } else {
24551                cx.theme().colors().text
24552            },
24553            font_family: settings.buffer_font.family.clone(),
24554            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24555            font_size: settings.buffer_font_size(cx).into(),
24556            font_weight: settings.buffer_font.weight,
24557            line_height: relative(settings.buffer_line_height.value()),
24558            ..Default::default()
24559        };
24560        EditorElement::new(
24561            &self.prompt,
24562            EditorStyle {
24563                background: cx.theme().colors().editor_background,
24564                local_player: cx.theme().players().local(),
24565                text: text_style,
24566                ..Default::default()
24567            },
24568        )
24569    }
24570}
24571
24572impl Render for BreakpointPromptEditor {
24573    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24574        let editor_margins = *self.editor_margins.lock();
24575        let gutter_dimensions = editor_margins.gutter;
24576        h_flex()
24577            .key_context("Editor")
24578            .bg(cx.theme().colors().editor_background)
24579            .border_y_1()
24580            .border_color(cx.theme().status().info_border)
24581            .size_full()
24582            .py(window.line_height() / 2.5)
24583            .on_action(cx.listener(Self::confirm))
24584            .on_action(cx.listener(Self::cancel))
24585            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24586            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24587    }
24588}
24589
24590impl Focusable for BreakpointPromptEditor {
24591    fn focus_handle(&self, cx: &App) -> FocusHandle {
24592        self.prompt.focus_handle(cx)
24593    }
24594}
24595
24596fn all_edits_insertions_or_deletions(
24597    edits: &Vec<(Range<Anchor>, String)>,
24598    snapshot: &MultiBufferSnapshot,
24599) -> bool {
24600    let mut all_insertions = true;
24601    let mut all_deletions = true;
24602
24603    for (range, new_text) in edits.iter() {
24604        let range_is_empty = range.to_offset(snapshot).is_empty();
24605        let text_is_empty = new_text.is_empty();
24606
24607        if range_is_empty != text_is_empty {
24608            if range_is_empty {
24609                all_deletions = false;
24610            } else {
24611                all_insertions = false;
24612            }
24613        } else {
24614            return false;
24615        }
24616
24617        if !all_insertions && !all_deletions {
24618            return false;
24619        }
24620    }
24621    all_insertions || all_deletions
24622}
24623
24624struct MissingEditPredictionKeybindingTooltip;
24625
24626impl Render for MissingEditPredictionKeybindingTooltip {
24627    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24628        ui::tooltip_container(cx, |container, cx| {
24629            container
24630                .flex_shrink_0()
24631                .max_w_80()
24632                .min_h(rems_from_px(124.))
24633                .justify_between()
24634                .child(
24635                    v_flex()
24636                        .flex_1()
24637                        .text_ui_sm(cx)
24638                        .child(Label::new("Conflict with Accept Keybinding"))
24639                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24640                )
24641                .child(
24642                    h_flex()
24643                        .pb_1()
24644                        .gap_1()
24645                        .items_end()
24646                        .w_full()
24647                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24648                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24649                        }))
24650                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24651                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24652                        })),
24653                )
24654        })
24655    }
24656}
24657
24658#[derive(Debug, Clone, Copy, PartialEq)]
24659pub struct LineHighlight {
24660    pub background: Background,
24661    pub border: Option<gpui::Hsla>,
24662    pub include_gutter: bool,
24663    pub type_id: Option<TypeId>,
24664}
24665
24666struct LineManipulationResult {
24667    pub new_text: String,
24668    pub line_count_before: usize,
24669    pub line_count_after: usize,
24670}
24671
24672fn render_diff_hunk_controls(
24673    row: u32,
24674    status: &DiffHunkStatus,
24675    hunk_range: Range<Anchor>,
24676    is_created_file: bool,
24677    line_height: Pixels,
24678    editor: &Entity<Editor>,
24679    _window: &mut Window,
24680    cx: &mut App,
24681) -> AnyElement {
24682    h_flex()
24683        .h(line_height)
24684        .mr_1()
24685        .gap_1()
24686        .px_0p5()
24687        .pb_1()
24688        .border_x_1()
24689        .border_b_1()
24690        .border_color(cx.theme().colors().border_variant)
24691        .rounded_b_lg()
24692        .bg(cx.theme().colors().editor_background)
24693        .gap_1()
24694        .block_mouse_except_scroll()
24695        .shadow_md()
24696        .child(if status.has_secondary_hunk() {
24697            Button::new(("stage", row as u64), "Stage")
24698                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24699                .tooltip({
24700                    let focus_handle = editor.focus_handle(cx);
24701                    move |window, cx| {
24702                        Tooltip::for_action_in(
24703                            "Stage Hunk",
24704                            &::git::ToggleStaged,
24705                            &focus_handle,
24706                            window,
24707                            cx,
24708                        )
24709                    }
24710                })
24711                .on_click({
24712                    let editor = editor.clone();
24713                    move |_event, _window, cx| {
24714                        editor.update(cx, |editor, cx| {
24715                            editor.stage_or_unstage_diff_hunks(
24716                                true,
24717                                vec![hunk_range.start..hunk_range.start],
24718                                cx,
24719                            );
24720                        });
24721                    }
24722                })
24723        } else {
24724            Button::new(("unstage", row as u64), "Unstage")
24725                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24726                .tooltip({
24727                    let focus_handle = editor.focus_handle(cx);
24728                    move |window, cx| {
24729                        Tooltip::for_action_in(
24730                            "Unstage Hunk",
24731                            &::git::ToggleStaged,
24732                            &focus_handle,
24733                            window,
24734                            cx,
24735                        )
24736                    }
24737                })
24738                .on_click({
24739                    let editor = editor.clone();
24740                    move |_event, _window, cx| {
24741                        editor.update(cx, |editor, cx| {
24742                            editor.stage_or_unstage_diff_hunks(
24743                                false,
24744                                vec![hunk_range.start..hunk_range.start],
24745                                cx,
24746                            );
24747                        });
24748                    }
24749                })
24750        })
24751        .child(
24752            Button::new(("restore", row as u64), "Restore")
24753                .tooltip({
24754                    let focus_handle = editor.focus_handle(cx);
24755                    move |window, cx| {
24756                        Tooltip::for_action_in(
24757                            "Restore Hunk",
24758                            &::git::Restore,
24759                            &focus_handle,
24760                            window,
24761                            cx,
24762                        )
24763                    }
24764                })
24765                .on_click({
24766                    let editor = editor.clone();
24767                    move |_event, window, cx| {
24768                        editor.update(cx, |editor, cx| {
24769                            let snapshot = editor.snapshot(window, cx);
24770                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24771                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24772                        });
24773                    }
24774                })
24775                .disabled(is_created_file),
24776        )
24777        .when(
24778            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24779            |el| {
24780                el.child(
24781                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24782                        .shape(IconButtonShape::Square)
24783                        .icon_size(IconSize::Small)
24784                        // .disabled(!has_multiple_hunks)
24785                        .tooltip({
24786                            let focus_handle = editor.focus_handle(cx);
24787                            move |window, cx| {
24788                                Tooltip::for_action_in(
24789                                    "Next Hunk",
24790                                    &GoToHunk,
24791                                    &focus_handle,
24792                                    window,
24793                                    cx,
24794                                )
24795                            }
24796                        })
24797                        .on_click({
24798                            let editor = editor.clone();
24799                            move |_event, window, cx| {
24800                                editor.update(cx, |editor, cx| {
24801                                    let snapshot = editor.snapshot(window, cx);
24802                                    let position =
24803                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24804                                    editor.go_to_hunk_before_or_after_position(
24805                                        &snapshot,
24806                                        position,
24807                                        Direction::Next,
24808                                        window,
24809                                        cx,
24810                                    );
24811                                    editor.expand_selected_diff_hunks(cx);
24812                                });
24813                            }
24814                        }),
24815                )
24816                .child(
24817                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24818                        .shape(IconButtonShape::Square)
24819                        .icon_size(IconSize::Small)
24820                        // .disabled(!has_multiple_hunks)
24821                        .tooltip({
24822                            let focus_handle = editor.focus_handle(cx);
24823                            move |window, cx| {
24824                                Tooltip::for_action_in(
24825                                    "Previous Hunk",
24826                                    &GoToPreviousHunk,
24827                                    &focus_handle,
24828                                    window,
24829                                    cx,
24830                                )
24831                            }
24832                        })
24833                        .on_click({
24834                            let editor = editor.clone();
24835                            move |_event, window, cx| {
24836                                editor.update(cx, |editor, cx| {
24837                                    let snapshot = editor.snapshot(window, cx);
24838                                    let point =
24839                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24840                                    editor.go_to_hunk_before_or_after_position(
24841                                        &snapshot,
24842                                        point,
24843                                        Direction::Prev,
24844                                        window,
24845                                        cx,
24846                                    );
24847                                    editor.expand_selected_diff_hunks(cx);
24848                                });
24849                            }
24850                        }),
24851                )
24852            },
24853        )
24854        .into_any_element()
24855}
24856
24857pub fn multibuffer_context_lines(cx: &App) -> u32 {
24858    EditorSettings::try_get(cx)
24859        .map(|settings| settings.excerpt_context_lines)
24860        .unwrap_or(2)
24861        .min(32)
24862}