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};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::{
  208    code_context_menus::CompletionsMenuSource,
  209    editor_settings::MultiCursorModifier,
  210    hover_links::{find_url, find_url_from_range},
  211    scroll::{ScrollOffset, ScrollPixelOffset},
  212    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  213};
  214
  215pub const FILE_HEADER_HEIGHT: u32 = 2;
  216pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  217const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  218const MAX_LINE_LEN: usize = 1024;
  219const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  220const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  221pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  222#[doc(hidden)]
  223pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  224pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  225
  226pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  227pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  229
  230pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  231pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  232pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  233
  234pub type RenderDiffHunkControlsFn = Arc<
  235    dyn Fn(
  236        u32,
  237        &DiffHunkStatus,
  238        Range<Anchor>,
  239        bool,
  240        Pixels,
  241        &Entity<Editor>,
  242        &mut Window,
  243        &mut App,
  244    ) -> AnyElement,
  245>;
  246
  247enum ReportEditorEvent {
  248    Saved { auto_saved: bool },
  249    EditorOpened,
  250    Closed,
  251}
  252
  253impl ReportEditorEvent {
  254    pub fn event_type(&self) -> &'static str {
  255        match self {
  256            Self::Saved { .. } => "Editor Saved",
  257            Self::EditorOpened => "Editor Opened",
  258            Self::Closed => "Editor Closed",
  259        }
  260    }
  261}
  262
  263struct InlineValueCache {
  264    enabled: bool,
  265    inlays: Vec<InlayId>,
  266    refresh_task: Task<Option<()>>,
  267}
  268
  269impl InlineValueCache {
  270    fn new(enabled: bool) -> Self {
  271        Self {
  272            enabled,
  273            inlays: Vec::new(),
  274            refresh_task: Task::ready(None),
  275        }
  276    }
  277}
  278
  279#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  280pub enum InlayId {
  281    EditPrediction(u32),
  282    DebuggerValue(u32),
  283    // LSP
  284    Hint(u32),
  285    Color(u32),
  286}
  287
  288impl InlayId {
  289    fn id(&self) -> u32 {
  290        match self {
  291            Self::EditPrediction(id) => *id,
  292            Self::DebuggerValue(id) => *id,
  293            Self::Hint(id) => *id,
  294            Self::Color(id) => *id,
  295        }
  296    }
  297}
  298
  299pub enum ActiveDebugLine {}
  300pub enum DebugStackFrameLine {}
  301enum DocumentHighlightRead {}
  302enum DocumentHighlightWrite {}
  303enum InputComposition {}
  304pub enum PendingInput {}
  305enum SelectedTextHighlight {}
  306
  307pub enum ConflictsOuter {}
  308pub enum ConflictsOurs {}
  309pub enum ConflictsTheirs {}
  310pub enum ConflictsOursMarker {}
  311pub enum ConflictsTheirsMarker {}
  312
  313#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  314pub enum Navigated {
  315    Yes,
  316    No,
  317}
  318
  319impl Navigated {
  320    pub fn from_bool(yes: bool) -> Navigated {
  321        if yes { Navigated::Yes } else { Navigated::No }
  322    }
  323}
  324
  325#[derive(Debug, Clone, PartialEq, Eq)]
  326enum DisplayDiffHunk {
  327    Folded {
  328        display_row: DisplayRow,
  329    },
  330    Unfolded {
  331        is_created_file: bool,
  332        diff_base_byte_range: Range<usize>,
  333        display_row_range: Range<DisplayRow>,
  334        multi_buffer_range: Range<Anchor>,
  335        status: DiffHunkStatus,
  336    },
  337}
  338
  339pub enum HideMouseCursorOrigin {
  340    TypingAction,
  341    MovementAction,
  342}
  343
  344pub fn init_settings(cx: &mut App) {
  345    EditorSettings::register(cx);
  346}
  347
  348pub fn init(cx: &mut App) {
  349    init_settings(cx);
  350
  351    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  352
  353    workspace::register_project_item::<Editor>(cx);
  354    workspace::FollowableViewRegistry::register::<Editor>(cx);
  355    workspace::register_serializable_item::<Editor>(cx);
  356
  357    cx.observe_new(
  358        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  359            workspace.register_action(Editor::new_file);
  360            workspace.register_action(Editor::new_file_vertical);
  361            workspace.register_action(Editor::new_file_horizontal);
  362            workspace.register_action(Editor::cancel_language_server_work);
  363            workspace.register_action(Editor::toggle_focus);
  364        },
  365    )
  366    .detach();
  367
  368    cx.on_action(move |_: &workspace::NewFile, cx| {
  369        let app_state = workspace::AppState::global(cx);
  370        if let Some(app_state) = app_state.upgrade() {
  371            workspace::open_new(
  372                Default::default(),
  373                app_state,
  374                cx,
  375                |workspace, window, cx| {
  376                    Editor::new_file(workspace, &Default::default(), window, cx)
  377                },
  378            )
  379            .detach();
  380        }
  381    });
  382    cx.on_action(move |_: &workspace::NewWindow, cx| {
  383        let app_state = workspace::AppState::global(cx);
  384        if let Some(app_state) = app_state.upgrade() {
  385            workspace::open_new(
  386                Default::default(),
  387                app_state,
  388                cx,
  389                |workspace, window, cx| {
  390                    cx.activate(true);
  391                    Editor::new_file(workspace, &Default::default(), window, cx)
  392                },
  393            )
  394            .detach();
  395        }
  396    });
  397}
  398
  399pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  400    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  401}
  402
  403pub trait DiagnosticRenderer {
  404    fn render_group(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  407        buffer_id: BufferId,
  408        snapshot: EditorSnapshot,
  409        editor: WeakEntity<Editor>,
  410        cx: &mut App,
  411    ) -> Vec<BlockProperties<Anchor>>;
  412
  413    fn render_hover(
  414        &self,
  415        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  416        range: Range<Point>,
  417        buffer_id: BufferId,
  418        cx: &mut App,
  419    ) -> Option<Entity<markdown::Markdown>>;
  420
  421    fn open_link(
  422        &self,
  423        editor: &mut Editor,
  424        link: SharedString,
  425        window: &mut Window,
  426        cx: &mut Context<Editor>,
  427    );
  428}
  429
  430pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  431
  432impl GlobalDiagnosticRenderer {
  433    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  434        cx.try_global::<Self>().map(|g| g.0.clone())
  435    }
  436}
  437
  438impl gpui::Global for GlobalDiagnosticRenderer {}
  439pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  440    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  441}
  442
  443pub struct SearchWithinRange;
  444
  445trait InvalidationRegion {
  446    fn ranges(&self) -> &[Range<Anchor>];
  447}
  448
  449#[derive(Clone, Debug, PartialEq)]
  450pub enum SelectPhase {
  451    Begin {
  452        position: DisplayPoint,
  453        add: bool,
  454        click_count: usize,
  455    },
  456    BeginColumnar {
  457        position: DisplayPoint,
  458        reset: bool,
  459        mode: ColumnarMode,
  460        goal_column: u32,
  461    },
  462    Extend {
  463        position: DisplayPoint,
  464        click_count: usize,
  465    },
  466    Update {
  467        position: DisplayPoint,
  468        goal_column: u32,
  469        scroll_delta: gpui::Point<f32>,
  470    },
  471    End,
  472}
  473
  474#[derive(Clone, Debug, PartialEq)]
  475pub enum ColumnarMode {
  476    FromMouse,
  477    FromSelection,
  478}
  479
  480#[derive(Clone, Debug)]
  481pub enum SelectMode {
  482    Character,
  483    Word(Range<Anchor>),
  484    Line(Range<Anchor>),
  485    All,
  486}
  487
  488#[derive(Clone, PartialEq, Eq, Debug)]
  489pub enum EditorMode {
  490    SingleLine,
  491    AutoHeight {
  492        min_lines: usize,
  493        max_lines: Option<usize>,
  494    },
  495    Full {
  496        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  497        scale_ui_elements_with_buffer_font_size: bool,
  498        /// When set to `true`, the editor will render a background for the active line.
  499        show_active_line_background: bool,
  500        /// When set to `true`, the editor's height will be determined by its content.
  501        sized_by_content: bool,
  502    },
  503    Minimap {
  504        parent: WeakEntity<Editor>,
  505    },
  506}
  507
  508impl EditorMode {
  509    pub fn full() -> Self {
  510        Self::Full {
  511            scale_ui_elements_with_buffer_font_size: true,
  512            show_active_line_background: true,
  513            sized_by_content: false,
  514        }
  515    }
  516
  517    #[inline]
  518    pub fn is_full(&self) -> bool {
  519        matches!(self, Self::Full { .. })
  520    }
  521
  522    #[inline]
  523    pub fn is_single_line(&self) -> bool {
  524        matches!(self, Self::SingleLine { .. })
  525    }
  526
  527    #[inline]
  528    fn is_minimap(&self) -> bool {
  529        matches!(self, Self::Minimap { .. })
  530    }
  531}
  532
  533#[derive(Copy, Clone, Debug)]
  534pub enum SoftWrap {
  535    /// Prefer not to wrap at all.
  536    ///
  537    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  538    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  539    GitDiff,
  540    /// Prefer a single line generally, unless an overly long line is encountered.
  541    None,
  542    /// Soft wrap lines that exceed the editor width.
  543    EditorWidth,
  544    /// Soft wrap lines at the preferred line length.
  545    Column(u32),
  546    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  547    Bounded(u32),
  548}
  549
  550#[derive(Clone)]
  551pub struct EditorStyle {
  552    pub background: Hsla,
  553    pub border: Hsla,
  554    pub local_player: PlayerColor,
  555    pub text: TextStyle,
  556    pub scrollbar_width: Pixels,
  557    pub syntax: Arc<SyntaxTheme>,
  558    pub status: StatusColors,
  559    pub inlay_hints_style: HighlightStyle,
  560    pub edit_prediction_styles: EditPredictionStyles,
  561    pub unnecessary_code_fade: f32,
  562    pub show_underlines: bool,
  563}
  564
  565impl Default for EditorStyle {
  566    fn default() -> Self {
  567        Self {
  568            background: Hsla::default(),
  569            border: Hsla::default(),
  570            local_player: PlayerColor::default(),
  571            text: TextStyle::default(),
  572            scrollbar_width: Pixels::default(),
  573            syntax: Default::default(),
  574            // HACK: Status colors don't have a real default.
  575            // We should look into removing the status colors from the editor
  576            // style and retrieve them directly from the theme.
  577            status: StatusColors::dark(),
  578            inlay_hints_style: HighlightStyle::default(),
  579            edit_prediction_styles: EditPredictionStyles {
  580                insertion: HighlightStyle::default(),
  581                whitespace: HighlightStyle::default(),
  582            },
  583            unnecessary_code_fade: Default::default(),
  584            show_underlines: true,
  585        }
  586    }
  587}
  588
  589pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  590    let show_background = language_settings::language_settings(None, None, cx)
  591        .inlay_hints
  592        .show_background;
  593
  594    let mut style = cx.theme().syntax().get("hint");
  595
  596    if style.color.is_none() {
  597        style.color = Some(cx.theme().status().hint);
  598    }
  599
  600    if !show_background {
  601        style.background_color = None;
  602        return style;
  603    }
  604
  605    if style.background_color.is_none() {
  606        style.background_color = Some(cx.theme().status().hint_background);
  607    }
  608
  609    style
  610}
  611
  612pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  613    EditPredictionStyles {
  614        insertion: HighlightStyle {
  615            color: Some(cx.theme().status().predictive),
  616            ..HighlightStyle::default()
  617        },
  618        whitespace: HighlightStyle {
  619            background_color: Some(cx.theme().status().created_background),
  620            ..HighlightStyle::default()
  621        },
  622    }
  623}
  624
  625type CompletionId = usize;
  626
  627pub(crate) enum EditDisplayMode {
  628    TabAccept,
  629    DiffPopover,
  630    Inline,
  631}
  632
  633enum EditPrediction {
  634    Edit {
  635        edits: Vec<(Range<Anchor>, String)>,
  636        edit_preview: Option<EditPreview>,
  637        display_mode: EditDisplayMode,
  638        snapshot: BufferSnapshot,
  639    },
  640    /// Move to a specific location in the active editor
  641    MoveWithin {
  642        target: Anchor,
  643        snapshot: BufferSnapshot,
  644    },
  645    /// Move to a specific location in a different editor (not the active one)
  646    MoveOutside {
  647        target: language::Anchor,
  648        snapshot: BufferSnapshot,
  649    },
  650}
  651
  652struct EditPredictionState {
  653    inlay_ids: Vec<InlayId>,
  654    completion: EditPrediction,
  655    completion_id: Option<SharedString>,
  656    invalidation_range: Option<Range<Anchor>>,
  657}
  658
  659enum EditPredictionSettings {
  660    Disabled,
  661    Enabled {
  662        show_in_menu: bool,
  663        preview_requires_modifier: bool,
  664    },
  665}
  666
  667enum EditPredictionHighlight {}
  668
  669#[derive(Debug, Clone)]
  670struct InlineDiagnostic {
  671    message: SharedString,
  672    group_id: usize,
  673    is_primary: bool,
  674    start: Point,
  675    severity: lsp::DiagnosticSeverity,
  676}
  677
  678pub enum MenuEditPredictionsPolicy {
  679    Never,
  680    ByProvider,
  681}
  682
  683pub enum EditPredictionPreview {
  684    /// Modifier is not pressed
  685    Inactive { released_too_fast: bool },
  686    /// Modifier pressed
  687    Active {
  688        since: Instant,
  689        previous_scroll_position: Option<ScrollAnchor>,
  690    },
  691}
  692
  693impl EditPredictionPreview {
  694    pub fn released_too_fast(&self) -> bool {
  695        match self {
  696            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  697            EditPredictionPreview::Active { .. } => false,
  698        }
  699    }
  700
  701    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  702        if let EditPredictionPreview::Active {
  703            previous_scroll_position,
  704            ..
  705        } = self
  706        {
  707            *previous_scroll_position = scroll_position;
  708        }
  709    }
  710}
  711
  712pub struct ContextMenuOptions {
  713    pub min_entries_visible: usize,
  714    pub max_entries_visible: usize,
  715    pub placement: Option<ContextMenuPlacement>,
  716}
  717
  718#[derive(Debug, Clone, PartialEq, Eq)]
  719pub enum ContextMenuPlacement {
  720    Above,
  721    Below,
  722}
  723
  724#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  725struct EditorActionId(usize);
  726
  727impl EditorActionId {
  728    pub fn post_inc(&mut self) -> Self {
  729        let answer = self.0;
  730
  731        *self = Self(answer + 1);
  732
  733        Self(answer)
  734    }
  735}
  736
  737// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  738// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  739
  740type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  741type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  742
  743#[derive(Default)]
  744struct ScrollbarMarkerState {
  745    scrollbar_size: Size<Pixels>,
  746    dirty: bool,
  747    markers: Arc<[PaintQuad]>,
  748    pending_refresh: Option<Task<Result<()>>>,
  749}
  750
  751impl ScrollbarMarkerState {
  752    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  753        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  754    }
  755}
  756
  757#[derive(Clone, Copy, PartialEq, Eq)]
  758pub enum MinimapVisibility {
  759    Disabled,
  760    Enabled {
  761        /// The configuration currently present in the users settings.
  762        setting_configuration: bool,
  763        /// Whether to override the currently set visibility from the users setting.
  764        toggle_override: bool,
  765    },
  766}
  767
  768impl MinimapVisibility {
  769    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  770        if mode.is_full() {
  771            Self::Enabled {
  772                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  773                toggle_override: false,
  774            }
  775        } else {
  776            Self::Disabled
  777        }
  778    }
  779
  780    fn hidden(&self) -> Self {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => Self::Enabled {
  786                setting_configuration,
  787                toggle_override: setting_configuration,
  788            },
  789            Self::Disabled => Self::Disabled,
  790        }
  791    }
  792
  793    fn disabled(&self) -> bool {
  794        matches!(*self, Self::Disabled)
  795    }
  796
  797    fn settings_visibility(&self) -> bool {
  798        match *self {
  799            Self::Enabled {
  800                setting_configuration,
  801                ..
  802            } => setting_configuration,
  803            _ => false,
  804        }
  805    }
  806
  807    fn visible(&self) -> bool {
  808        match *self {
  809            Self::Enabled {
  810                setting_configuration,
  811                toggle_override,
  812            } => setting_configuration ^ toggle_override,
  813            _ => false,
  814        }
  815    }
  816
  817    fn toggle_visibility(&self) -> Self {
  818        match *self {
  819            Self::Enabled {
  820                toggle_override,
  821                setting_configuration,
  822            } => Self::Enabled {
  823                setting_configuration,
  824                toggle_override: !toggle_override,
  825            },
  826            Self::Disabled => Self::Disabled,
  827        }
  828    }
  829}
  830
  831#[derive(Clone, Debug)]
  832struct RunnableTasks {
  833    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  834    offset: multi_buffer::Anchor,
  835    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  836    column: u32,
  837    // Values of all named captures, including those starting with '_'
  838    extra_variables: HashMap<String, String>,
  839    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  840    context_range: Range<BufferOffset>,
  841}
  842
  843impl RunnableTasks {
  844    fn resolve<'a>(
  845        &'a self,
  846        cx: &'a task::TaskContext,
  847    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  848        self.templates.iter().filter_map(|(kind, template)| {
  849            template
  850                .resolve_task(&kind.to_id_base(), cx)
  851                .map(|task| (kind.clone(), task))
  852        })
  853    }
  854}
  855
  856#[derive(Clone)]
  857pub struct ResolvedTasks {
  858    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  859    position: Anchor,
  860}
  861
  862#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  863struct BufferOffset(usize);
  864
  865/// Addons allow storing per-editor state in other crates (e.g. Vim)
  866pub trait Addon: 'static {
  867    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  868
  869    fn render_buffer_header_controls(
  870        &self,
  871        _: &ExcerptInfo,
  872        _: &Window,
  873        _: &App,
  874    ) -> Option<AnyElement> {
  875        None
  876    }
  877
  878    fn to_any(&self) -> &dyn std::any::Any;
  879
  880    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  881        None
  882    }
  883}
  884
  885struct ChangeLocation {
  886    current: Option<Vec<Anchor>>,
  887    original: Vec<Anchor>,
  888}
  889impl ChangeLocation {
  890    fn locations(&self) -> &[Anchor] {
  891        self.current.as_ref().unwrap_or(&self.original)
  892    }
  893}
  894
  895/// A set of caret positions, registered when the editor was edited.
  896pub struct ChangeList {
  897    changes: Vec<ChangeLocation>,
  898    /// Currently "selected" change.
  899    position: Option<usize>,
  900}
  901
  902impl ChangeList {
  903    pub fn new() -> Self {
  904        Self {
  905            changes: Vec::new(),
  906            position: None,
  907        }
  908    }
  909
  910    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  911    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  912    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  913        if self.changes.is_empty() {
  914            return None;
  915        }
  916
  917        let prev = self.position.unwrap_or(self.changes.len());
  918        let next = if direction == Direction::Prev {
  919            prev.saturating_sub(count)
  920        } else {
  921            (prev + count).min(self.changes.len() - 1)
  922        };
  923        self.position = Some(next);
  924        self.changes.get(next).map(|change| change.locations())
  925    }
  926
  927    /// Adds a new change to the list, resetting the change list position.
  928    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  929        self.position.take();
  930        if let Some(last) = self.changes.last_mut()
  931            && group
  932        {
  933            last.current = Some(new_positions)
  934        } else {
  935            self.changes.push(ChangeLocation {
  936                original: new_positions,
  937                current: None,
  938            });
  939        }
  940    }
  941
  942    pub fn last(&self) -> Option<&[Anchor]> {
  943        self.changes.last().map(|change| change.locations())
  944    }
  945
  946    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  947        self.changes.last().map(|change| change.original.as_slice())
  948    }
  949
  950    pub fn invert_last_group(&mut self) {
  951        if let Some(last) = self.changes.last_mut()
  952            && let Some(current) = last.current.as_mut()
  953        {
  954            mem::swap(&mut last.original, current);
  955        }
  956    }
  957}
  958
  959#[derive(Clone)]
  960struct InlineBlamePopoverState {
  961    scroll_handle: ScrollHandle,
  962    commit_message: Option<ParsedCommitMessage>,
  963    markdown: Entity<Markdown>,
  964}
  965
  966struct InlineBlamePopover {
  967    position: gpui::Point<Pixels>,
  968    hide_task: Option<Task<()>>,
  969    popover_bounds: Option<Bounds<Pixels>>,
  970    popover_state: InlineBlamePopoverState,
  971    keyboard_grace: bool,
  972}
  973
  974enum SelectionDragState {
  975    /// State when no drag related activity is detected.
  976    None,
  977    /// State when the mouse is down on a selection that is about to be dragged.
  978    ReadyToDrag {
  979        selection: Selection<Anchor>,
  980        click_position: gpui::Point<Pixels>,
  981        mouse_down_time: Instant,
  982    },
  983    /// State when the mouse is dragging the selection in the editor.
  984    Dragging {
  985        selection: Selection<Anchor>,
  986        drop_cursor: Selection<Anchor>,
  987        hide_drop_cursor: bool,
  988    },
  989}
  990
  991enum ColumnarSelectionState {
  992    FromMouse {
  993        selection_tail: Anchor,
  994        display_point: Option<DisplayPoint>,
  995    },
  996    FromSelection {
  997        selection_tail: Anchor,
  998    },
  999}
 1000
 1001/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1002/// a breakpoint on them.
 1003#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1004struct PhantomBreakpointIndicator {
 1005    display_row: DisplayRow,
 1006    /// There's a small debounce between hovering over the line and showing the indicator.
 1007    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1008    is_active: bool,
 1009    collides_with_existing_breakpoint: bool,
 1010}
 1011
 1012/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1013///
 1014/// See the [module level documentation](self) for more information.
 1015pub struct Editor {
 1016    focus_handle: FocusHandle,
 1017    last_focused_descendant: Option<WeakFocusHandle>,
 1018    /// The text buffer being edited
 1019    buffer: Entity<MultiBuffer>,
 1020    /// Map of how text in the buffer should be displayed.
 1021    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1022    pub display_map: Entity<DisplayMap>,
 1023    placeholder_display_map: Option<Entity<DisplayMap>>,
 1024    pub selections: SelectionsCollection,
 1025    pub scroll_manager: ScrollManager,
 1026    /// When inline assist editors are linked, they all render cursors because
 1027    /// typing enters text into each of them, even the ones that aren't focused.
 1028    pub(crate) show_cursor_when_unfocused: bool,
 1029    columnar_selection_state: Option<ColumnarSelectionState>,
 1030    add_selections_state: Option<AddSelectionsState>,
 1031    select_next_state: Option<SelectNextState>,
 1032    select_prev_state: Option<SelectNextState>,
 1033    selection_history: SelectionHistory,
 1034    defer_selection_effects: bool,
 1035    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1036    autoclose_regions: Vec<AutocloseRegion>,
 1037    snippet_stack: InvalidationStack<SnippetState>,
 1038    select_syntax_node_history: SelectSyntaxNodeHistory,
 1039    ime_transaction: Option<TransactionId>,
 1040    pub diagnostics_max_severity: DiagnosticSeverity,
 1041    active_diagnostics: ActiveDiagnostic,
 1042    show_inline_diagnostics: bool,
 1043    inline_diagnostics_update: Task<()>,
 1044    inline_diagnostics_enabled: bool,
 1045    diagnostics_enabled: bool,
 1046    word_completions_enabled: bool,
 1047    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1048    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1049    hard_wrap: Option<usize>,
 1050    project: Option<Entity<Project>>,
 1051    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1052    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1053    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1054    blink_manager: Entity<BlinkManager>,
 1055    show_cursor_names: bool,
 1056    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1057    pub show_local_selections: bool,
 1058    mode: EditorMode,
 1059    show_breadcrumbs: bool,
 1060    show_gutter: bool,
 1061    show_scrollbars: ScrollbarAxes,
 1062    minimap_visibility: MinimapVisibility,
 1063    offset_content: bool,
 1064    disable_expand_excerpt_buttons: bool,
 1065    show_line_numbers: Option<bool>,
 1066    use_relative_line_numbers: Option<bool>,
 1067    show_git_diff_gutter: Option<bool>,
 1068    show_code_actions: Option<bool>,
 1069    show_runnables: Option<bool>,
 1070    show_breakpoints: Option<bool>,
 1071    show_wrap_guides: Option<bool>,
 1072    show_indent_guides: Option<bool>,
 1073    highlight_order: usize,
 1074    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1075    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1076    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1077    scrollbar_marker_state: ScrollbarMarkerState,
 1078    active_indent_guides_state: ActiveIndentGuidesState,
 1079    nav_history: Option<ItemNavHistory>,
 1080    context_menu: RefCell<Option<CodeContextMenu>>,
 1081    context_menu_options: Option<ContextMenuOptions>,
 1082    mouse_context_menu: Option<MouseContextMenu>,
 1083    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1084    inline_blame_popover: Option<InlineBlamePopover>,
 1085    inline_blame_popover_show_task: Option<Task<()>>,
 1086    signature_help_state: SignatureHelpState,
 1087    auto_signature_help: Option<bool>,
 1088    find_all_references_task_sources: Vec<Anchor>,
 1089    next_completion_id: CompletionId,
 1090    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1091    code_actions_task: Option<Task<Result<()>>>,
 1092    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1093    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    document_highlights_task: Option<Task<()>>,
 1095    linked_editing_range_task: Option<Task<Option<()>>>,
 1096    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1097    pending_rename: Option<RenameState>,
 1098    searchable: bool,
 1099    cursor_shape: CursorShape,
 1100    current_line_highlight: Option<CurrentLineHighlight>,
 1101    collapse_matches: bool,
 1102    autoindent_mode: Option<AutoindentMode>,
 1103    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1104    input_enabled: bool,
 1105    use_modal_editing: bool,
 1106    read_only: bool,
 1107    leader_id: Option<CollaboratorId>,
 1108    remote_id: Option<ViewId>,
 1109    pub hover_state: HoverState,
 1110    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1111    gutter_hovered: bool,
 1112    hovered_link_state: Option<HoveredLinkState>,
 1113    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1114    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1115    active_edit_prediction: Option<EditPredictionState>,
 1116    /// Used to prevent flickering as the user types while the menu is open
 1117    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1118    edit_prediction_settings: EditPredictionSettings,
 1119    edit_predictions_hidden_for_vim_mode: bool,
 1120    show_edit_predictions_override: Option<bool>,
 1121    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1122    edit_prediction_preview: EditPredictionPreview,
 1123    edit_prediction_indent_conflict: bool,
 1124    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1125    inlay_hint_cache: InlayHintCache,
 1126    next_inlay_id: u32,
 1127    next_color_inlay_id: u32,
 1128    _subscriptions: Vec<Subscription>,
 1129    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1130    gutter_dimensions: GutterDimensions,
 1131    style: Option<EditorStyle>,
 1132    text_style_refinement: Option<TextStyleRefinement>,
 1133    next_editor_action_id: EditorActionId,
 1134    editor_actions: Rc<
 1135        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1136    >,
 1137    use_autoclose: bool,
 1138    use_auto_surround: bool,
 1139    auto_replace_emoji_shortcode: bool,
 1140    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1141    show_git_blame_gutter: bool,
 1142    show_git_blame_inline: bool,
 1143    show_git_blame_inline_delay_task: Option<Task<()>>,
 1144    git_blame_inline_enabled: bool,
 1145    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1146    serialize_dirty_buffers: bool,
 1147    show_selection_menu: Option<bool>,
 1148    blame: Option<Entity<GitBlame>>,
 1149    blame_subscription: Option<Subscription>,
 1150    custom_context_menu: Option<
 1151        Box<
 1152            dyn 'static
 1153                + Fn(
 1154                    &mut Self,
 1155                    DisplayPoint,
 1156                    &mut Window,
 1157                    &mut Context<Self>,
 1158                ) -> Option<Entity<ui::ContextMenu>>,
 1159        >,
 1160    >,
 1161    last_bounds: Option<Bounds<Pixels>>,
 1162    last_position_map: Option<Rc<PositionMap>>,
 1163    expect_bounds_change: Option<Bounds<Pixels>>,
 1164    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1165    tasks_update_task: Option<Task<()>>,
 1166    breakpoint_store: Option<Entity<BreakpointStore>>,
 1167    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1168    hovered_diff_hunk_row: Option<DisplayRow>,
 1169    pull_diagnostics_task: Task<()>,
 1170    in_project_search: bool,
 1171    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1172    breadcrumb_header: Option<String>,
 1173    focused_block: Option<FocusedBlock>,
 1174    next_scroll_position: NextScrollCursorCenterTopBottom,
 1175    addons: HashMap<TypeId, Box<dyn Addon>>,
 1176    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1177    load_diff_task: Option<Shared<Task<()>>>,
 1178    /// Whether we are temporarily displaying a diff other than git's
 1179    temporary_diff_override: bool,
 1180    selection_mark_mode: bool,
 1181    toggle_fold_multiple_buffers: Task<()>,
 1182    _scroll_cursor_center_top_bottom_task: Task<()>,
 1183    serialize_selections: Task<()>,
 1184    serialize_folds: Task<()>,
 1185    mouse_cursor_hidden: bool,
 1186    minimap: Option<Entity<Self>>,
 1187    hide_mouse_mode: HideMouseMode,
 1188    pub change_list: ChangeList,
 1189    inline_value_cache: InlineValueCache,
 1190    selection_drag_state: SelectionDragState,
 1191    colors: Option<LspColorData>,
 1192    folding_newlines: Task<()>,
 1193    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1194}
 1195
 1196#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1197enum NextScrollCursorCenterTopBottom {
 1198    #[default]
 1199    Center,
 1200    Top,
 1201    Bottom,
 1202}
 1203
 1204impl NextScrollCursorCenterTopBottom {
 1205    fn next(&self) -> Self {
 1206        match self {
 1207            Self::Center => Self::Top,
 1208            Self::Top => Self::Bottom,
 1209            Self::Bottom => Self::Center,
 1210        }
 1211    }
 1212}
 1213
 1214#[derive(Clone)]
 1215pub struct EditorSnapshot {
 1216    pub mode: EditorMode,
 1217    show_gutter: bool,
 1218    show_line_numbers: Option<bool>,
 1219    show_git_diff_gutter: Option<bool>,
 1220    show_code_actions: Option<bool>,
 1221    show_runnables: Option<bool>,
 1222    show_breakpoints: Option<bool>,
 1223    git_blame_gutter_max_author_length: Option<usize>,
 1224    pub display_snapshot: DisplaySnapshot,
 1225    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1226    is_focused: bool,
 1227    scroll_anchor: ScrollAnchor,
 1228    ongoing_scroll: OngoingScroll,
 1229    current_line_highlight: CurrentLineHighlight,
 1230    gutter_hovered: bool,
 1231}
 1232
 1233#[derive(Default, Debug, Clone, Copy)]
 1234pub struct GutterDimensions {
 1235    pub left_padding: Pixels,
 1236    pub right_padding: Pixels,
 1237    pub width: Pixels,
 1238    pub margin: Pixels,
 1239    pub git_blame_entries_width: Option<Pixels>,
 1240}
 1241
 1242impl GutterDimensions {
 1243    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1244        Self {
 1245            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1246            ..Default::default()
 1247        }
 1248    }
 1249
 1250    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1251        -cx.text_system().descent(font_id, font_size)
 1252    }
 1253    /// The full width of the space taken up by the gutter.
 1254    pub fn full_width(&self) -> Pixels {
 1255        self.margin + self.width
 1256    }
 1257
 1258    /// The width of the space reserved for the fold indicators,
 1259    /// use alongside 'justify_end' and `gutter_width` to
 1260    /// right align content with the line numbers
 1261    pub fn fold_area_width(&self) -> Pixels {
 1262        self.margin + self.right_padding
 1263    }
 1264}
 1265
 1266struct CharacterDimensions {
 1267    em_width: Pixels,
 1268    em_advance: Pixels,
 1269    line_height: Pixels,
 1270}
 1271
 1272#[derive(Debug)]
 1273pub struct RemoteSelection {
 1274    pub replica_id: ReplicaId,
 1275    pub selection: Selection<Anchor>,
 1276    pub cursor_shape: CursorShape,
 1277    pub collaborator_id: CollaboratorId,
 1278    pub line_mode: bool,
 1279    pub user_name: Option<SharedString>,
 1280    pub color: PlayerColor,
 1281}
 1282
 1283#[derive(Clone, Debug)]
 1284struct SelectionHistoryEntry {
 1285    selections: Arc<[Selection<Anchor>]>,
 1286    select_next_state: Option<SelectNextState>,
 1287    select_prev_state: Option<SelectNextState>,
 1288    add_selections_state: Option<AddSelectionsState>,
 1289}
 1290
 1291#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1292enum SelectionHistoryMode {
 1293    Normal,
 1294    Undoing,
 1295    Redoing,
 1296    Skipping,
 1297}
 1298
 1299#[derive(Clone, PartialEq, Eq, Hash)]
 1300struct HoveredCursor {
 1301    replica_id: u16,
 1302    selection_id: usize,
 1303}
 1304
 1305impl Default for SelectionHistoryMode {
 1306    fn default() -> Self {
 1307        Self::Normal
 1308    }
 1309}
 1310
 1311#[derive(Debug)]
 1312/// SelectionEffects controls the side-effects of updating the selection.
 1313///
 1314/// The default behaviour does "what you mostly want":
 1315/// - it pushes to the nav history if the cursor moved by >10 lines
 1316/// - it re-triggers completion requests
 1317/// - it scrolls to fit
 1318///
 1319/// You might want to modify these behaviours. For example when doing a "jump"
 1320/// like go to definition, we always want to add to nav history; but when scrolling
 1321/// in vim mode we never do.
 1322///
 1323/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1324/// move.
 1325#[derive(Clone)]
 1326pub struct SelectionEffects {
 1327    nav_history: Option<bool>,
 1328    completions: bool,
 1329    scroll: Option<Autoscroll>,
 1330}
 1331
 1332impl Default for SelectionEffects {
 1333    fn default() -> Self {
 1334        Self {
 1335            nav_history: None,
 1336            completions: true,
 1337            scroll: Some(Autoscroll::fit()),
 1338        }
 1339    }
 1340}
 1341impl SelectionEffects {
 1342    pub fn scroll(scroll: Autoscroll) -> Self {
 1343        Self {
 1344            scroll: Some(scroll),
 1345            ..Default::default()
 1346        }
 1347    }
 1348
 1349    pub fn no_scroll() -> Self {
 1350        Self {
 1351            scroll: None,
 1352            ..Default::default()
 1353        }
 1354    }
 1355
 1356    pub fn completions(self, completions: bool) -> Self {
 1357        Self {
 1358            completions,
 1359            ..self
 1360        }
 1361    }
 1362
 1363    pub fn nav_history(self, nav_history: bool) -> Self {
 1364        Self {
 1365            nav_history: Some(nav_history),
 1366            ..self
 1367        }
 1368    }
 1369}
 1370
 1371struct DeferredSelectionEffectsState {
 1372    changed: bool,
 1373    effects: SelectionEffects,
 1374    old_cursor_position: Anchor,
 1375    history_entry: SelectionHistoryEntry,
 1376}
 1377
 1378#[derive(Default)]
 1379struct SelectionHistory {
 1380    #[allow(clippy::type_complexity)]
 1381    selections_by_transaction:
 1382        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1383    mode: SelectionHistoryMode,
 1384    undo_stack: VecDeque<SelectionHistoryEntry>,
 1385    redo_stack: VecDeque<SelectionHistoryEntry>,
 1386}
 1387
 1388impl SelectionHistory {
 1389    #[track_caller]
 1390    fn insert_transaction(
 1391        &mut self,
 1392        transaction_id: TransactionId,
 1393        selections: Arc<[Selection<Anchor>]>,
 1394    ) {
 1395        if selections.is_empty() {
 1396            log::error!(
 1397                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1398                std::panic::Location::caller()
 1399            );
 1400            return;
 1401        }
 1402        self.selections_by_transaction
 1403            .insert(transaction_id, (selections, None));
 1404    }
 1405
 1406    #[allow(clippy::type_complexity)]
 1407    fn transaction(
 1408        &self,
 1409        transaction_id: TransactionId,
 1410    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1411        self.selections_by_transaction.get(&transaction_id)
 1412    }
 1413
 1414    #[allow(clippy::type_complexity)]
 1415    fn transaction_mut(
 1416        &mut self,
 1417        transaction_id: TransactionId,
 1418    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1419        self.selections_by_transaction.get_mut(&transaction_id)
 1420    }
 1421
 1422    fn push(&mut self, entry: SelectionHistoryEntry) {
 1423        if !entry.selections.is_empty() {
 1424            match self.mode {
 1425                SelectionHistoryMode::Normal => {
 1426                    self.push_undo(entry);
 1427                    self.redo_stack.clear();
 1428                }
 1429                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1430                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1431                SelectionHistoryMode::Skipping => {}
 1432            }
 1433        }
 1434    }
 1435
 1436    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1437        if self
 1438            .undo_stack
 1439            .back()
 1440            .is_none_or(|e| e.selections != entry.selections)
 1441        {
 1442            self.undo_stack.push_back(entry);
 1443            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1444                self.undo_stack.pop_front();
 1445            }
 1446        }
 1447    }
 1448
 1449    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1450        if self
 1451            .redo_stack
 1452            .back()
 1453            .is_none_or(|e| e.selections != entry.selections)
 1454        {
 1455            self.redo_stack.push_back(entry);
 1456            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1457                self.redo_stack.pop_front();
 1458            }
 1459        }
 1460    }
 1461}
 1462
 1463#[derive(Clone, Copy)]
 1464pub struct RowHighlightOptions {
 1465    pub autoscroll: bool,
 1466    pub include_gutter: bool,
 1467}
 1468
 1469impl Default for RowHighlightOptions {
 1470    fn default() -> Self {
 1471        Self {
 1472            autoscroll: Default::default(),
 1473            include_gutter: true,
 1474        }
 1475    }
 1476}
 1477
 1478struct RowHighlight {
 1479    index: usize,
 1480    range: Range<Anchor>,
 1481    color: Hsla,
 1482    options: RowHighlightOptions,
 1483    type_id: TypeId,
 1484}
 1485
 1486#[derive(Clone, Debug)]
 1487struct AddSelectionsState {
 1488    groups: Vec<AddSelectionsGroup>,
 1489}
 1490
 1491#[derive(Clone, Debug)]
 1492struct AddSelectionsGroup {
 1493    above: bool,
 1494    stack: Vec<usize>,
 1495}
 1496
 1497#[derive(Clone)]
 1498struct SelectNextState {
 1499    query: AhoCorasick,
 1500    wordwise: bool,
 1501    done: bool,
 1502}
 1503
 1504impl std::fmt::Debug for SelectNextState {
 1505    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1506        f.debug_struct(std::any::type_name::<Self>())
 1507            .field("wordwise", &self.wordwise)
 1508            .field("done", &self.done)
 1509            .finish()
 1510    }
 1511}
 1512
 1513#[derive(Debug)]
 1514struct AutocloseRegion {
 1515    selection_id: usize,
 1516    range: Range<Anchor>,
 1517    pair: BracketPair,
 1518}
 1519
 1520#[derive(Debug)]
 1521struct SnippetState {
 1522    ranges: Vec<Vec<Range<Anchor>>>,
 1523    active_index: usize,
 1524    choices: Vec<Option<Vec<String>>>,
 1525}
 1526
 1527#[doc(hidden)]
 1528pub struct RenameState {
 1529    pub range: Range<Anchor>,
 1530    pub old_name: Arc<str>,
 1531    pub editor: Entity<Editor>,
 1532    block_id: CustomBlockId,
 1533}
 1534
 1535struct InvalidationStack<T>(Vec<T>);
 1536
 1537struct RegisteredEditPredictionProvider {
 1538    provider: Arc<dyn EditPredictionProviderHandle>,
 1539    _subscription: Subscription,
 1540}
 1541
 1542#[derive(Debug, PartialEq, Eq)]
 1543pub struct ActiveDiagnosticGroup {
 1544    pub active_range: Range<Anchor>,
 1545    pub active_message: String,
 1546    pub group_id: usize,
 1547    pub blocks: HashSet<CustomBlockId>,
 1548}
 1549
 1550#[derive(Debug, PartialEq, Eq)]
 1551
 1552pub(crate) enum ActiveDiagnostic {
 1553    None,
 1554    All,
 1555    Group(ActiveDiagnosticGroup),
 1556}
 1557
 1558#[derive(Serialize, Deserialize, Clone, Debug)]
 1559pub struct ClipboardSelection {
 1560    /// The number of bytes in this selection.
 1561    pub len: usize,
 1562    /// Whether this was a full-line selection.
 1563    pub is_entire_line: bool,
 1564    /// The indentation of the first line when this content was originally copied.
 1565    pub first_line_indent: u32,
 1566}
 1567
 1568// selections, scroll behavior, was newest selection reversed
 1569type SelectSyntaxNodeHistoryState = (
 1570    Box<[Selection<usize>]>,
 1571    SelectSyntaxNodeScrollBehavior,
 1572    bool,
 1573);
 1574
 1575#[derive(Default)]
 1576struct SelectSyntaxNodeHistory {
 1577    stack: Vec<SelectSyntaxNodeHistoryState>,
 1578    // disable temporarily to allow changing selections without losing the stack
 1579    pub disable_clearing: bool,
 1580}
 1581
 1582impl SelectSyntaxNodeHistory {
 1583    pub fn try_clear(&mut self) {
 1584        if !self.disable_clearing {
 1585            self.stack.clear();
 1586        }
 1587    }
 1588
 1589    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1590        self.stack.push(selection);
 1591    }
 1592
 1593    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1594        self.stack.pop()
 1595    }
 1596}
 1597
 1598enum SelectSyntaxNodeScrollBehavior {
 1599    CursorTop,
 1600    FitSelection,
 1601    CursorBottom,
 1602}
 1603
 1604#[derive(Debug)]
 1605pub(crate) struct NavigationData {
 1606    cursor_anchor: Anchor,
 1607    cursor_position: Point,
 1608    scroll_anchor: ScrollAnchor,
 1609    scroll_top_row: u32,
 1610}
 1611
 1612#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1613pub enum GotoDefinitionKind {
 1614    Symbol,
 1615    Declaration,
 1616    Type,
 1617    Implementation,
 1618}
 1619
 1620#[derive(Debug, Clone)]
 1621enum InlayHintRefreshReason {
 1622    ModifiersChanged(bool),
 1623    Toggle(bool),
 1624    SettingsChange(InlayHintSettings),
 1625    NewLinesShown,
 1626    BufferEdited(HashSet<Arc<Language>>),
 1627    RefreshRequested,
 1628    ExcerptsRemoved(Vec<ExcerptId>),
 1629}
 1630
 1631impl InlayHintRefreshReason {
 1632    fn description(&self) -> &'static str {
 1633        match self {
 1634            Self::ModifiersChanged(_) => "modifiers changed",
 1635            Self::Toggle(_) => "toggle",
 1636            Self::SettingsChange(_) => "settings change",
 1637            Self::NewLinesShown => "new lines shown",
 1638            Self::BufferEdited(_) => "buffer edited",
 1639            Self::RefreshRequested => "refresh requested",
 1640            Self::ExcerptsRemoved(_) => "excerpts removed",
 1641        }
 1642    }
 1643}
 1644
 1645pub enum FormatTarget {
 1646    Buffers(HashSet<Entity<Buffer>>),
 1647    Ranges(Vec<Range<MultiBufferPoint>>),
 1648}
 1649
 1650pub(crate) struct FocusedBlock {
 1651    id: BlockId,
 1652    focus_handle: WeakFocusHandle,
 1653}
 1654
 1655#[derive(Clone)]
 1656enum JumpData {
 1657    MultiBufferRow {
 1658        row: MultiBufferRow,
 1659        line_offset_from_top: u32,
 1660    },
 1661    MultiBufferPoint {
 1662        excerpt_id: ExcerptId,
 1663        position: Point,
 1664        anchor: text::Anchor,
 1665        line_offset_from_top: u32,
 1666    },
 1667}
 1668
 1669pub enum MultibufferSelectionMode {
 1670    First,
 1671    All,
 1672}
 1673
 1674#[derive(Clone, Copy, Debug, Default)]
 1675pub struct RewrapOptions {
 1676    pub override_language_settings: bool,
 1677    pub preserve_existing_whitespace: bool,
 1678}
 1679
 1680impl Editor {
 1681    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1682        let buffer = cx.new(|cx| Buffer::local("", cx));
 1683        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1684        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1685    }
 1686
 1687    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1688        let buffer = cx.new(|cx| Buffer::local("", cx));
 1689        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1690        Self::new(EditorMode::full(), buffer, None, window, cx)
 1691    }
 1692
 1693    pub fn auto_height(
 1694        min_lines: usize,
 1695        max_lines: usize,
 1696        window: &mut Window,
 1697        cx: &mut Context<Self>,
 1698    ) -> Self {
 1699        let buffer = cx.new(|cx| Buffer::local("", cx));
 1700        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1701        Self::new(
 1702            EditorMode::AutoHeight {
 1703                min_lines,
 1704                max_lines: Some(max_lines),
 1705            },
 1706            buffer,
 1707            None,
 1708            window,
 1709            cx,
 1710        )
 1711    }
 1712
 1713    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1714    /// The editor grows as tall as needed to fit its content.
 1715    pub fn auto_height_unbounded(
 1716        min_lines: usize,
 1717        window: &mut Window,
 1718        cx: &mut Context<Self>,
 1719    ) -> Self {
 1720        let buffer = cx.new(|cx| Buffer::local("", cx));
 1721        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1722        Self::new(
 1723            EditorMode::AutoHeight {
 1724                min_lines,
 1725                max_lines: None,
 1726            },
 1727            buffer,
 1728            None,
 1729            window,
 1730            cx,
 1731        )
 1732    }
 1733
 1734    pub fn for_buffer(
 1735        buffer: Entity<Buffer>,
 1736        project: Option<Entity<Project>>,
 1737        window: &mut Window,
 1738        cx: &mut Context<Self>,
 1739    ) -> Self {
 1740        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1741        Self::new(EditorMode::full(), buffer, project, window, cx)
 1742    }
 1743
 1744    pub fn for_multibuffer(
 1745        buffer: Entity<MultiBuffer>,
 1746        project: Option<Entity<Project>>,
 1747        window: &mut Window,
 1748        cx: &mut Context<Self>,
 1749    ) -> Self {
 1750        Self::new(EditorMode::full(), buffer, project, window, cx)
 1751    }
 1752
 1753    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1754        let mut clone = Self::new(
 1755            self.mode.clone(),
 1756            self.buffer.clone(),
 1757            self.project.clone(),
 1758            window,
 1759            cx,
 1760        );
 1761        self.display_map.update(cx, |display_map, cx| {
 1762            let snapshot = display_map.snapshot(cx);
 1763            clone.display_map.update(cx, |display_map, cx| {
 1764                display_map.set_state(&snapshot, cx);
 1765            });
 1766        });
 1767        clone.folds_did_change(cx);
 1768        clone.selections.clone_state(&self.selections);
 1769        clone.scroll_manager.clone_state(&self.scroll_manager);
 1770        clone.searchable = self.searchable;
 1771        clone.read_only = self.read_only;
 1772        clone
 1773    }
 1774
 1775    pub fn new(
 1776        mode: EditorMode,
 1777        buffer: Entity<MultiBuffer>,
 1778        project: Option<Entity<Project>>,
 1779        window: &mut Window,
 1780        cx: &mut Context<Self>,
 1781    ) -> Self {
 1782        Editor::new_internal(mode, buffer, project, None, window, cx)
 1783    }
 1784
 1785    fn new_internal(
 1786        mode: EditorMode,
 1787        buffer: Entity<MultiBuffer>,
 1788        project: Option<Entity<Project>>,
 1789        display_map: Option<Entity<DisplayMap>>,
 1790        window: &mut Window,
 1791        cx: &mut Context<Self>,
 1792    ) -> Self {
 1793        debug_assert!(
 1794            display_map.is_none() || mode.is_minimap(),
 1795            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1796        );
 1797
 1798        let full_mode = mode.is_full();
 1799        let is_minimap = mode.is_minimap();
 1800        let diagnostics_max_severity = if full_mode {
 1801            EditorSettings::get_global(cx)
 1802                .diagnostics_max_severity
 1803                .unwrap_or(DiagnosticSeverity::Hint)
 1804        } else {
 1805            DiagnosticSeverity::Off
 1806        };
 1807        let style = window.text_style();
 1808        let font_size = style.font_size.to_pixels(window.rem_size());
 1809        let editor = cx.entity().downgrade();
 1810        let fold_placeholder = FoldPlaceholder {
 1811            constrain_width: false,
 1812            render: Arc::new(move |fold_id, fold_range, cx| {
 1813                let editor = editor.clone();
 1814                div()
 1815                    .id(fold_id)
 1816                    .bg(cx.theme().colors().ghost_element_background)
 1817                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1818                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1819                    .rounded_xs()
 1820                    .size_full()
 1821                    .cursor_pointer()
 1822                    .child("")
 1823                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1824                    .on_click(move |_, _window, cx| {
 1825                        editor
 1826                            .update(cx, |editor, cx| {
 1827                                editor.unfold_ranges(
 1828                                    &[fold_range.start..fold_range.end],
 1829                                    true,
 1830                                    false,
 1831                                    cx,
 1832                                );
 1833                                cx.stop_propagation();
 1834                            })
 1835                            .ok();
 1836                    })
 1837                    .into_any()
 1838            }),
 1839            merge_adjacent: true,
 1840            ..FoldPlaceholder::default()
 1841        };
 1842        let display_map = display_map.unwrap_or_else(|| {
 1843            cx.new(|cx| {
 1844                DisplayMap::new(
 1845                    buffer.clone(),
 1846                    style.font(),
 1847                    font_size,
 1848                    None,
 1849                    FILE_HEADER_HEIGHT,
 1850                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1851                    fold_placeholder,
 1852                    diagnostics_max_severity,
 1853                    cx,
 1854                )
 1855            })
 1856        });
 1857
 1858        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1859
 1860        let blink_manager = cx.new(|cx| {
 1861            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1862            if is_minimap {
 1863                blink_manager.disable(cx);
 1864            }
 1865            blink_manager
 1866        });
 1867
 1868        let soft_wrap_mode_override =
 1869            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1870
 1871        let mut project_subscriptions = Vec::new();
 1872        if full_mode && let Some(project) = project.as_ref() {
 1873            project_subscriptions.push(cx.subscribe_in(
 1874                project,
 1875                window,
 1876                |editor, _, event, window, cx| match event {
 1877                    project::Event::RefreshCodeLens => {
 1878                        // we always query lens with actions, without storing them, always refreshing them
 1879                    }
 1880                    project::Event::RefreshInlayHints => {
 1881                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1882                    }
 1883                    project::Event::LanguageServerAdded(..)
 1884                    | project::Event::LanguageServerRemoved(..) => {
 1885                        if editor.tasks_update_task.is_none() {
 1886                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1887                        }
 1888                    }
 1889                    project::Event::SnippetEdit(id, snippet_edits) => {
 1890                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1891                            let focus_handle = editor.focus_handle(cx);
 1892                            if focus_handle.is_focused(window) {
 1893                                let snapshot = buffer.read(cx).snapshot();
 1894                                for (range, snippet) in snippet_edits {
 1895                                    let editor_range =
 1896                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1897                                    editor
 1898                                        .insert_snippet(
 1899                                            &[editor_range],
 1900                                            snippet.clone(),
 1901                                            window,
 1902                                            cx,
 1903                                        )
 1904                                        .ok();
 1905                                }
 1906                            }
 1907                        }
 1908                    }
 1909                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1910                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1911                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1912                        }
 1913                    }
 1914
 1915                    project::Event::EntryRenamed(transaction) => {
 1916                        let Some(workspace) = editor.workspace() else {
 1917                            return;
 1918                        };
 1919                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1920                        else {
 1921                            return;
 1922                        };
 1923                        if active_editor.entity_id() == cx.entity_id() {
 1924                            let edited_buffers_already_open = {
 1925                                let other_editors: Vec<Entity<Editor>> = workspace
 1926                                    .read(cx)
 1927                                    .panes()
 1928                                    .iter()
 1929                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1930                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1931                                    .collect();
 1932
 1933                                transaction.0.keys().all(|buffer| {
 1934                                    other_editors.iter().any(|editor| {
 1935                                        let multi_buffer = editor.read(cx).buffer();
 1936                                        multi_buffer.read(cx).is_singleton()
 1937                                            && multi_buffer.read(cx).as_singleton().map_or(
 1938                                                false,
 1939                                                |singleton| {
 1940                                                    singleton.entity_id() == buffer.entity_id()
 1941                                                },
 1942                                            )
 1943                                    })
 1944                                })
 1945                            };
 1946
 1947                            if !edited_buffers_already_open {
 1948                                let workspace = workspace.downgrade();
 1949                                let transaction = transaction.clone();
 1950                                cx.defer_in(window, move |_, window, cx| {
 1951                                    cx.spawn_in(window, async move |editor, cx| {
 1952                                        Self::open_project_transaction(
 1953                                            &editor,
 1954                                            workspace,
 1955                                            transaction,
 1956                                            "Rename".to_string(),
 1957                                            cx,
 1958                                        )
 1959                                        .await
 1960                                        .ok()
 1961                                    })
 1962                                    .detach();
 1963                                });
 1964                            }
 1965                        }
 1966                    }
 1967
 1968                    _ => {}
 1969                },
 1970            ));
 1971            if let Some(task_inventory) = project
 1972                .read(cx)
 1973                .task_store()
 1974                .read(cx)
 1975                .task_inventory()
 1976                .cloned()
 1977            {
 1978                project_subscriptions.push(cx.observe_in(
 1979                    &task_inventory,
 1980                    window,
 1981                    |editor, _, window, cx| {
 1982                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1983                    },
 1984                ));
 1985            };
 1986
 1987            project_subscriptions.push(cx.subscribe_in(
 1988                &project.read(cx).breakpoint_store(),
 1989                window,
 1990                |editor, _, event, window, cx| match event {
 1991                    BreakpointStoreEvent::ClearDebugLines => {
 1992                        editor.clear_row_highlights::<ActiveDebugLine>();
 1993                        editor.refresh_inline_values(cx);
 1994                    }
 1995                    BreakpointStoreEvent::SetDebugLine => {
 1996                        if editor.go_to_active_debug_line(window, cx) {
 1997                            cx.stop_propagation();
 1998                        }
 1999
 2000                        editor.refresh_inline_values(cx);
 2001                    }
 2002                    _ => {}
 2003                },
 2004            ));
 2005            let git_store = project.read(cx).git_store().clone();
 2006            let project = project.clone();
 2007            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2008                if let GitStoreEvent::RepositoryUpdated(
 2009                    _,
 2010                    RepositoryEvent::Updated {
 2011                        new_instance: true, ..
 2012                    },
 2013                    _,
 2014                ) = event
 2015                {
 2016                    this.load_diff_task = Some(
 2017                        update_uncommitted_diff_for_buffer(
 2018                            cx.entity(),
 2019                            &project,
 2020                            this.buffer.read(cx).all_buffers(),
 2021                            this.buffer.clone(),
 2022                            cx,
 2023                        )
 2024                        .shared(),
 2025                    );
 2026                }
 2027            }));
 2028        }
 2029
 2030        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2031
 2032        let inlay_hint_settings =
 2033            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2034        let focus_handle = cx.focus_handle();
 2035        if !is_minimap {
 2036            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2037                .detach();
 2038            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2039                .detach();
 2040            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2041                .detach();
 2042            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2043                .detach();
 2044            cx.observe_pending_input(window, Self::observe_pending_input)
 2045                .detach();
 2046        }
 2047
 2048        let show_indent_guides =
 2049            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2050                Some(false)
 2051            } else {
 2052                None
 2053            };
 2054
 2055        let breakpoint_store = match (&mode, project.as_ref()) {
 2056            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2057            _ => None,
 2058        };
 2059
 2060        let mut code_action_providers = Vec::new();
 2061        let mut load_uncommitted_diff = None;
 2062        if let Some(project) = project.clone() {
 2063            load_uncommitted_diff = Some(
 2064                update_uncommitted_diff_for_buffer(
 2065                    cx.entity(),
 2066                    &project,
 2067                    buffer.read(cx).all_buffers(),
 2068                    buffer.clone(),
 2069                    cx,
 2070                )
 2071                .shared(),
 2072            );
 2073            code_action_providers.push(Rc::new(project) as Rc<_>);
 2074        }
 2075
 2076        let mut editor = Self {
 2077            focus_handle,
 2078            show_cursor_when_unfocused: false,
 2079            last_focused_descendant: None,
 2080            buffer: buffer.clone(),
 2081            display_map: display_map.clone(),
 2082            placeholder_display_map: None,
 2083            selections,
 2084            scroll_manager: ScrollManager::new(cx),
 2085            columnar_selection_state: None,
 2086            add_selections_state: None,
 2087            select_next_state: None,
 2088            select_prev_state: None,
 2089            selection_history: SelectionHistory::default(),
 2090            defer_selection_effects: false,
 2091            deferred_selection_effects_state: None,
 2092            autoclose_regions: Vec::new(),
 2093            snippet_stack: InvalidationStack::default(),
 2094            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2095            ime_transaction: None,
 2096            active_diagnostics: ActiveDiagnostic::None,
 2097            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2098            inline_diagnostics_update: Task::ready(()),
 2099            inline_diagnostics: Vec::new(),
 2100            soft_wrap_mode_override,
 2101            diagnostics_max_severity,
 2102            hard_wrap: None,
 2103            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2104            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2105            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2106            project,
 2107            blink_manager: blink_manager.clone(),
 2108            show_local_selections: true,
 2109            show_scrollbars: ScrollbarAxes {
 2110                horizontal: full_mode,
 2111                vertical: full_mode,
 2112            },
 2113            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2114            offset_content: !matches!(mode, EditorMode::SingleLine),
 2115            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2116            show_gutter: full_mode,
 2117            show_line_numbers: (!full_mode).then_some(false),
 2118            use_relative_line_numbers: None,
 2119            disable_expand_excerpt_buttons: !full_mode,
 2120            show_git_diff_gutter: None,
 2121            show_code_actions: None,
 2122            show_runnables: None,
 2123            show_breakpoints: None,
 2124            show_wrap_guides: None,
 2125            show_indent_guides,
 2126            highlight_order: 0,
 2127            highlighted_rows: HashMap::default(),
 2128            background_highlights: HashMap::default(),
 2129            gutter_highlights: HashMap::default(),
 2130            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2131            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2132            nav_history: None,
 2133            context_menu: RefCell::new(None),
 2134            context_menu_options: None,
 2135            mouse_context_menu: None,
 2136            completion_tasks: Vec::new(),
 2137            inline_blame_popover: None,
 2138            inline_blame_popover_show_task: None,
 2139            signature_help_state: SignatureHelpState::default(),
 2140            auto_signature_help: None,
 2141            find_all_references_task_sources: Vec::new(),
 2142            next_completion_id: 0,
 2143            next_inlay_id: 0,
 2144            code_action_providers,
 2145            available_code_actions: None,
 2146            code_actions_task: None,
 2147            quick_selection_highlight_task: None,
 2148            debounced_selection_highlight_task: None,
 2149            document_highlights_task: None,
 2150            linked_editing_range_task: None,
 2151            pending_rename: None,
 2152            searchable: !is_minimap,
 2153            cursor_shape: EditorSettings::get_global(cx)
 2154                .cursor_shape
 2155                .unwrap_or_default(),
 2156            current_line_highlight: None,
 2157            autoindent_mode: Some(AutoindentMode::EachLine),
 2158            collapse_matches: false,
 2159            workspace: None,
 2160            input_enabled: !is_minimap,
 2161            use_modal_editing: full_mode,
 2162            read_only: is_minimap,
 2163            use_autoclose: true,
 2164            use_auto_surround: true,
 2165            auto_replace_emoji_shortcode: false,
 2166            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2167            leader_id: None,
 2168            remote_id: None,
 2169            hover_state: HoverState::default(),
 2170            pending_mouse_down: None,
 2171            hovered_link_state: None,
 2172            edit_prediction_provider: None,
 2173            active_edit_prediction: None,
 2174            stale_edit_prediction_in_menu: None,
 2175            edit_prediction_preview: EditPredictionPreview::Inactive {
 2176                released_too_fast: false,
 2177            },
 2178            inline_diagnostics_enabled: full_mode,
 2179            diagnostics_enabled: full_mode,
 2180            word_completions_enabled: full_mode,
 2181            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2182            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2183            gutter_hovered: false,
 2184            pixel_position_of_newest_cursor: None,
 2185            last_bounds: None,
 2186            last_position_map: None,
 2187            expect_bounds_change: None,
 2188            gutter_dimensions: GutterDimensions::default(),
 2189            style: None,
 2190            show_cursor_names: false,
 2191            hovered_cursors: HashMap::default(),
 2192            next_editor_action_id: EditorActionId::default(),
 2193            editor_actions: Rc::default(),
 2194            edit_predictions_hidden_for_vim_mode: false,
 2195            show_edit_predictions_override: None,
 2196            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2197            edit_prediction_settings: EditPredictionSettings::Disabled,
 2198            edit_prediction_indent_conflict: false,
 2199            edit_prediction_requires_modifier_in_indent_conflict: true,
 2200            custom_context_menu: None,
 2201            show_git_blame_gutter: false,
 2202            show_git_blame_inline: false,
 2203            show_selection_menu: None,
 2204            show_git_blame_inline_delay_task: None,
 2205            git_blame_inline_enabled: full_mode
 2206                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2207            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2208            serialize_dirty_buffers: !is_minimap
 2209                && ProjectSettings::get_global(cx)
 2210                    .session
 2211                    .restore_unsaved_buffers,
 2212            blame: None,
 2213            blame_subscription: None,
 2214            tasks: BTreeMap::default(),
 2215
 2216            breakpoint_store,
 2217            gutter_breakpoint_indicator: (None, None),
 2218            hovered_diff_hunk_row: None,
 2219            _subscriptions: (!is_minimap)
 2220                .then(|| {
 2221                    vec![
 2222                        cx.observe(&buffer, Self::on_buffer_changed),
 2223                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2224                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2225                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2226                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2227                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2228                        cx.observe_window_activation(window, |editor, window, cx| {
 2229                            let active = window.is_window_active();
 2230                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2231                                if active {
 2232                                    blink_manager.enable(cx);
 2233                                } else {
 2234                                    blink_manager.disable(cx);
 2235                                }
 2236                            });
 2237                            if active {
 2238                                editor.show_mouse_cursor(cx);
 2239                            }
 2240                        }),
 2241                    ]
 2242                })
 2243                .unwrap_or_default(),
 2244            tasks_update_task: None,
 2245            pull_diagnostics_task: Task::ready(()),
 2246            colors: None,
 2247            next_color_inlay_id: 0,
 2248            linked_edit_ranges: Default::default(),
 2249            in_project_search: false,
 2250            previous_search_ranges: None,
 2251            breadcrumb_header: None,
 2252            focused_block: None,
 2253            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2254            addons: HashMap::default(),
 2255            registered_buffers: HashMap::default(),
 2256            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2257            selection_mark_mode: false,
 2258            toggle_fold_multiple_buffers: Task::ready(()),
 2259            serialize_selections: Task::ready(()),
 2260            serialize_folds: Task::ready(()),
 2261            text_style_refinement: None,
 2262            load_diff_task: load_uncommitted_diff,
 2263            temporary_diff_override: false,
 2264            mouse_cursor_hidden: false,
 2265            minimap: None,
 2266            hide_mouse_mode: EditorSettings::get_global(cx)
 2267                .hide_mouse
 2268                .unwrap_or_default(),
 2269            change_list: ChangeList::new(),
 2270            mode,
 2271            selection_drag_state: SelectionDragState::None,
 2272            folding_newlines: Task::ready(()),
 2273            lookup_key: None,
 2274        };
 2275
 2276        if is_minimap {
 2277            return editor;
 2278        }
 2279
 2280        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2281            editor
 2282                ._subscriptions
 2283                .push(cx.observe(breakpoints, |_, _, cx| {
 2284                    cx.notify();
 2285                }));
 2286        }
 2287        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2288        editor._subscriptions.extend(project_subscriptions);
 2289
 2290        editor._subscriptions.push(cx.subscribe_in(
 2291            &cx.entity(),
 2292            window,
 2293            |editor, _, e: &EditorEvent, window, cx| match e {
 2294                EditorEvent::ScrollPositionChanged { local, .. } => {
 2295                    if *local {
 2296                        let new_anchor = editor.scroll_manager.anchor();
 2297                        let snapshot = editor.snapshot(window, cx);
 2298                        editor.update_restoration_data(cx, move |data| {
 2299                            data.scroll_position = (
 2300                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2301                                new_anchor.offset,
 2302                            );
 2303                        });
 2304                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2305                        editor.inline_blame_popover.take();
 2306                    }
 2307                }
 2308                EditorEvent::Edited { .. } => {
 2309                    if !vim_enabled(cx) {
 2310                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2311                        let pop_state = editor
 2312                            .change_list
 2313                            .last()
 2314                            .map(|previous| {
 2315                                previous.len() == selections.len()
 2316                                    && previous.iter().enumerate().all(|(ix, p)| {
 2317                                        p.to_display_point(&map).row()
 2318                                            == selections[ix].head().row()
 2319                                    })
 2320                            })
 2321                            .unwrap_or(false);
 2322                        let new_positions = selections
 2323                            .into_iter()
 2324                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2325                            .collect();
 2326                        editor
 2327                            .change_list
 2328                            .push_to_change_list(pop_state, new_positions);
 2329                    }
 2330                }
 2331                _ => (),
 2332            },
 2333        ));
 2334
 2335        if let Some(dap_store) = editor
 2336            .project
 2337            .as_ref()
 2338            .map(|project| project.read(cx).dap_store())
 2339        {
 2340            let weak_editor = cx.weak_entity();
 2341
 2342            editor
 2343                ._subscriptions
 2344                .push(
 2345                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2346                        let session_entity = cx.entity();
 2347                        weak_editor
 2348                            .update(cx, |editor, cx| {
 2349                                editor._subscriptions.push(
 2350                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2351                                );
 2352                            })
 2353                            .ok();
 2354                    }),
 2355                );
 2356
 2357            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2358                editor
 2359                    ._subscriptions
 2360                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2361            }
 2362        }
 2363
 2364        // skip adding the initial selection to selection history
 2365        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2366        editor.end_selection(window, cx);
 2367        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2368
 2369        editor.scroll_manager.show_scrollbars(window, cx);
 2370        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2371
 2372        if full_mode {
 2373            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2374            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2375
 2376            if editor.git_blame_inline_enabled {
 2377                editor.start_git_blame_inline(false, window, cx);
 2378            }
 2379
 2380            editor.go_to_active_debug_line(window, cx);
 2381
 2382            if let Some(buffer) = buffer.read(cx).as_singleton()
 2383                && let Some(project) = editor.project()
 2384            {
 2385                let handle = project.update(cx, |project, cx| {
 2386                    project.register_buffer_with_language_servers(&buffer, cx)
 2387                });
 2388                editor
 2389                    .registered_buffers
 2390                    .insert(buffer.read(cx).remote_id(), handle);
 2391            }
 2392
 2393            editor.minimap =
 2394                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2395            editor.colors = Some(LspColorData::new(cx));
 2396            editor.update_lsp_data(false, None, window, cx);
 2397        }
 2398
 2399        if editor.mode.is_full() {
 2400            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2401        }
 2402
 2403        editor
 2404    }
 2405
 2406    pub fn deploy_mouse_context_menu(
 2407        &mut self,
 2408        position: gpui::Point<Pixels>,
 2409        context_menu: Entity<ContextMenu>,
 2410        window: &mut Window,
 2411        cx: &mut Context<Self>,
 2412    ) {
 2413        self.mouse_context_menu = Some(MouseContextMenu::new(
 2414            self,
 2415            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2416            context_menu,
 2417            window,
 2418            cx,
 2419        ));
 2420    }
 2421
 2422    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2423        self.mouse_context_menu
 2424            .as_ref()
 2425            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2426    }
 2427
 2428    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2429        if self
 2430            .selections
 2431            .pending_anchor()
 2432            .is_some_and(|pending_selection| {
 2433                let snapshot = self.buffer().read(cx).snapshot(cx);
 2434                pending_selection.range().includes(range, &snapshot)
 2435            })
 2436        {
 2437            return true;
 2438        }
 2439
 2440        self.selections
 2441            .disjoint_in_range::<usize>(range.clone(), cx)
 2442            .into_iter()
 2443            .any(|selection| {
 2444                // This is needed to cover a corner case, if we just check for an existing
 2445                // selection in the fold range, having a cursor at the start of the fold
 2446                // marks it as selected. Non-empty selections don't cause this.
 2447                let length = selection.end - selection.start;
 2448                length > 0
 2449            })
 2450    }
 2451
 2452    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2453        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2454    }
 2455
 2456    fn key_context_internal(
 2457        &self,
 2458        has_active_edit_prediction: bool,
 2459        window: &Window,
 2460        cx: &App,
 2461    ) -> KeyContext {
 2462        let mut key_context = KeyContext::new_with_defaults();
 2463        key_context.add("Editor");
 2464        let mode = match self.mode {
 2465            EditorMode::SingleLine => "single_line",
 2466            EditorMode::AutoHeight { .. } => "auto_height",
 2467            EditorMode::Minimap { .. } => "minimap",
 2468            EditorMode::Full { .. } => "full",
 2469        };
 2470
 2471        if EditorSettings::jupyter_enabled(cx) {
 2472            key_context.add("jupyter");
 2473        }
 2474
 2475        key_context.set("mode", mode);
 2476        if self.pending_rename.is_some() {
 2477            key_context.add("renaming");
 2478        }
 2479
 2480        match self.context_menu.borrow().as_ref() {
 2481            Some(CodeContextMenu::Completions(menu)) => {
 2482                if menu.visible() {
 2483                    key_context.add("menu");
 2484                    key_context.add("showing_completions");
 2485                }
 2486            }
 2487            Some(CodeContextMenu::CodeActions(menu)) => {
 2488                if menu.visible() {
 2489                    key_context.add("menu");
 2490                    key_context.add("showing_code_actions")
 2491                }
 2492            }
 2493            None => {}
 2494        }
 2495
 2496        if self.signature_help_state.has_multiple_signatures() {
 2497            key_context.add("showing_signature_help");
 2498        }
 2499
 2500        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2501        if !self.focus_handle(cx).contains_focused(window, cx)
 2502            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2503        {
 2504            for addon in self.addons.values() {
 2505                addon.extend_key_context(&mut key_context, cx)
 2506            }
 2507        }
 2508
 2509        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2510            if let Some(extension) = singleton_buffer
 2511                .read(cx)
 2512                .file()
 2513                .and_then(|file| file.path().extension())
 2514            {
 2515                key_context.set("extension", extension.to_string());
 2516            }
 2517        } else {
 2518            key_context.add("multibuffer");
 2519        }
 2520
 2521        if has_active_edit_prediction {
 2522            if self.edit_prediction_in_conflict() {
 2523                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2524            } else {
 2525                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2526                key_context.add("copilot_suggestion");
 2527            }
 2528        }
 2529
 2530        if self.selection_mark_mode {
 2531            key_context.add("selection_mode");
 2532        }
 2533
 2534        key_context
 2535    }
 2536
 2537    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2538        self.last_bounds.as_ref()
 2539    }
 2540
 2541    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2542        if self.mouse_cursor_hidden {
 2543            self.mouse_cursor_hidden = false;
 2544            cx.notify();
 2545        }
 2546    }
 2547
 2548    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2549        let hide_mouse_cursor = match origin {
 2550            HideMouseCursorOrigin::TypingAction => {
 2551                matches!(
 2552                    self.hide_mouse_mode,
 2553                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2554                )
 2555            }
 2556            HideMouseCursorOrigin::MovementAction => {
 2557                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2558            }
 2559        };
 2560        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2561            self.mouse_cursor_hidden = hide_mouse_cursor;
 2562            cx.notify();
 2563        }
 2564    }
 2565
 2566    pub fn edit_prediction_in_conflict(&self) -> bool {
 2567        if !self.show_edit_predictions_in_menu() {
 2568            return false;
 2569        }
 2570
 2571        let showing_completions = self
 2572            .context_menu
 2573            .borrow()
 2574            .as_ref()
 2575            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2576
 2577        showing_completions
 2578            || self.edit_prediction_requires_modifier()
 2579            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2580            // bindings to insert tab characters.
 2581            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2582    }
 2583
 2584    pub fn accept_edit_prediction_keybind(
 2585        &self,
 2586        accept_partial: bool,
 2587        window: &Window,
 2588        cx: &App,
 2589    ) -> AcceptEditPredictionBinding {
 2590        let key_context = self.key_context_internal(true, window, cx);
 2591        let in_conflict = self.edit_prediction_in_conflict();
 2592
 2593        let bindings = if accept_partial {
 2594            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2595        } else {
 2596            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2597        };
 2598
 2599        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2600        // just the first one.
 2601        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2602            !in_conflict
 2603                || binding
 2604                    .keystrokes()
 2605                    .first()
 2606                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2607        }))
 2608    }
 2609
 2610    pub fn new_file(
 2611        workspace: &mut Workspace,
 2612        _: &workspace::NewFile,
 2613        window: &mut Window,
 2614        cx: &mut Context<Workspace>,
 2615    ) {
 2616        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2617            "Failed to create buffer",
 2618            window,
 2619            cx,
 2620            |e, _, _| match e.error_code() {
 2621                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2622                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2623                e.error_tag("required").unwrap_or("the latest version")
 2624            )),
 2625                _ => None,
 2626            },
 2627        );
 2628    }
 2629
 2630    pub fn new_in_workspace(
 2631        workspace: &mut Workspace,
 2632        window: &mut Window,
 2633        cx: &mut Context<Workspace>,
 2634    ) -> Task<Result<Entity<Editor>>> {
 2635        let project = workspace.project().clone();
 2636        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2637
 2638        cx.spawn_in(window, async move |workspace, cx| {
 2639            let buffer = create.await?;
 2640            workspace.update_in(cx, |workspace, window, cx| {
 2641                let editor =
 2642                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2643                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2644                editor
 2645            })
 2646        })
 2647    }
 2648
 2649    fn new_file_vertical(
 2650        workspace: &mut Workspace,
 2651        _: &workspace::NewFileSplitVertical,
 2652        window: &mut Window,
 2653        cx: &mut Context<Workspace>,
 2654    ) {
 2655        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2656    }
 2657
 2658    fn new_file_horizontal(
 2659        workspace: &mut Workspace,
 2660        _: &workspace::NewFileSplitHorizontal,
 2661        window: &mut Window,
 2662        cx: &mut Context<Workspace>,
 2663    ) {
 2664        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2665    }
 2666
 2667    fn new_file_in_direction(
 2668        workspace: &mut Workspace,
 2669        direction: SplitDirection,
 2670        window: &mut Window,
 2671        cx: &mut Context<Workspace>,
 2672    ) {
 2673        let project = workspace.project().clone();
 2674        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2675
 2676        cx.spawn_in(window, async move |workspace, cx| {
 2677            let buffer = create.await?;
 2678            workspace.update_in(cx, move |workspace, window, cx| {
 2679                workspace.split_item(
 2680                    direction,
 2681                    Box::new(
 2682                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2683                    ),
 2684                    window,
 2685                    cx,
 2686                )
 2687            })?;
 2688            anyhow::Ok(())
 2689        })
 2690        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2691            match e.error_code() {
 2692                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2693                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2694                e.error_tag("required").unwrap_or("the latest version")
 2695            )),
 2696                _ => None,
 2697            }
 2698        });
 2699    }
 2700
 2701    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2702        self.leader_id
 2703    }
 2704
 2705    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2706        &self.buffer
 2707    }
 2708
 2709    pub fn project(&self) -> Option<&Entity<Project>> {
 2710        self.project.as_ref()
 2711    }
 2712
 2713    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2714        self.workspace.as_ref()?.0.upgrade()
 2715    }
 2716
 2717    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2718        self.buffer().read(cx).title(cx)
 2719    }
 2720
 2721    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2722        let git_blame_gutter_max_author_length = self
 2723            .render_git_blame_gutter(cx)
 2724            .then(|| {
 2725                if let Some(blame) = self.blame.as_ref() {
 2726                    let max_author_length =
 2727                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2728                    Some(max_author_length)
 2729                } else {
 2730                    None
 2731                }
 2732            })
 2733            .flatten();
 2734
 2735        EditorSnapshot {
 2736            mode: self.mode.clone(),
 2737            show_gutter: self.show_gutter,
 2738            show_line_numbers: self.show_line_numbers,
 2739            show_git_diff_gutter: self.show_git_diff_gutter,
 2740            show_code_actions: self.show_code_actions,
 2741            show_runnables: self.show_runnables,
 2742            show_breakpoints: self.show_breakpoints,
 2743            git_blame_gutter_max_author_length,
 2744            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2745            placeholder_display_snapshot: self
 2746                .placeholder_display_map
 2747                .as_ref()
 2748                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2749            scroll_anchor: self.scroll_manager.anchor(),
 2750            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2751            is_focused: self.focus_handle.is_focused(window),
 2752            current_line_highlight: self
 2753                .current_line_highlight
 2754                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2755            gutter_hovered: self.gutter_hovered,
 2756        }
 2757    }
 2758
 2759    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2760        self.buffer.read(cx).language_at(point, cx)
 2761    }
 2762
 2763    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2764        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2765    }
 2766
 2767    pub fn active_excerpt(
 2768        &self,
 2769        cx: &App,
 2770    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2771        self.buffer
 2772            .read(cx)
 2773            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2774    }
 2775
 2776    pub fn mode(&self) -> &EditorMode {
 2777        &self.mode
 2778    }
 2779
 2780    pub fn set_mode(&mut self, mode: EditorMode) {
 2781        self.mode = mode;
 2782    }
 2783
 2784    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2785        self.collaboration_hub.as_deref()
 2786    }
 2787
 2788    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2789        self.collaboration_hub = Some(hub);
 2790    }
 2791
 2792    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2793        self.in_project_search = in_project_search;
 2794    }
 2795
 2796    pub fn set_custom_context_menu(
 2797        &mut self,
 2798        f: impl 'static
 2799        + Fn(
 2800            &mut Self,
 2801            DisplayPoint,
 2802            &mut Window,
 2803            &mut Context<Self>,
 2804        ) -> Option<Entity<ui::ContextMenu>>,
 2805    ) {
 2806        self.custom_context_menu = Some(Box::new(f))
 2807    }
 2808
 2809    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2810        self.completion_provider = provider;
 2811    }
 2812
 2813    #[cfg(any(test, feature = "test-support"))]
 2814    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2815        self.completion_provider.clone()
 2816    }
 2817
 2818    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2819        self.semantics_provider.clone()
 2820    }
 2821
 2822    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2823        self.semantics_provider = provider;
 2824    }
 2825
 2826    pub fn set_edit_prediction_provider<T>(
 2827        &mut self,
 2828        provider: Option<Entity<T>>,
 2829        window: &mut Window,
 2830        cx: &mut Context<Self>,
 2831    ) where
 2832        T: EditPredictionProvider,
 2833    {
 2834        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2835            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2836                if this.focus_handle.is_focused(window) {
 2837                    this.update_visible_edit_prediction(window, cx);
 2838                }
 2839            }),
 2840            provider: Arc::new(provider),
 2841        });
 2842        self.update_edit_prediction_settings(cx);
 2843        self.refresh_edit_prediction(false, false, window, cx);
 2844    }
 2845
 2846    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2847        self.placeholder_display_map
 2848            .as_ref()
 2849            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2850    }
 2851
 2852    pub fn set_placeholder_text(
 2853        &mut self,
 2854        placeholder_text: &str,
 2855        window: &mut Window,
 2856        cx: &mut Context<Self>,
 2857    ) {
 2858        let multibuffer = cx
 2859            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2860
 2861        let style = window.text_style();
 2862
 2863        self.placeholder_display_map = Some(cx.new(|cx| {
 2864            DisplayMap::new(
 2865                multibuffer,
 2866                style.font(),
 2867                style.font_size.to_pixels(window.rem_size()),
 2868                None,
 2869                FILE_HEADER_HEIGHT,
 2870                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2871                Default::default(),
 2872                DiagnosticSeverity::Off,
 2873                cx,
 2874            )
 2875        }));
 2876        cx.notify();
 2877    }
 2878
 2879    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2880        self.cursor_shape = cursor_shape;
 2881
 2882        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2883        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2884
 2885        cx.notify();
 2886    }
 2887
 2888    pub fn set_current_line_highlight(
 2889        &mut self,
 2890        current_line_highlight: Option<CurrentLineHighlight>,
 2891    ) {
 2892        self.current_line_highlight = current_line_highlight;
 2893    }
 2894
 2895    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2896        self.collapse_matches = collapse_matches;
 2897    }
 2898
 2899    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2900        let buffers = self.buffer.read(cx).all_buffers();
 2901        let Some(project) = self.project.as_ref() else {
 2902            return;
 2903        };
 2904        project.update(cx, |project, cx| {
 2905            for buffer in buffers {
 2906                self.registered_buffers
 2907                    .entry(buffer.read(cx).remote_id())
 2908                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2909            }
 2910        })
 2911    }
 2912
 2913    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2914        if self.collapse_matches {
 2915            return range.start..range.start;
 2916        }
 2917        range.clone()
 2918    }
 2919
 2920    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2921        if self.display_map.read(cx).clip_at_line_ends != clip {
 2922            self.display_map
 2923                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2924        }
 2925    }
 2926
 2927    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2928        self.input_enabled = input_enabled;
 2929    }
 2930
 2931    pub fn set_edit_predictions_hidden_for_vim_mode(
 2932        &mut self,
 2933        hidden: bool,
 2934        window: &mut Window,
 2935        cx: &mut Context<Self>,
 2936    ) {
 2937        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2938            self.edit_predictions_hidden_for_vim_mode = hidden;
 2939            if hidden {
 2940                self.update_visible_edit_prediction(window, cx);
 2941            } else {
 2942                self.refresh_edit_prediction(true, false, window, cx);
 2943            }
 2944        }
 2945    }
 2946
 2947    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2948        self.menu_edit_predictions_policy = value;
 2949    }
 2950
 2951    pub fn set_autoindent(&mut self, autoindent: bool) {
 2952        if autoindent {
 2953            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2954        } else {
 2955            self.autoindent_mode = None;
 2956        }
 2957    }
 2958
 2959    pub fn read_only(&self, cx: &App) -> bool {
 2960        self.read_only || self.buffer.read(cx).read_only()
 2961    }
 2962
 2963    pub fn set_read_only(&mut self, read_only: bool) {
 2964        self.read_only = read_only;
 2965    }
 2966
 2967    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2968        self.use_autoclose = autoclose;
 2969    }
 2970
 2971    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2972        self.use_auto_surround = auto_surround;
 2973    }
 2974
 2975    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2976        self.auto_replace_emoji_shortcode = auto_replace;
 2977    }
 2978
 2979    pub fn toggle_edit_predictions(
 2980        &mut self,
 2981        _: &ToggleEditPrediction,
 2982        window: &mut Window,
 2983        cx: &mut Context<Self>,
 2984    ) {
 2985        if self.show_edit_predictions_override.is_some() {
 2986            self.set_show_edit_predictions(None, window, cx);
 2987        } else {
 2988            let show_edit_predictions = !self.edit_predictions_enabled();
 2989            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2990        }
 2991    }
 2992
 2993    pub fn set_show_edit_predictions(
 2994        &mut self,
 2995        show_edit_predictions: Option<bool>,
 2996        window: &mut Window,
 2997        cx: &mut Context<Self>,
 2998    ) {
 2999        self.show_edit_predictions_override = show_edit_predictions;
 3000        self.update_edit_prediction_settings(cx);
 3001
 3002        if let Some(false) = show_edit_predictions {
 3003            self.discard_edit_prediction(false, cx);
 3004        } else {
 3005            self.refresh_edit_prediction(false, true, window, cx);
 3006        }
 3007    }
 3008
 3009    fn edit_predictions_disabled_in_scope(
 3010        &self,
 3011        buffer: &Entity<Buffer>,
 3012        buffer_position: language::Anchor,
 3013        cx: &App,
 3014    ) -> bool {
 3015        let snapshot = buffer.read(cx).snapshot();
 3016        let settings = snapshot.settings_at(buffer_position, cx);
 3017
 3018        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3019            return false;
 3020        };
 3021
 3022        scope.override_name().is_some_and(|scope_name| {
 3023            settings
 3024                .edit_predictions_disabled_in
 3025                .iter()
 3026                .any(|s| s == scope_name)
 3027        })
 3028    }
 3029
 3030    pub fn set_use_modal_editing(&mut self, to: bool) {
 3031        self.use_modal_editing = to;
 3032    }
 3033
 3034    pub fn use_modal_editing(&self) -> bool {
 3035        self.use_modal_editing
 3036    }
 3037
 3038    fn selections_did_change(
 3039        &mut self,
 3040        local: bool,
 3041        old_cursor_position: &Anchor,
 3042        effects: SelectionEffects,
 3043        window: &mut Window,
 3044        cx: &mut Context<Self>,
 3045    ) {
 3046        window.invalidate_character_coordinates();
 3047
 3048        // Copy selections to primary selection buffer
 3049        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3050        if local {
 3051            let selections = self.selections.all::<usize>(cx);
 3052            let buffer_handle = self.buffer.read(cx).read(cx);
 3053
 3054            let mut text = String::new();
 3055            for (index, selection) in selections.iter().enumerate() {
 3056                let text_for_selection = buffer_handle
 3057                    .text_for_range(selection.start..selection.end)
 3058                    .collect::<String>();
 3059
 3060                text.push_str(&text_for_selection);
 3061                if index != selections.len() - 1 {
 3062                    text.push('\n');
 3063                }
 3064            }
 3065
 3066            if !text.is_empty() {
 3067                cx.write_to_primary(ClipboardItem::new_string(text));
 3068            }
 3069        }
 3070
 3071        let selection_anchors = self.selections.disjoint_anchors_arc();
 3072
 3073        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3074            self.buffer.update(cx, |buffer, cx| {
 3075                buffer.set_active_selections(
 3076                    &selection_anchors,
 3077                    self.selections.line_mode(),
 3078                    self.cursor_shape,
 3079                    cx,
 3080                )
 3081            });
 3082        }
 3083        let display_map = self
 3084            .display_map
 3085            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3086        let buffer = &display_map.buffer_snapshot;
 3087        if self.selections.count() == 1 {
 3088            self.add_selections_state = None;
 3089        }
 3090        self.select_next_state = None;
 3091        self.select_prev_state = None;
 3092        self.select_syntax_node_history.try_clear();
 3093        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3094        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3095        self.take_rename(false, window, cx);
 3096
 3097        let newest_selection = self.selections.newest_anchor();
 3098        let new_cursor_position = newest_selection.head();
 3099        let selection_start = newest_selection.start;
 3100
 3101        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3102            self.push_to_nav_history(
 3103                *old_cursor_position,
 3104                Some(new_cursor_position.to_point(buffer)),
 3105                false,
 3106                effects.nav_history == Some(true),
 3107                cx,
 3108            );
 3109        }
 3110
 3111        if local {
 3112            if let Some(buffer_id) = new_cursor_position.buffer_id
 3113                && !self.registered_buffers.contains_key(&buffer_id)
 3114                && let Some(project) = self.project.as_ref()
 3115            {
 3116                project.update(cx, |project, cx| {
 3117                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3118                        return;
 3119                    };
 3120                    self.registered_buffers.insert(
 3121                        buffer_id,
 3122                        project.register_buffer_with_language_servers(&buffer, cx),
 3123                    );
 3124                })
 3125            }
 3126
 3127            let mut context_menu = self.context_menu.borrow_mut();
 3128            let completion_menu = match context_menu.as_ref() {
 3129                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3130                Some(CodeContextMenu::CodeActions(_)) => {
 3131                    *context_menu = None;
 3132                    None
 3133                }
 3134                None => None,
 3135            };
 3136            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3137            drop(context_menu);
 3138
 3139            if effects.completions
 3140                && let Some(completion_position) = completion_position
 3141            {
 3142                let start_offset = selection_start.to_offset(buffer);
 3143                let position_matches = start_offset == completion_position.to_offset(buffer);
 3144                let continue_showing = if position_matches {
 3145                    if self.snippet_stack.is_empty() {
 3146                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3147                            == Some(CharKind::Word)
 3148                    } else {
 3149                        // Snippet choices can be shown even when the cursor is in whitespace.
 3150                        // Dismissing the menu with actions like backspace is handled by
 3151                        // invalidation regions.
 3152                        true
 3153                    }
 3154                } else {
 3155                    false
 3156                };
 3157
 3158                if continue_showing {
 3159                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3160                } else {
 3161                    self.hide_context_menu(window, cx);
 3162                }
 3163            }
 3164
 3165            hide_hover(self, cx);
 3166
 3167            if old_cursor_position.to_display_point(&display_map).row()
 3168                != new_cursor_position.to_display_point(&display_map).row()
 3169            {
 3170                self.available_code_actions.take();
 3171            }
 3172            self.refresh_code_actions(window, cx);
 3173            self.refresh_document_highlights(cx);
 3174            self.refresh_selected_text_highlights(false, window, cx);
 3175            refresh_matching_bracket_highlights(self, window, cx);
 3176            self.update_visible_edit_prediction(window, cx);
 3177            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3178            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3179            self.inline_blame_popover.take();
 3180            if self.git_blame_inline_enabled {
 3181                self.start_inline_blame_timer(window, cx);
 3182            }
 3183        }
 3184
 3185        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3186        cx.emit(EditorEvent::SelectionsChanged { local });
 3187
 3188        let selections = &self.selections.disjoint_anchors_arc();
 3189        if selections.len() == 1 {
 3190            cx.emit(SearchEvent::ActiveMatchChanged)
 3191        }
 3192        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3193            let inmemory_selections = selections
 3194                .iter()
 3195                .map(|s| {
 3196                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3197                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3198                })
 3199                .collect();
 3200            self.update_restoration_data(cx, |data| {
 3201                data.selections = inmemory_selections;
 3202            });
 3203
 3204            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3205                && let Some(workspace_id) =
 3206                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3207            {
 3208                let snapshot = self.buffer().read(cx).snapshot(cx);
 3209                let selections = selections.clone();
 3210                let background_executor = cx.background_executor().clone();
 3211                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3212                self.serialize_selections = cx.background_spawn(async move {
 3213                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3214                    let db_selections = selections
 3215                        .iter()
 3216                        .map(|selection| {
 3217                            (
 3218                                selection.start.to_offset(&snapshot),
 3219                                selection.end.to_offset(&snapshot),
 3220                            )
 3221                        })
 3222                        .collect();
 3223
 3224                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3225                        .await
 3226                        .with_context(|| {
 3227                            format!(
 3228                                "persisting editor selections for editor {editor_id}, \
 3229                                workspace {workspace_id:?}"
 3230                            )
 3231                        })
 3232                        .log_err();
 3233                });
 3234            }
 3235        }
 3236
 3237        cx.notify();
 3238    }
 3239
 3240    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3241        use text::ToOffset as _;
 3242        use text::ToPoint as _;
 3243
 3244        if self.mode.is_minimap()
 3245            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3246        {
 3247            return;
 3248        }
 3249
 3250        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3251            return;
 3252        };
 3253
 3254        let snapshot = singleton.read(cx).snapshot();
 3255        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3256            let display_snapshot = display_map.snapshot(cx);
 3257
 3258            display_snapshot
 3259                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3260                .map(|fold| {
 3261                    fold.range.start.text_anchor.to_point(&snapshot)
 3262                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3263                })
 3264                .collect()
 3265        });
 3266        self.update_restoration_data(cx, |data| {
 3267            data.folds = inmemory_folds;
 3268        });
 3269
 3270        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3271            return;
 3272        };
 3273        let background_executor = cx.background_executor().clone();
 3274        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3275        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3276            display_map
 3277                .snapshot(cx)
 3278                .folds_in_range(0..snapshot.len())
 3279                .map(|fold| {
 3280                    (
 3281                        fold.range.start.text_anchor.to_offset(&snapshot),
 3282                        fold.range.end.text_anchor.to_offset(&snapshot),
 3283                    )
 3284                })
 3285                .collect()
 3286        });
 3287        self.serialize_folds = cx.background_spawn(async move {
 3288            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3289            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3290                .await
 3291                .with_context(|| {
 3292                    format!(
 3293                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3294                    )
 3295                })
 3296                .log_err();
 3297        });
 3298    }
 3299
 3300    pub fn sync_selections(
 3301        &mut self,
 3302        other: Entity<Editor>,
 3303        cx: &mut Context<Self>,
 3304    ) -> gpui::Subscription {
 3305        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3306        if !other_selections.is_empty() {
 3307            self.selections.change_with(cx, |selections| {
 3308                selections.select_anchors(other_selections);
 3309            });
 3310        }
 3311
 3312        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3313            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3314                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3315                if other_selections.is_empty() {
 3316                    return;
 3317                }
 3318                this.selections.change_with(cx, |selections| {
 3319                    selections.select_anchors(other_selections);
 3320                });
 3321            }
 3322        });
 3323
 3324        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3325            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3326                let these_selections = this.selections.disjoint_anchors().to_vec();
 3327                if these_selections.is_empty() {
 3328                    return;
 3329                }
 3330                other.update(cx, |other_editor, cx| {
 3331                    other_editor.selections.change_with(cx, |selections| {
 3332                        selections.select_anchors(these_selections);
 3333                    })
 3334                });
 3335            }
 3336        });
 3337
 3338        Subscription::join(other_subscription, this_subscription)
 3339    }
 3340
 3341    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3342    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3343    /// effects of selection change occur at the end of the transaction.
 3344    pub fn change_selections<R>(
 3345        &mut self,
 3346        effects: SelectionEffects,
 3347        window: &mut Window,
 3348        cx: &mut Context<Self>,
 3349        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3350    ) -> R {
 3351        if let Some(state) = &mut self.deferred_selection_effects_state {
 3352            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3353            state.effects.completions = effects.completions;
 3354            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3355            let (changed, result) = self.selections.change_with(cx, change);
 3356            state.changed |= changed;
 3357            return result;
 3358        }
 3359        let mut state = DeferredSelectionEffectsState {
 3360            changed: false,
 3361            effects,
 3362            old_cursor_position: self.selections.newest_anchor().head(),
 3363            history_entry: SelectionHistoryEntry {
 3364                selections: self.selections.disjoint_anchors_arc(),
 3365                select_next_state: self.select_next_state.clone(),
 3366                select_prev_state: self.select_prev_state.clone(),
 3367                add_selections_state: self.add_selections_state.clone(),
 3368            },
 3369        };
 3370        let (changed, result) = self.selections.change_with(cx, change);
 3371        state.changed = state.changed || changed;
 3372        if self.defer_selection_effects {
 3373            self.deferred_selection_effects_state = Some(state);
 3374        } else {
 3375            self.apply_selection_effects(state, window, cx);
 3376        }
 3377        result
 3378    }
 3379
 3380    /// Defers the effects of selection change, so that the effects of multiple calls to
 3381    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3382    /// to selection history and the state of popovers based on selection position aren't
 3383    /// erroneously updated.
 3384    pub fn with_selection_effects_deferred<R>(
 3385        &mut self,
 3386        window: &mut Window,
 3387        cx: &mut Context<Self>,
 3388        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3389    ) -> R {
 3390        let already_deferred = self.defer_selection_effects;
 3391        self.defer_selection_effects = true;
 3392        let result = update(self, window, cx);
 3393        if !already_deferred {
 3394            self.defer_selection_effects = false;
 3395            if let Some(state) = self.deferred_selection_effects_state.take() {
 3396                self.apply_selection_effects(state, window, cx);
 3397            }
 3398        }
 3399        result
 3400    }
 3401
 3402    fn apply_selection_effects(
 3403        &mut self,
 3404        state: DeferredSelectionEffectsState,
 3405        window: &mut Window,
 3406        cx: &mut Context<Self>,
 3407    ) {
 3408        if state.changed {
 3409            self.selection_history.push(state.history_entry);
 3410
 3411            if let Some(autoscroll) = state.effects.scroll {
 3412                self.request_autoscroll(autoscroll, cx);
 3413            }
 3414
 3415            let old_cursor_position = &state.old_cursor_position;
 3416
 3417            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3418
 3419            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3420                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3421            }
 3422        }
 3423    }
 3424
 3425    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3426    where
 3427        I: IntoIterator<Item = (Range<S>, T)>,
 3428        S: ToOffset,
 3429        T: Into<Arc<str>>,
 3430    {
 3431        if self.read_only(cx) {
 3432            return;
 3433        }
 3434
 3435        self.buffer
 3436            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3437    }
 3438
 3439    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3440    where
 3441        I: IntoIterator<Item = (Range<S>, T)>,
 3442        S: ToOffset,
 3443        T: Into<Arc<str>>,
 3444    {
 3445        if self.read_only(cx) {
 3446            return;
 3447        }
 3448
 3449        self.buffer.update(cx, |buffer, cx| {
 3450            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3451        });
 3452    }
 3453
 3454    pub fn edit_with_block_indent<I, S, T>(
 3455        &mut self,
 3456        edits: I,
 3457        original_indent_columns: Vec<Option<u32>>,
 3458        cx: &mut Context<Self>,
 3459    ) where
 3460        I: IntoIterator<Item = (Range<S>, T)>,
 3461        S: ToOffset,
 3462        T: Into<Arc<str>>,
 3463    {
 3464        if self.read_only(cx) {
 3465            return;
 3466        }
 3467
 3468        self.buffer.update(cx, |buffer, cx| {
 3469            buffer.edit(
 3470                edits,
 3471                Some(AutoindentMode::Block {
 3472                    original_indent_columns,
 3473                }),
 3474                cx,
 3475            )
 3476        });
 3477    }
 3478
 3479    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3480        self.hide_context_menu(window, cx);
 3481
 3482        match phase {
 3483            SelectPhase::Begin {
 3484                position,
 3485                add,
 3486                click_count,
 3487            } => self.begin_selection(position, add, click_count, window, cx),
 3488            SelectPhase::BeginColumnar {
 3489                position,
 3490                goal_column,
 3491                reset,
 3492                mode,
 3493            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3494            SelectPhase::Extend {
 3495                position,
 3496                click_count,
 3497            } => self.extend_selection(position, click_count, window, cx),
 3498            SelectPhase::Update {
 3499                position,
 3500                goal_column,
 3501                scroll_delta,
 3502            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3503            SelectPhase::End => self.end_selection(window, cx),
 3504        }
 3505    }
 3506
 3507    fn extend_selection(
 3508        &mut self,
 3509        position: DisplayPoint,
 3510        click_count: usize,
 3511        window: &mut Window,
 3512        cx: &mut Context<Self>,
 3513    ) {
 3514        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3515        let tail = self.selections.newest::<usize>(cx).tail();
 3516        self.begin_selection(position, false, click_count, window, cx);
 3517
 3518        let position = position.to_offset(&display_map, Bias::Left);
 3519        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3520
 3521        let mut pending_selection = self
 3522            .selections
 3523            .pending_anchor()
 3524            .cloned()
 3525            .expect("extend_selection not called with pending selection");
 3526        if position >= tail {
 3527            pending_selection.start = tail_anchor;
 3528        } else {
 3529            pending_selection.end = tail_anchor;
 3530            pending_selection.reversed = true;
 3531        }
 3532
 3533        let mut pending_mode = self.selections.pending_mode().unwrap();
 3534        match &mut pending_mode {
 3535            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3536            _ => {}
 3537        }
 3538
 3539        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3540            SelectionEffects::scroll(Autoscroll::fit())
 3541        } else {
 3542            SelectionEffects::no_scroll()
 3543        };
 3544
 3545        self.change_selections(effects, window, cx, |s| {
 3546            s.set_pending(pending_selection.clone(), pending_mode)
 3547        });
 3548    }
 3549
 3550    fn begin_selection(
 3551        &mut self,
 3552        position: DisplayPoint,
 3553        add: bool,
 3554        click_count: usize,
 3555        window: &mut Window,
 3556        cx: &mut Context<Self>,
 3557    ) {
 3558        if !self.focus_handle.is_focused(window) {
 3559            self.last_focused_descendant = None;
 3560            window.focus(&self.focus_handle);
 3561        }
 3562
 3563        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3564        let buffer = &display_map.buffer_snapshot;
 3565        let position = display_map.clip_point(position, Bias::Left);
 3566
 3567        let start;
 3568        let end;
 3569        let mode;
 3570        let mut auto_scroll;
 3571        match click_count {
 3572            1 => {
 3573                start = buffer.anchor_before(position.to_point(&display_map));
 3574                end = start;
 3575                mode = SelectMode::Character;
 3576                auto_scroll = true;
 3577            }
 3578            2 => {
 3579                let position = display_map
 3580                    .clip_point(position, Bias::Left)
 3581                    .to_offset(&display_map, Bias::Left);
 3582                let (range, _) = buffer.surrounding_word(position, None);
 3583                start = buffer.anchor_before(range.start);
 3584                end = buffer.anchor_before(range.end);
 3585                mode = SelectMode::Word(start..end);
 3586                auto_scroll = true;
 3587            }
 3588            3 => {
 3589                let position = display_map
 3590                    .clip_point(position, Bias::Left)
 3591                    .to_point(&display_map);
 3592                let line_start = display_map.prev_line_boundary(position).0;
 3593                let next_line_start = buffer.clip_point(
 3594                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3595                    Bias::Left,
 3596                );
 3597                start = buffer.anchor_before(line_start);
 3598                end = buffer.anchor_before(next_line_start);
 3599                mode = SelectMode::Line(start..end);
 3600                auto_scroll = true;
 3601            }
 3602            _ => {
 3603                start = buffer.anchor_before(0);
 3604                end = buffer.anchor_before(buffer.len());
 3605                mode = SelectMode::All;
 3606                auto_scroll = false;
 3607            }
 3608        }
 3609        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3610
 3611        let point_to_delete: Option<usize> = {
 3612            let selected_points: Vec<Selection<Point>> =
 3613                self.selections.disjoint_in_range(start..end, cx);
 3614
 3615            if !add || click_count > 1 {
 3616                None
 3617            } else if !selected_points.is_empty() {
 3618                Some(selected_points[0].id)
 3619            } else {
 3620                let clicked_point_already_selected =
 3621                    self.selections.disjoint_anchors().iter().find(|selection| {
 3622                        selection.start.to_point(buffer) == start.to_point(buffer)
 3623                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3624                    });
 3625
 3626                clicked_point_already_selected.map(|selection| selection.id)
 3627            }
 3628        };
 3629
 3630        let selections_count = self.selections.count();
 3631        let effects = if auto_scroll {
 3632            SelectionEffects::default()
 3633        } else {
 3634            SelectionEffects::no_scroll()
 3635        };
 3636
 3637        self.change_selections(effects, window, cx, |s| {
 3638            if let Some(point_to_delete) = point_to_delete {
 3639                s.delete(point_to_delete);
 3640
 3641                if selections_count == 1 {
 3642                    s.set_pending_anchor_range(start..end, mode);
 3643                }
 3644            } else {
 3645                if !add {
 3646                    s.clear_disjoint();
 3647                }
 3648
 3649                s.set_pending_anchor_range(start..end, mode);
 3650            }
 3651        });
 3652    }
 3653
 3654    fn begin_columnar_selection(
 3655        &mut self,
 3656        position: DisplayPoint,
 3657        goal_column: u32,
 3658        reset: bool,
 3659        mode: ColumnarMode,
 3660        window: &mut Window,
 3661        cx: &mut Context<Self>,
 3662    ) {
 3663        if !self.focus_handle.is_focused(window) {
 3664            self.last_focused_descendant = None;
 3665            window.focus(&self.focus_handle);
 3666        }
 3667
 3668        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3669
 3670        if reset {
 3671            let pointer_position = display_map
 3672                .buffer_snapshot
 3673                .anchor_before(position.to_point(&display_map));
 3674
 3675            self.change_selections(
 3676                SelectionEffects::scroll(Autoscroll::newest()),
 3677                window,
 3678                cx,
 3679                |s| {
 3680                    s.clear_disjoint();
 3681                    s.set_pending_anchor_range(
 3682                        pointer_position..pointer_position,
 3683                        SelectMode::Character,
 3684                    );
 3685                },
 3686            );
 3687        };
 3688
 3689        let tail = self.selections.newest::<Point>(cx).tail();
 3690        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3691        self.columnar_selection_state = match mode {
 3692            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3693                selection_tail: selection_anchor,
 3694                display_point: if reset {
 3695                    if position.column() != goal_column {
 3696                        Some(DisplayPoint::new(position.row(), goal_column))
 3697                    } else {
 3698                        None
 3699                    }
 3700                } else {
 3701                    None
 3702                },
 3703            }),
 3704            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3705                selection_tail: selection_anchor,
 3706            }),
 3707        };
 3708
 3709        if !reset {
 3710            self.select_columns(position, goal_column, &display_map, window, cx);
 3711        }
 3712    }
 3713
 3714    fn update_selection(
 3715        &mut self,
 3716        position: DisplayPoint,
 3717        goal_column: u32,
 3718        scroll_delta: gpui::Point<f32>,
 3719        window: &mut Window,
 3720        cx: &mut Context<Self>,
 3721    ) {
 3722        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3723
 3724        if self.columnar_selection_state.is_some() {
 3725            self.select_columns(position, goal_column, &display_map, window, cx);
 3726        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3727            let buffer = &display_map.buffer_snapshot;
 3728            let head;
 3729            let tail;
 3730            let mode = self.selections.pending_mode().unwrap();
 3731            match &mode {
 3732                SelectMode::Character => {
 3733                    head = position.to_point(&display_map);
 3734                    tail = pending.tail().to_point(buffer);
 3735                }
 3736                SelectMode::Word(original_range) => {
 3737                    let offset = display_map
 3738                        .clip_point(position, Bias::Left)
 3739                        .to_offset(&display_map, Bias::Left);
 3740                    let original_range = original_range.to_offset(buffer);
 3741
 3742                    let head_offset = if buffer.is_inside_word(offset, None)
 3743                        || original_range.contains(&offset)
 3744                    {
 3745                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3746                        if word_range.start < original_range.start {
 3747                            word_range.start
 3748                        } else {
 3749                            word_range.end
 3750                        }
 3751                    } else {
 3752                        offset
 3753                    };
 3754
 3755                    head = head_offset.to_point(buffer);
 3756                    if head_offset <= original_range.start {
 3757                        tail = original_range.end.to_point(buffer);
 3758                    } else {
 3759                        tail = original_range.start.to_point(buffer);
 3760                    }
 3761                }
 3762                SelectMode::Line(original_range) => {
 3763                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3764
 3765                    let position = display_map
 3766                        .clip_point(position, Bias::Left)
 3767                        .to_point(&display_map);
 3768                    let line_start = display_map.prev_line_boundary(position).0;
 3769                    let next_line_start = buffer.clip_point(
 3770                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3771                        Bias::Left,
 3772                    );
 3773
 3774                    if line_start < original_range.start {
 3775                        head = line_start
 3776                    } else {
 3777                        head = next_line_start
 3778                    }
 3779
 3780                    if head <= original_range.start {
 3781                        tail = original_range.end;
 3782                    } else {
 3783                        tail = original_range.start;
 3784                    }
 3785                }
 3786                SelectMode::All => {
 3787                    return;
 3788                }
 3789            };
 3790
 3791            if head < tail {
 3792                pending.start = buffer.anchor_before(head);
 3793                pending.end = buffer.anchor_before(tail);
 3794                pending.reversed = true;
 3795            } else {
 3796                pending.start = buffer.anchor_before(tail);
 3797                pending.end = buffer.anchor_before(head);
 3798                pending.reversed = false;
 3799            }
 3800
 3801            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3802                s.set_pending(pending.clone(), mode);
 3803            });
 3804        } else {
 3805            log::error!("update_selection dispatched with no pending selection");
 3806            return;
 3807        }
 3808
 3809        self.apply_scroll_delta(scroll_delta, window, cx);
 3810        cx.notify();
 3811    }
 3812
 3813    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3814        self.columnar_selection_state.take();
 3815        if self.selections.pending_anchor().is_some() {
 3816            let selections = self.selections.all::<usize>(cx);
 3817            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3818                s.select(selections);
 3819                s.clear_pending();
 3820            });
 3821        }
 3822    }
 3823
 3824    fn select_columns(
 3825        &mut self,
 3826        head: DisplayPoint,
 3827        goal_column: u32,
 3828        display_map: &DisplaySnapshot,
 3829        window: &mut Window,
 3830        cx: &mut Context<Self>,
 3831    ) {
 3832        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3833            return;
 3834        };
 3835
 3836        let tail = match columnar_state {
 3837            ColumnarSelectionState::FromMouse {
 3838                selection_tail,
 3839                display_point,
 3840            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3841            ColumnarSelectionState::FromSelection { selection_tail } => {
 3842                selection_tail.to_display_point(display_map)
 3843            }
 3844        };
 3845
 3846        let start_row = cmp::min(tail.row(), head.row());
 3847        let end_row = cmp::max(tail.row(), head.row());
 3848        let start_column = cmp::min(tail.column(), goal_column);
 3849        let end_column = cmp::max(tail.column(), goal_column);
 3850        let reversed = start_column < tail.column();
 3851
 3852        let selection_ranges = (start_row.0..=end_row.0)
 3853            .map(DisplayRow)
 3854            .filter_map(|row| {
 3855                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3856                    || start_column <= display_map.line_len(row))
 3857                    && !display_map.is_block_line(row)
 3858                {
 3859                    let start = display_map
 3860                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3861                        .to_point(display_map);
 3862                    let end = display_map
 3863                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3864                        .to_point(display_map);
 3865                    if reversed {
 3866                        Some(end..start)
 3867                    } else {
 3868                        Some(start..end)
 3869                    }
 3870                } else {
 3871                    None
 3872                }
 3873            })
 3874            .collect::<Vec<_>>();
 3875
 3876        let ranges = match columnar_state {
 3877            ColumnarSelectionState::FromMouse { .. } => {
 3878                let mut non_empty_ranges = selection_ranges
 3879                    .iter()
 3880                    .filter(|selection_range| selection_range.start != selection_range.end)
 3881                    .peekable();
 3882                if non_empty_ranges.peek().is_some() {
 3883                    non_empty_ranges.cloned().collect()
 3884                } else {
 3885                    selection_ranges
 3886                }
 3887            }
 3888            _ => selection_ranges,
 3889        };
 3890
 3891        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3892            s.select_ranges(ranges);
 3893        });
 3894        cx.notify();
 3895    }
 3896
 3897    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3898        self.selections
 3899            .all_adjusted(cx)
 3900            .iter()
 3901            .any(|selection| !selection.is_empty())
 3902    }
 3903
 3904    pub fn has_pending_nonempty_selection(&self) -> bool {
 3905        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3906            Some(Selection { start, end, .. }) => start != end,
 3907            None => false,
 3908        };
 3909
 3910        pending_nonempty_selection
 3911            || (self.columnar_selection_state.is_some()
 3912                && self.selections.disjoint_anchors().len() > 1)
 3913    }
 3914
 3915    pub fn has_pending_selection(&self) -> bool {
 3916        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3917    }
 3918
 3919    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3920        self.selection_mark_mode = false;
 3921        self.selection_drag_state = SelectionDragState::None;
 3922
 3923        if self.clear_expanded_diff_hunks(cx) {
 3924            cx.notify();
 3925            return;
 3926        }
 3927        if self.dismiss_menus_and_popups(true, window, cx) {
 3928            return;
 3929        }
 3930
 3931        if self.mode.is_full()
 3932            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3933        {
 3934            return;
 3935        }
 3936
 3937        cx.propagate();
 3938    }
 3939
 3940    pub fn dismiss_menus_and_popups(
 3941        &mut self,
 3942        is_user_requested: bool,
 3943        window: &mut Window,
 3944        cx: &mut Context<Self>,
 3945    ) -> bool {
 3946        if self.take_rename(false, window, cx).is_some() {
 3947            return true;
 3948        }
 3949
 3950        if hide_hover(self, cx) {
 3951            return true;
 3952        }
 3953
 3954        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3955            return true;
 3956        }
 3957
 3958        if self.hide_context_menu(window, cx).is_some() {
 3959            return true;
 3960        }
 3961
 3962        if self.mouse_context_menu.take().is_some() {
 3963            return true;
 3964        }
 3965
 3966        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3967            return true;
 3968        }
 3969
 3970        if self.snippet_stack.pop().is_some() {
 3971            return true;
 3972        }
 3973
 3974        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3975            self.dismiss_diagnostics(cx);
 3976            return true;
 3977        }
 3978
 3979        false
 3980    }
 3981
 3982    fn linked_editing_ranges_for(
 3983        &self,
 3984        selection: Range<text::Anchor>,
 3985        cx: &App,
 3986    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3987        if self.linked_edit_ranges.is_empty() {
 3988            return None;
 3989        }
 3990        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3991            selection.end.buffer_id.and_then(|end_buffer_id| {
 3992                if selection.start.buffer_id != Some(end_buffer_id) {
 3993                    return None;
 3994                }
 3995                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3996                let snapshot = buffer.read(cx).snapshot();
 3997                self.linked_edit_ranges
 3998                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3999                    .map(|ranges| (ranges, snapshot, buffer))
 4000            })?;
 4001        use text::ToOffset as TO;
 4002        // find offset from the start of current range to current cursor position
 4003        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4004
 4005        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4006        let start_difference = start_offset - start_byte_offset;
 4007        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4008        let end_difference = end_offset - start_byte_offset;
 4009        // Current range has associated linked ranges.
 4010        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4011        for range in linked_ranges.iter() {
 4012            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4013            let end_offset = start_offset + end_difference;
 4014            let start_offset = start_offset + start_difference;
 4015            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4016                continue;
 4017            }
 4018            if self.selections.disjoint_anchor_ranges().any(|s| {
 4019                if s.start.buffer_id != selection.start.buffer_id
 4020                    || s.end.buffer_id != selection.end.buffer_id
 4021                {
 4022                    return false;
 4023                }
 4024                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4025                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4026            }) {
 4027                continue;
 4028            }
 4029            let start = buffer_snapshot.anchor_after(start_offset);
 4030            let end = buffer_snapshot.anchor_after(end_offset);
 4031            linked_edits
 4032                .entry(buffer.clone())
 4033                .or_default()
 4034                .push(start..end);
 4035        }
 4036        Some(linked_edits)
 4037    }
 4038
 4039    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4040        let text: Arc<str> = text.into();
 4041
 4042        if self.read_only(cx) {
 4043            return;
 4044        }
 4045
 4046        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4047
 4048        let selections = self.selections.all_adjusted(cx);
 4049        let mut bracket_inserted = false;
 4050        let mut edits = Vec::new();
 4051        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4052        let mut new_selections = Vec::with_capacity(selections.len());
 4053        let mut new_autoclose_regions = Vec::new();
 4054        let snapshot = self.buffer.read(cx).read(cx);
 4055        let mut clear_linked_edit_ranges = false;
 4056
 4057        for (selection, autoclose_region) in
 4058            self.selections_with_autoclose_regions(selections, &snapshot)
 4059        {
 4060            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4061                // Determine if the inserted text matches the opening or closing
 4062                // bracket of any of this language's bracket pairs.
 4063                let mut bracket_pair = None;
 4064                let mut is_bracket_pair_start = false;
 4065                let mut is_bracket_pair_end = false;
 4066                if !text.is_empty() {
 4067                    let mut bracket_pair_matching_end = None;
 4068                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4069                    //  and they are removing the character that triggered IME popup.
 4070                    for (pair, enabled) in scope.brackets() {
 4071                        if !pair.close && !pair.surround {
 4072                            continue;
 4073                        }
 4074
 4075                        if enabled && pair.start.ends_with(text.as_ref()) {
 4076                            let prefix_len = pair.start.len() - text.len();
 4077                            let preceding_text_matches_prefix = prefix_len == 0
 4078                                || (selection.start.column >= (prefix_len as u32)
 4079                                    && snapshot.contains_str_at(
 4080                                        Point::new(
 4081                                            selection.start.row,
 4082                                            selection.start.column - (prefix_len as u32),
 4083                                        ),
 4084                                        &pair.start[..prefix_len],
 4085                                    ));
 4086                            if preceding_text_matches_prefix {
 4087                                bracket_pair = Some(pair.clone());
 4088                                is_bracket_pair_start = true;
 4089                                break;
 4090                            }
 4091                        }
 4092                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4093                        {
 4094                            // take first bracket pair matching end, but don't break in case a later bracket
 4095                            // pair matches start
 4096                            bracket_pair_matching_end = Some(pair.clone());
 4097                        }
 4098                    }
 4099                    if let Some(end) = bracket_pair_matching_end
 4100                        && bracket_pair.is_none()
 4101                    {
 4102                        bracket_pair = Some(end);
 4103                        is_bracket_pair_end = true;
 4104                    }
 4105                }
 4106
 4107                if let Some(bracket_pair) = bracket_pair {
 4108                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4109                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4110                    let auto_surround =
 4111                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4112                    if selection.is_empty() {
 4113                        if is_bracket_pair_start {
 4114                            // If the inserted text is a suffix of an opening bracket and the
 4115                            // selection is preceded by the rest of the opening bracket, then
 4116                            // insert the closing bracket.
 4117                            let following_text_allows_autoclose = snapshot
 4118                                .chars_at(selection.start)
 4119                                .next()
 4120                                .is_none_or(|c| scope.should_autoclose_before(c));
 4121
 4122                            let preceding_text_allows_autoclose = selection.start.column == 0
 4123                                || snapshot
 4124                                    .reversed_chars_at(selection.start)
 4125                                    .next()
 4126                                    .is_none_or(|c| {
 4127                                        bracket_pair.start != bracket_pair.end
 4128                                            || !snapshot
 4129                                                .char_classifier_at(selection.start)
 4130                                                .is_word(c)
 4131                                    });
 4132
 4133                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4134                                && bracket_pair.start.len() == 1
 4135                            {
 4136                                let target = bracket_pair.start.chars().next().unwrap();
 4137                                let current_line_count = snapshot
 4138                                    .reversed_chars_at(selection.start)
 4139                                    .take_while(|&c| c != '\n')
 4140                                    .filter(|&c| c == target)
 4141                                    .count();
 4142                                current_line_count % 2 == 1
 4143                            } else {
 4144                                false
 4145                            };
 4146
 4147                            if autoclose
 4148                                && bracket_pair.close
 4149                                && following_text_allows_autoclose
 4150                                && preceding_text_allows_autoclose
 4151                                && !is_closing_quote
 4152                            {
 4153                                let anchor = snapshot.anchor_before(selection.end);
 4154                                new_selections.push((selection.map(|_| anchor), text.len()));
 4155                                new_autoclose_regions.push((
 4156                                    anchor,
 4157                                    text.len(),
 4158                                    selection.id,
 4159                                    bracket_pair.clone(),
 4160                                ));
 4161                                edits.push((
 4162                                    selection.range(),
 4163                                    format!("{}{}", text, bracket_pair.end).into(),
 4164                                ));
 4165                                bracket_inserted = true;
 4166                                continue;
 4167                            }
 4168                        }
 4169
 4170                        if let Some(region) = autoclose_region {
 4171                            // If the selection is followed by an auto-inserted closing bracket,
 4172                            // then don't insert that closing bracket again; just move the selection
 4173                            // past the closing bracket.
 4174                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4175                                && text.as_ref() == region.pair.end.as_str()
 4176                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4177                            if should_skip {
 4178                                let anchor = snapshot.anchor_after(selection.end);
 4179                                new_selections
 4180                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4181                                continue;
 4182                            }
 4183                        }
 4184
 4185                        let always_treat_brackets_as_autoclosed = snapshot
 4186                            .language_settings_at(selection.start, cx)
 4187                            .always_treat_brackets_as_autoclosed;
 4188                        if always_treat_brackets_as_autoclosed
 4189                            && is_bracket_pair_end
 4190                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4191                        {
 4192                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4193                            // and the inserted text is a closing bracket and the selection is followed
 4194                            // by the closing bracket then move the selection past the closing bracket.
 4195                            let anchor = snapshot.anchor_after(selection.end);
 4196                            new_selections.push((selection.map(|_| anchor), text.len()));
 4197                            continue;
 4198                        }
 4199                    }
 4200                    // If an opening bracket is 1 character long and is typed while
 4201                    // text is selected, then surround that text with the bracket pair.
 4202                    else if auto_surround
 4203                        && bracket_pair.surround
 4204                        && is_bracket_pair_start
 4205                        && bracket_pair.start.chars().count() == 1
 4206                    {
 4207                        edits.push((selection.start..selection.start, text.clone()));
 4208                        edits.push((
 4209                            selection.end..selection.end,
 4210                            bracket_pair.end.as_str().into(),
 4211                        ));
 4212                        bracket_inserted = true;
 4213                        new_selections.push((
 4214                            Selection {
 4215                                id: selection.id,
 4216                                start: snapshot.anchor_after(selection.start),
 4217                                end: snapshot.anchor_before(selection.end),
 4218                                reversed: selection.reversed,
 4219                                goal: selection.goal,
 4220                            },
 4221                            0,
 4222                        ));
 4223                        continue;
 4224                    }
 4225                }
 4226            }
 4227
 4228            if self.auto_replace_emoji_shortcode
 4229                && selection.is_empty()
 4230                && text.as_ref().ends_with(':')
 4231                && let Some(possible_emoji_short_code) =
 4232                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4233                && !possible_emoji_short_code.is_empty()
 4234                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4235            {
 4236                let emoji_shortcode_start = Point::new(
 4237                    selection.start.row,
 4238                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4239                );
 4240
 4241                // Remove shortcode from buffer
 4242                edits.push((
 4243                    emoji_shortcode_start..selection.start,
 4244                    "".to_string().into(),
 4245                ));
 4246                new_selections.push((
 4247                    Selection {
 4248                        id: selection.id,
 4249                        start: snapshot.anchor_after(emoji_shortcode_start),
 4250                        end: snapshot.anchor_before(selection.start),
 4251                        reversed: selection.reversed,
 4252                        goal: selection.goal,
 4253                    },
 4254                    0,
 4255                ));
 4256
 4257                // Insert emoji
 4258                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4259                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4260                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4261
 4262                continue;
 4263            }
 4264
 4265            // If not handling any auto-close operation, then just replace the selected
 4266            // text with the given input and move the selection to the end of the
 4267            // newly inserted text.
 4268            let anchor = snapshot.anchor_after(selection.end);
 4269            if !self.linked_edit_ranges.is_empty() {
 4270                let start_anchor = snapshot.anchor_before(selection.start);
 4271
 4272                let is_word_char = text.chars().next().is_none_or(|char| {
 4273                    let classifier = snapshot
 4274                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4275                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4276                    classifier.is_word(char)
 4277                });
 4278
 4279                if is_word_char {
 4280                    if let Some(ranges) = self
 4281                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4282                    {
 4283                        for (buffer, edits) in ranges {
 4284                            linked_edits
 4285                                .entry(buffer.clone())
 4286                                .or_default()
 4287                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4288                        }
 4289                    }
 4290                } else {
 4291                    clear_linked_edit_ranges = true;
 4292                }
 4293            }
 4294
 4295            new_selections.push((selection.map(|_| anchor), 0));
 4296            edits.push((selection.start..selection.end, text.clone()));
 4297        }
 4298
 4299        drop(snapshot);
 4300
 4301        self.transact(window, cx, |this, window, cx| {
 4302            if clear_linked_edit_ranges {
 4303                this.linked_edit_ranges.clear();
 4304            }
 4305            let initial_buffer_versions =
 4306                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4307
 4308            this.buffer.update(cx, |buffer, cx| {
 4309                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4310            });
 4311            for (buffer, edits) in linked_edits {
 4312                buffer.update(cx, |buffer, cx| {
 4313                    let snapshot = buffer.snapshot();
 4314                    let edits = edits
 4315                        .into_iter()
 4316                        .map(|(range, text)| {
 4317                            use text::ToPoint as TP;
 4318                            let end_point = TP::to_point(&range.end, &snapshot);
 4319                            let start_point = TP::to_point(&range.start, &snapshot);
 4320                            (start_point..end_point, text)
 4321                        })
 4322                        .sorted_by_key(|(range, _)| range.start);
 4323                    buffer.edit(edits, None, cx);
 4324                })
 4325            }
 4326            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4327            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4328            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4329            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4330                .zip(new_selection_deltas)
 4331                .map(|(selection, delta)| Selection {
 4332                    id: selection.id,
 4333                    start: selection.start + delta,
 4334                    end: selection.end + delta,
 4335                    reversed: selection.reversed,
 4336                    goal: SelectionGoal::None,
 4337                })
 4338                .collect::<Vec<_>>();
 4339
 4340            let mut i = 0;
 4341            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4342                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4343                let start = map.buffer_snapshot.anchor_before(position);
 4344                let end = map.buffer_snapshot.anchor_after(position);
 4345                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4346                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4347                        Ordering::Less => i += 1,
 4348                        Ordering::Greater => break,
 4349                        Ordering::Equal => {
 4350                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4351                                Ordering::Less => i += 1,
 4352                                Ordering::Equal => break,
 4353                                Ordering::Greater => break,
 4354                            }
 4355                        }
 4356                    }
 4357                }
 4358                this.autoclose_regions.insert(
 4359                    i,
 4360                    AutocloseRegion {
 4361                        selection_id,
 4362                        range: start..end,
 4363                        pair,
 4364                    },
 4365                );
 4366            }
 4367
 4368            let had_active_edit_prediction = this.has_active_edit_prediction();
 4369            this.change_selections(
 4370                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4371                window,
 4372                cx,
 4373                |s| s.select(new_selections),
 4374            );
 4375
 4376            if !bracket_inserted
 4377                && let Some(on_type_format_task) =
 4378                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4379            {
 4380                on_type_format_task.detach_and_log_err(cx);
 4381            }
 4382
 4383            let editor_settings = EditorSettings::get_global(cx);
 4384            if bracket_inserted
 4385                && (editor_settings.auto_signature_help
 4386                    || editor_settings.show_signature_help_after_edits)
 4387            {
 4388                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4389            }
 4390
 4391            let trigger_in_words =
 4392                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4393            if this.hard_wrap.is_some() {
 4394                let latest: Range<Point> = this.selections.newest(cx).range();
 4395                if latest.is_empty()
 4396                    && this
 4397                        .buffer()
 4398                        .read(cx)
 4399                        .snapshot(cx)
 4400                        .line_len(MultiBufferRow(latest.start.row))
 4401                        == latest.start.column
 4402                {
 4403                    this.rewrap_impl(
 4404                        RewrapOptions {
 4405                            override_language_settings: true,
 4406                            preserve_existing_whitespace: true,
 4407                        },
 4408                        cx,
 4409                    )
 4410                }
 4411            }
 4412            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4413            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4414            this.refresh_edit_prediction(true, false, window, cx);
 4415            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4416        });
 4417    }
 4418
 4419    fn find_possible_emoji_shortcode_at_position(
 4420        snapshot: &MultiBufferSnapshot,
 4421        position: Point,
 4422    ) -> Option<String> {
 4423        let mut chars = Vec::new();
 4424        let mut found_colon = false;
 4425        for char in snapshot.reversed_chars_at(position).take(100) {
 4426            // Found a possible emoji shortcode in the middle of the buffer
 4427            if found_colon {
 4428                if char.is_whitespace() {
 4429                    chars.reverse();
 4430                    return Some(chars.iter().collect());
 4431                }
 4432                // If the previous character is not a whitespace, we are in the middle of a word
 4433                // and we only want to complete the shortcode if the word is made up of other emojis
 4434                let mut containing_word = String::new();
 4435                for ch in snapshot
 4436                    .reversed_chars_at(position)
 4437                    .skip(chars.len() + 1)
 4438                    .take(100)
 4439                {
 4440                    if ch.is_whitespace() {
 4441                        break;
 4442                    }
 4443                    containing_word.push(ch);
 4444                }
 4445                let containing_word = containing_word.chars().rev().collect::<String>();
 4446                if util::word_consists_of_emojis(containing_word.as_str()) {
 4447                    chars.reverse();
 4448                    return Some(chars.iter().collect());
 4449                }
 4450            }
 4451
 4452            if char.is_whitespace() || !char.is_ascii() {
 4453                return None;
 4454            }
 4455            if char == ':' {
 4456                found_colon = true;
 4457            } else {
 4458                chars.push(char);
 4459            }
 4460        }
 4461        // Found a possible emoji shortcode at the beginning of the buffer
 4462        chars.reverse();
 4463        Some(chars.iter().collect())
 4464    }
 4465
 4466    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4467        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4468        self.transact(window, cx, |this, window, cx| {
 4469            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4470                let selections = this.selections.all::<usize>(cx);
 4471                let multi_buffer = this.buffer.read(cx);
 4472                let buffer = multi_buffer.snapshot(cx);
 4473                selections
 4474                    .iter()
 4475                    .map(|selection| {
 4476                        let start_point = selection.start.to_point(&buffer);
 4477                        let mut existing_indent =
 4478                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4479                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4480                        let start = selection.start;
 4481                        let end = selection.end;
 4482                        let selection_is_empty = start == end;
 4483                        let language_scope = buffer.language_scope_at(start);
 4484                        let (
 4485                            comment_delimiter,
 4486                            doc_delimiter,
 4487                            insert_extra_newline,
 4488                            indent_on_newline,
 4489                            indent_on_extra_newline,
 4490                        ) = if let Some(language) = &language_scope {
 4491                            let mut insert_extra_newline =
 4492                                insert_extra_newline_brackets(&buffer, start..end, language)
 4493                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4494
 4495                            // Comment extension on newline is allowed only for cursor selections
 4496                            let comment_delimiter = maybe!({
 4497                                if !selection_is_empty {
 4498                                    return None;
 4499                                }
 4500
 4501                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4502                                    return None;
 4503                                }
 4504
 4505                                let delimiters = language.line_comment_prefixes();
 4506                                let max_len_of_delimiter =
 4507                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4508                                let (snapshot, range) =
 4509                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4510
 4511                                let num_of_whitespaces = snapshot
 4512                                    .chars_for_range(range.clone())
 4513                                    .take_while(|c| c.is_whitespace())
 4514                                    .count();
 4515                                let comment_candidate = snapshot
 4516                                    .chars_for_range(range.clone())
 4517                                    .skip(num_of_whitespaces)
 4518                                    .take(max_len_of_delimiter)
 4519                                    .collect::<String>();
 4520                                let (delimiter, trimmed_len) = delimiters
 4521                                    .iter()
 4522                                    .filter_map(|delimiter| {
 4523                                        let prefix = delimiter.trim_end();
 4524                                        if comment_candidate.starts_with(prefix) {
 4525                                            Some((delimiter, prefix.len()))
 4526                                        } else {
 4527                                            None
 4528                                        }
 4529                                    })
 4530                                    .max_by_key(|(_, len)| *len)?;
 4531
 4532                                if let Some(BlockCommentConfig {
 4533                                    start: block_start, ..
 4534                                }) = language.block_comment()
 4535                                {
 4536                                    let block_start_trimmed = block_start.trim_end();
 4537                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4538                                        let line_content = snapshot
 4539                                            .chars_for_range(range)
 4540                                            .skip(num_of_whitespaces)
 4541                                            .take(block_start_trimmed.len())
 4542                                            .collect::<String>();
 4543
 4544                                        if line_content.starts_with(block_start_trimmed) {
 4545                                            return None;
 4546                                        }
 4547                                    }
 4548                                }
 4549
 4550                                let cursor_is_placed_after_comment_marker =
 4551                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4552                                if cursor_is_placed_after_comment_marker {
 4553                                    Some(delimiter.clone())
 4554                                } else {
 4555                                    None
 4556                                }
 4557                            });
 4558
 4559                            let mut indent_on_newline = IndentSize::spaces(0);
 4560                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4561
 4562                            let doc_delimiter = maybe!({
 4563                                if !selection_is_empty {
 4564                                    return None;
 4565                                }
 4566
 4567                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4568                                    return None;
 4569                                }
 4570
 4571                                let BlockCommentConfig {
 4572                                    start: start_tag,
 4573                                    end: end_tag,
 4574                                    prefix: delimiter,
 4575                                    tab_size: len,
 4576                                } = language.documentation_comment()?;
 4577                                let is_within_block_comment = buffer
 4578                                    .language_scope_at(start_point)
 4579                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4580                                if !is_within_block_comment {
 4581                                    return None;
 4582                                }
 4583
 4584                                let (snapshot, range) =
 4585                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4586
 4587                                let num_of_whitespaces = snapshot
 4588                                    .chars_for_range(range.clone())
 4589                                    .take_while(|c| c.is_whitespace())
 4590                                    .count();
 4591
 4592                                // 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.
 4593                                let column = start_point.column;
 4594                                let cursor_is_after_start_tag = {
 4595                                    let start_tag_len = start_tag.len();
 4596                                    let start_tag_line = snapshot
 4597                                        .chars_for_range(range.clone())
 4598                                        .skip(num_of_whitespaces)
 4599                                        .take(start_tag_len)
 4600                                        .collect::<String>();
 4601                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4602                                        num_of_whitespaces + start_tag_len <= column as usize
 4603                                    } else {
 4604                                        false
 4605                                    }
 4606                                };
 4607
 4608                                let cursor_is_after_delimiter = {
 4609                                    let delimiter_trim = delimiter.trim_end();
 4610                                    let delimiter_line = snapshot
 4611                                        .chars_for_range(range.clone())
 4612                                        .skip(num_of_whitespaces)
 4613                                        .take(delimiter_trim.len())
 4614                                        .collect::<String>();
 4615                                    if delimiter_line.starts_with(delimiter_trim) {
 4616                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4617                                    } else {
 4618                                        false
 4619                                    }
 4620                                };
 4621
 4622                                let cursor_is_before_end_tag_if_exists = {
 4623                                    let mut char_position = 0u32;
 4624                                    let mut end_tag_offset = None;
 4625
 4626                                    'outer: for chunk in snapshot.text_for_range(range) {
 4627                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4628                                            let chars_before_match =
 4629                                                chunk[..byte_pos].chars().count() as u32;
 4630                                            end_tag_offset =
 4631                                                Some(char_position + chars_before_match);
 4632                                            break 'outer;
 4633                                        }
 4634                                        char_position += chunk.chars().count() as u32;
 4635                                    }
 4636
 4637                                    if let Some(end_tag_offset) = end_tag_offset {
 4638                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4639                                        if cursor_is_after_start_tag {
 4640                                            if cursor_is_before_end_tag {
 4641                                                insert_extra_newline = true;
 4642                                            }
 4643                                            let cursor_is_at_start_of_end_tag =
 4644                                                column == end_tag_offset;
 4645                                            if cursor_is_at_start_of_end_tag {
 4646                                                indent_on_extra_newline.len = *len;
 4647                                            }
 4648                                        }
 4649                                        cursor_is_before_end_tag
 4650                                    } else {
 4651                                        true
 4652                                    }
 4653                                };
 4654
 4655                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4656                                    && cursor_is_before_end_tag_if_exists
 4657                                {
 4658                                    if cursor_is_after_start_tag {
 4659                                        indent_on_newline.len = *len;
 4660                                    }
 4661                                    Some(delimiter.clone())
 4662                                } else {
 4663                                    None
 4664                                }
 4665                            });
 4666
 4667                            (
 4668                                comment_delimiter,
 4669                                doc_delimiter,
 4670                                insert_extra_newline,
 4671                                indent_on_newline,
 4672                                indent_on_extra_newline,
 4673                            )
 4674                        } else {
 4675                            (
 4676                                None,
 4677                                None,
 4678                                false,
 4679                                IndentSize::default(),
 4680                                IndentSize::default(),
 4681                            )
 4682                        };
 4683
 4684                        let prevent_auto_indent = doc_delimiter.is_some();
 4685                        let delimiter = comment_delimiter.or(doc_delimiter);
 4686
 4687                        let capacity_for_delimiter =
 4688                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4689                        let mut new_text = String::with_capacity(
 4690                            1 + capacity_for_delimiter
 4691                                + existing_indent.len as usize
 4692                                + indent_on_newline.len as usize
 4693                                + indent_on_extra_newline.len as usize,
 4694                        );
 4695                        new_text.push('\n');
 4696                        new_text.extend(existing_indent.chars());
 4697                        new_text.extend(indent_on_newline.chars());
 4698
 4699                        if let Some(delimiter) = &delimiter {
 4700                            new_text.push_str(delimiter);
 4701                        }
 4702
 4703                        if insert_extra_newline {
 4704                            new_text.push('\n');
 4705                            new_text.extend(existing_indent.chars());
 4706                            new_text.extend(indent_on_extra_newline.chars());
 4707                        }
 4708
 4709                        let anchor = buffer.anchor_after(end);
 4710                        let new_selection = selection.map(|_| anchor);
 4711                        (
 4712                            ((start..end, new_text), prevent_auto_indent),
 4713                            (insert_extra_newline, new_selection),
 4714                        )
 4715                    })
 4716                    .unzip()
 4717            };
 4718
 4719            let mut auto_indent_edits = Vec::new();
 4720            let mut edits = Vec::new();
 4721            for (edit, prevent_auto_indent) in edits_with_flags {
 4722                if prevent_auto_indent {
 4723                    edits.push(edit);
 4724                } else {
 4725                    auto_indent_edits.push(edit);
 4726                }
 4727            }
 4728            if !edits.is_empty() {
 4729                this.edit(edits, cx);
 4730            }
 4731            if !auto_indent_edits.is_empty() {
 4732                this.edit_with_autoindent(auto_indent_edits, cx);
 4733            }
 4734
 4735            let buffer = this.buffer.read(cx).snapshot(cx);
 4736            let new_selections = selection_info
 4737                .into_iter()
 4738                .map(|(extra_newline_inserted, new_selection)| {
 4739                    let mut cursor = new_selection.end.to_point(&buffer);
 4740                    if extra_newline_inserted {
 4741                        cursor.row -= 1;
 4742                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4743                    }
 4744                    new_selection.map(|_| cursor)
 4745                })
 4746                .collect();
 4747
 4748            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4749            this.refresh_edit_prediction(true, false, window, cx);
 4750        });
 4751    }
 4752
 4753    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4754        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4755
 4756        let buffer = self.buffer.read(cx);
 4757        let snapshot = buffer.snapshot(cx);
 4758
 4759        let mut edits = Vec::new();
 4760        let mut rows = Vec::new();
 4761
 4762        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4763            let cursor = selection.head();
 4764            let row = cursor.row;
 4765
 4766            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4767
 4768            let newline = "\n".to_string();
 4769            edits.push((start_of_line..start_of_line, newline));
 4770
 4771            rows.push(row + rows_inserted as u32);
 4772        }
 4773
 4774        self.transact(window, cx, |editor, window, cx| {
 4775            editor.edit(edits, cx);
 4776
 4777            editor.change_selections(Default::default(), window, cx, |s| {
 4778                let mut index = 0;
 4779                s.move_cursors_with(|map, _, _| {
 4780                    let row = rows[index];
 4781                    index += 1;
 4782
 4783                    let point = Point::new(row, 0);
 4784                    let boundary = map.next_line_boundary(point).1;
 4785                    let clipped = map.clip_point(boundary, Bias::Left);
 4786
 4787                    (clipped, SelectionGoal::None)
 4788                });
 4789            });
 4790
 4791            let mut indent_edits = Vec::new();
 4792            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4793            for row in rows {
 4794                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4795                for (row, indent) in indents {
 4796                    if indent.len == 0 {
 4797                        continue;
 4798                    }
 4799
 4800                    let text = match indent.kind {
 4801                        IndentKind::Space => " ".repeat(indent.len as usize),
 4802                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4803                    };
 4804                    let point = Point::new(row.0, 0);
 4805                    indent_edits.push((point..point, text));
 4806                }
 4807            }
 4808            editor.edit(indent_edits, cx);
 4809        });
 4810    }
 4811
 4812    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4813        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4814
 4815        let buffer = self.buffer.read(cx);
 4816        let snapshot = buffer.snapshot(cx);
 4817
 4818        let mut edits = Vec::new();
 4819        let mut rows = Vec::new();
 4820        let mut rows_inserted = 0;
 4821
 4822        for selection in self.selections.all_adjusted(cx) {
 4823            let cursor = selection.head();
 4824            let row = cursor.row;
 4825
 4826            let point = Point::new(row + 1, 0);
 4827            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4828
 4829            let newline = "\n".to_string();
 4830            edits.push((start_of_line..start_of_line, newline));
 4831
 4832            rows_inserted += 1;
 4833            rows.push(row + rows_inserted);
 4834        }
 4835
 4836        self.transact(window, cx, |editor, window, cx| {
 4837            editor.edit(edits, cx);
 4838
 4839            editor.change_selections(Default::default(), window, cx, |s| {
 4840                let mut index = 0;
 4841                s.move_cursors_with(|map, _, _| {
 4842                    let row = rows[index];
 4843                    index += 1;
 4844
 4845                    let point = Point::new(row, 0);
 4846                    let boundary = map.next_line_boundary(point).1;
 4847                    let clipped = map.clip_point(boundary, Bias::Left);
 4848
 4849                    (clipped, SelectionGoal::None)
 4850                });
 4851            });
 4852
 4853            let mut indent_edits = Vec::new();
 4854            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4855            for row in rows {
 4856                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4857                for (row, indent) in indents {
 4858                    if indent.len == 0 {
 4859                        continue;
 4860                    }
 4861
 4862                    let text = match indent.kind {
 4863                        IndentKind::Space => " ".repeat(indent.len as usize),
 4864                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4865                    };
 4866                    let point = Point::new(row.0, 0);
 4867                    indent_edits.push((point..point, text));
 4868                }
 4869            }
 4870            editor.edit(indent_edits, cx);
 4871        });
 4872    }
 4873
 4874    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4875        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4876            original_indent_columns: Vec::new(),
 4877        });
 4878        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4879    }
 4880
 4881    fn insert_with_autoindent_mode(
 4882        &mut self,
 4883        text: &str,
 4884        autoindent_mode: Option<AutoindentMode>,
 4885        window: &mut Window,
 4886        cx: &mut Context<Self>,
 4887    ) {
 4888        if self.read_only(cx) {
 4889            return;
 4890        }
 4891
 4892        let text: Arc<str> = text.into();
 4893        self.transact(window, cx, |this, window, cx| {
 4894            let old_selections = this.selections.all_adjusted(cx);
 4895            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4896                let anchors = {
 4897                    let snapshot = buffer.read(cx);
 4898                    old_selections
 4899                        .iter()
 4900                        .map(|s| {
 4901                            let anchor = snapshot.anchor_after(s.head());
 4902                            s.map(|_| anchor)
 4903                        })
 4904                        .collect::<Vec<_>>()
 4905                };
 4906                buffer.edit(
 4907                    old_selections
 4908                        .iter()
 4909                        .map(|s| (s.start..s.end, text.clone())),
 4910                    autoindent_mode,
 4911                    cx,
 4912                );
 4913                anchors
 4914            });
 4915
 4916            this.change_selections(Default::default(), window, cx, |s| {
 4917                s.select_anchors(selection_anchors);
 4918            });
 4919
 4920            cx.notify();
 4921        });
 4922    }
 4923
 4924    fn trigger_completion_on_input(
 4925        &mut self,
 4926        text: &str,
 4927        trigger_in_words: bool,
 4928        window: &mut Window,
 4929        cx: &mut Context<Self>,
 4930    ) {
 4931        let completions_source = self
 4932            .context_menu
 4933            .borrow()
 4934            .as_ref()
 4935            .and_then(|menu| match menu {
 4936                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4937                CodeContextMenu::CodeActions(_) => None,
 4938            });
 4939
 4940        match completions_source {
 4941            Some(CompletionsMenuSource::Words { .. }) => {
 4942                self.open_or_update_completions_menu(
 4943                    Some(CompletionsMenuSource::Words {
 4944                        ignore_threshold: false,
 4945                    }),
 4946                    None,
 4947                    window,
 4948                    cx,
 4949                );
 4950            }
 4951            Some(CompletionsMenuSource::Normal)
 4952            | Some(CompletionsMenuSource::SnippetChoices)
 4953            | None
 4954                if self.is_completion_trigger(
 4955                    text,
 4956                    trigger_in_words,
 4957                    completions_source.is_some(),
 4958                    cx,
 4959                ) =>
 4960            {
 4961                self.show_completions(
 4962                    &ShowCompletions {
 4963                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4964                    },
 4965                    window,
 4966                    cx,
 4967                )
 4968            }
 4969            _ => {
 4970                self.hide_context_menu(window, cx);
 4971            }
 4972        }
 4973    }
 4974
 4975    fn is_completion_trigger(
 4976        &self,
 4977        text: &str,
 4978        trigger_in_words: bool,
 4979        menu_is_open: bool,
 4980        cx: &mut Context<Self>,
 4981    ) -> bool {
 4982        let position = self.selections.newest_anchor().head();
 4983        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4984            return false;
 4985        };
 4986
 4987        if let Some(completion_provider) = &self.completion_provider {
 4988            completion_provider.is_completion_trigger(
 4989                &buffer,
 4990                position.text_anchor,
 4991                text,
 4992                trigger_in_words,
 4993                menu_is_open,
 4994                cx,
 4995            )
 4996        } else {
 4997            false
 4998        }
 4999    }
 5000
 5001    /// If any empty selections is touching the start of its innermost containing autoclose
 5002    /// region, expand it to select the brackets.
 5003    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5004        let selections = self.selections.all::<usize>(cx);
 5005        let buffer = self.buffer.read(cx).read(cx);
 5006        let new_selections = self
 5007            .selections_with_autoclose_regions(selections, &buffer)
 5008            .map(|(mut selection, region)| {
 5009                if !selection.is_empty() {
 5010                    return selection;
 5011                }
 5012
 5013                if let Some(region) = region {
 5014                    let mut range = region.range.to_offset(&buffer);
 5015                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5016                        range.start -= region.pair.start.len();
 5017                        if buffer.contains_str_at(range.start, &region.pair.start)
 5018                            && buffer.contains_str_at(range.end, &region.pair.end)
 5019                        {
 5020                            range.end += region.pair.end.len();
 5021                            selection.start = range.start;
 5022                            selection.end = range.end;
 5023
 5024                            return selection;
 5025                        }
 5026                    }
 5027                }
 5028
 5029                let always_treat_brackets_as_autoclosed = buffer
 5030                    .language_settings_at(selection.start, cx)
 5031                    .always_treat_brackets_as_autoclosed;
 5032
 5033                if !always_treat_brackets_as_autoclosed {
 5034                    return selection;
 5035                }
 5036
 5037                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5038                    for (pair, enabled) in scope.brackets() {
 5039                        if !enabled || !pair.close {
 5040                            continue;
 5041                        }
 5042
 5043                        if buffer.contains_str_at(selection.start, &pair.end) {
 5044                            let pair_start_len = pair.start.len();
 5045                            if buffer.contains_str_at(
 5046                                selection.start.saturating_sub(pair_start_len),
 5047                                &pair.start,
 5048                            ) {
 5049                                selection.start -= pair_start_len;
 5050                                selection.end += pair.end.len();
 5051
 5052                                return selection;
 5053                            }
 5054                        }
 5055                    }
 5056                }
 5057
 5058                selection
 5059            })
 5060            .collect();
 5061
 5062        drop(buffer);
 5063        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5064            selections.select(new_selections)
 5065        });
 5066    }
 5067
 5068    /// Iterate the given selections, and for each one, find the smallest surrounding
 5069    /// autoclose region. This uses the ordering of the selections and the autoclose
 5070    /// regions to avoid repeated comparisons.
 5071    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5072        &'a self,
 5073        selections: impl IntoIterator<Item = Selection<D>>,
 5074        buffer: &'a MultiBufferSnapshot,
 5075    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5076        let mut i = 0;
 5077        let mut regions = self.autoclose_regions.as_slice();
 5078        selections.into_iter().map(move |selection| {
 5079            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5080
 5081            let mut enclosing = None;
 5082            while let Some(pair_state) = regions.get(i) {
 5083                if pair_state.range.end.to_offset(buffer) < range.start {
 5084                    regions = &regions[i + 1..];
 5085                    i = 0;
 5086                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5087                    break;
 5088                } else {
 5089                    if pair_state.selection_id == selection.id {
 5090                        enclosing = Some(pair_state);
 5091                    }
 5092                    i += 1;
 5093                }
 5094            }
 5095
 5096            (selection, enclosing)
 5097        })
 5098    }
 5099
 5100    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5101    fn invalidate_autoclose_regions(
 5102        &mut self,
 5103        mut selections: &[Selection<Anchor>],
 5104        buffer: &MultiBufferSnapshot,
 5105    ) {
 5106        self.autoclose_regions.retain(|state| {
 5107            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5108                return false;
 5109            }
 5110
 5111            let mut i = 0;
 5112            while let Some(selection) = selections.get(i) {
 5113                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5114                    selections = &selections[1..];
 5115                    continue;
 5116                }
 5117                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5118                    break;
 5119                }
 5120                if selection.id == state.selection_id {
 5121                    return true;
 5122                } else {
 5123                    i += 1;
 5124                }
 5125            }
 5126            false
 5127        });
 5128    }
 5129
 5130    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5131        let offset = position.to_offset(buffer);
 5132        let (word_range, kind) =
 5133            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5134        if offset > word_range.start && kind == Some(CharKind::Word) {
 5135            Some(
 5136                buffer
 5137                    .text_for_range(word_range.start..offset)
 5138                    .collect::<String>(),
 5139            )
 5140        } else {
 5141            None
 5142        }
 5143    }
 5144
 5145    pub fn toggle_inline_values(
 5146        &mut self,
 5147        _: &ToggleInlineValues,
 5148        _: &mut Window,
 5149        cx: &mut Context<Self>,
 5150    ) {
 5151        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5152
 5153        self.refresh_inline_values(cx);
 5154    }
 5155
 5156    pub fn toggle_inlay_hints(
 5157        &mut self,
 5158        _: &ToggleInlayHints,
 5159        _: &mut Window,
 5160        cx: &mut Context<Self>,
 5161    ) {
 5162        self.refresh_inlay_hints(
 5163            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5164            cx,
 5165        );
 5166    }
 5167
 5168    pub fn inlay_hints_enabled(&self) -> bool {
 5169        self.inlay_hint_cache.enabled
 5170    }
 5171
 5172    pub fn inline_values_enabled(&self) -> bool {
 5173        self.inline_value_cache.enabled
 5174    }
 5175
 5176    #[cfg(any(test, feature = "test-support"))]
 5177    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5178        self.display_map
 5179            .read(cx)
 5180            .current_inlays()
 5181            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5182            .cloned()
 5183            .collect()
 5184    }
 5185
 5186    #[cfg(any(test, feature = "test-support"))]
 5187    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5188        self.display_map
 5189            .read(cx)
 5190            .current_inlays()
 5191            .cloned()
 5192            .collect()
 5193    }
 5194
 5195    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5196        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5197            return;
 5198        }
 5199
 5200        let reason_description = reason.description();
 5201        let ignore_debounce = matches!(
 5202            reason,
 5203            InlayHintRefreshReason::SettingsChange(_)
 5204                | InlayHintRefreshReason::Toggle(_)
 5205                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5206                | InlayHintRefreshReason::ModifiersChanged(_)
 5207        );
 5208        let (invalidate_cache, required_languages) = match reason {
 5209            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5210                match self.inlay_hint_cache.modifiers_override(enabled) {
 5211                    Some(enabled) => {
 5212                        if enabled {
 5213                            (InvalidationStrategy::RefreshRequested, None)
 5214                        } else {
 5215                            self.splice_inlays(
 5216                                &self
 5217                                    .visible_inlay_hints(cx)
 5218                                    .iter()
 5219                                    .map(|inlay| inlay.id)
 5220                                    .collect::<Vec<InlayId>>(),
 5221                                Vec::new(),
 5222                                cx,
 5223                            );
 5224                            return;
 5225                        }
 5226                    }
 5227                    None => return,
 5228                }
 5229            }
 5230            InlayHintRefreshReason::Toggle(enabled) => {
 5231                if self.inlay_hint_cache.toggle(enabled) {
 5232                    if enabled {
 5233                        (InvalidationStrategy::RefreshRequested, None)
 5234                    } else {
 5235                        self.splice_inlays(
 5236                            &self
 5237                                .visible_inlay_hints(cx)
 5238                                .iter()
 5239                                .map(|inlay| inlay.id)
 5240                                .collect::<Vec<InlayId>>(),
 5241                            Vec::new(),
 5242                            cx,
 5243                        );
 5244                        return;
 5245                    }
 5246                } else {
 5247                    return;
 5248                }
 5249            }
 5250            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5251                match self.inlay_hint_cache.update_settings(
 5252                    &self.buffer,
 5253                    new_settings,
 5254                    self.visible_inlay_hints(cx),
 5255                    cx,
 5256                ) {
 5257                    ControlFlow::Break(Some(InlaySplice {
 5258                        to_remove,
 5259                        to_insert,
 5260                    })) => {
 5261                        self.splice_inlays(&to_remove, to_insert, cx);
 5262                        return;
 5263                    }
 5264                    ControlFlow::Break(None) => return,
 5265                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5266                }
 5267            }
 5268            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5269                if let Some(InlaySplice {
 5270                    to_remove,
 5271                    to_insert,
 5272                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5273                {
 5274                    self.splice_inlays(&to_remove, to_insert, cx);
 5275                }
 5276                self.display_map.update(cx, |display_map, _| {
 5277                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5278                });
 5279                return;
 5280            }
 5281            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5282            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5283                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5284            }
 5285            InlayHintRefreshReason::RefreshRequested => {
 5286                (InvalidationStrategy::RefreshRequested, None)
 5287            }
 5288        };
 5289
 5290        if let Some(InlaySplice {
 5291            to_remove,
 5292            to_insert,
 5293        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5294            reason_description,
 5295            self.visible_excerpts(required_languages.as_ref(), cx),
 5296            invalidate_cache,
 5297            ignore_debounce,
 5298            cx,
 5299        ) {
 5300            self.splice_inlays(&to_remove, to_insert, cx);
 5301        }
 5302    }
 5303
 5304    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5305        self.display_map
 5306            .read(cx)
 5307            .current_inlays()
 5308            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5309            .cloned()
 5310            .collect()
 5311    }
 5312
 5313    pub fn visible_excerpts(
 5314        &self,
 5315        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5316        cx: &mut Context<Editor>,
 5317    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5318        let Some(project) = self.project() else {
 5319            return HashMap::default();
 5320        };
 5321        let project = project.read(cx);
 5322        let multi_buffer = self.buffer().read(cx);
 5323        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5324        let multi_buffer_visible_start = self
 5325            .scroll_manager
 5326            .anchor()
 5327            .anchor
 5328            .to_point(&multi_buffer_snapshot);
 5329        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5330            multi_buffer_visible_start
 5331                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5332            Bias::Left,
 5333        );
 5334        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5335        multi_buffer_snapshot
 5336            .range_to_buffer_ranges(multi_buffer_visible_range)
 5337            .into_iter()
 5338            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5339            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5340                let buffer_file = project::File::from_dyn(buffer.file())?;
 5341                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5342                let worktree_entry = buffer_worktree
 5343                    .read(cx)
 5344                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5345                if worktree_entry.is_ignored {
 5346                    return None;
 5347                }
 5348
 5349                let language = buffer.language()?;
 5350                if let Some(restrict_to_languages) = restrict_to_languages
 5351                    && !restrict_to_languages.contains(language)
 5352                {
 5353                    return None;
 5354                }
 5355                Some((
 5356                    excerpt_id,
 5357                    (
 5358                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5359                        buffer.version().clone(),
 5360                        excerpt_visible_range,
 5361                    ),
 5362                ))
 5363            })
 5364            .collect()
 5365    }
 5366
 5367    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5368        TextLayoutDetails {
 5369            text_system: window.text_system().clone(),
 5370            editor_style: self.style.clone().unwrap(),
 5371            rem_size: window.rem_size(),
 5372            scroll_anchor: self.scroll_manager.anchor(),
 5373            visible_rows: self.visible_line_count(),
 5374            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5375        }
 5376    }
 5377
 5378    pub fn splice_inlays(
 5379        &self,
 5380        to_remove: &[InlayId],
 5381        to_insert: Vec<Inlay>,
 5382        cx: &mut Context<Self>,
 5383    ) {
 5384        self.display_map.update(cx, |display_map, cx| {
 5385            display_map.splice_inlays(to_remove, to_insert, cx)
 5386        });
 5387        cx.notify();
 5388    }
 5389
 5390    fn trigger_on_type_formatting(
 5391        &self,
 5392        input: String,
 5393        window: &mut Window,
 5394        cx: &mut Context<Self>,
 5395    ) -> Option<Task<Result<()>>> {
 5396        if input.len() != 1 {
 5397            return None;
 5398        }
 5399
 5400        let project = self.project()?;
 5401        let position = self.selections.newest_anchor().head();
 5402        let (buffer, buffer_position) = self
 5403            .buffer
 5404            .read(cx)
 5405            .text_anchor_for_position(position, cx)?;
 5406
 5407        let settings = language_settings::language_settings(
 5408            buffer
 5409                .read(cx)
 5410                .language_at(buffer_position)
 5411                .map(|l| l.name()),
 5412            buffer.read(cx).file(),
 5413            cx,
 5414        );
 5415        if !settings.use_on_type_format {
 5416            return None;
 5417        }
 5418
 5419        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5420        // hence we do LSP request & edit on host side only — add formats to host's history.
 5421        let push_to_lsp_host_history = true;
 5422        // If this is not the host, append its history with new edits.
 5423        let push_to_client_history = project.read(cx).is_via_collab();
 5424
 5425        let on_type_formatting = project.update(cx, |project, cx| {
 5426            project.on_type_format(
 5427                buffer.clone(),
 5428                buffer_position,
 5429                input,
 5430                push_to_lsp_host_history,
 5431                cx,
 5432            )
 5433        });
 5434        Some(cx.spawn_in(window, async move |editor, cx| {
 5435            if let Some(transaction) = on_type_formatting.await? {
 5436                if push_to_client_history {
 5437                    buffer
 5438                        .update(cx, |buffer, _| {
 5439                            buffer.push_transaction(transaction, Instant::now());
 5440                            buffer.finalize_last_transaction();
 5441                        })
 5442                        .ok();
 5443                }
 5444                editor.update(cx, |editor, cx| {
 5445                    editor.refresh_document_highlights(cx);
 5446                })?;
 5447            }
 5448            Ok(())
 5449        }))
 5450    }
 5451
 5452    pub fn show_word_completions(
 5453        &mut self,
 5454        _: &ShowWordCompletions,
 5455        window: &mut Window,
 5456        cx: &mut Context<Self>,
 5457    ) {
 5458        self.open_or_update_completions_menu(
 5459            Some(CompletionsMenuSource::Words {
 5460                ignore_threshold: true,
 5461            }),
 5462            None,
 5463            window,
 5464            cx,
 5465        );
 5466    }
 5467
 5468    pub fn show_completions(
 5469        &mut self,
 5470        options: &ShowCompletions,
 5471        window: &mut Window,
 5472        cx: &mut Context<Self>,
 5473    ) {
 5474        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5475    }
 5476
 5477    fn open_or_update_completions_menu(
 5478        &mut self,
 5479        requested_source: Option<CompletionsMenuSource>,
 5480        trigger: Option<&str>,
 5481        window: &mut Window,
 5482        cx: &mut Context<Self>,
 5483    ) {
 5484        if self.pending_rename.is_some() {
 5485            return;
 5486        }
 5487
 5488        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5489
 5490        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5491        // inserted and selected. To handle that case, the start of the selection is used so that
 5492        // the menu starts with all choices.
 5493        let position = self
 5494            .selections
 5495            .newest_anchor()
 5496            .start
 5497            .bias_right(&multibuffer_snapshot);
 5498        if position.diff_base_anchor.is_some() {
 5499            return;
 5500        }
 5501        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5502        let Some(buffer) = buffer_position
 5503            .buffer_id
 5504            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5505        else {
 5506            return;
 5507        };
 5508        let buffer_snapshot = buffer.read(cx).snapshot();
 5509
 5510        let query: Option<Arc<String>> =
 5511            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5512                .map(|query| query.into());
 5513
 5514        drop(multibuffer_snapshot);
 5515
 5516        // Hide the current completions menu when query is empty. Without this, cached
 5517        // completions from before the trigger char may be reused (#32774).
 5518        if query.is_none() {
 5519            let menu_is_open = matches!(
 5520                self.context_menu.borrow().as_ref(),
 5521                Some(CodeContextMenu::Completions(_))
 5522            );
 5523            if menu_is_open {
 5524                self.hide_context_menu(window, cx);
 5525            }
 5526        }
 5527
 5528        let mut ignore_word_threshold = false;
 5529        let provider = match requested_source {
 5530            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5531            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5532                ignore_word_threshold = ignore_threshold;
 5533                None
 5534            }
 5535            Some(CompletionsMenuSource::SnippetChoices) => {
 5536                log::error!("bug: SnippetChoices requested_source is not handled");
 5537                None
 5538            }
 5539        };
 5540
 5541        let sort_completions = provider
 5542            .as_ref()
 5543            .is_some_and(|provider| provider.sort_completions());
 5544
 5545        let filter_completions = provider
 5546            .as_ref()
 5547            .is_none_or(|provider| provider.filter_completions());
 5548
 5549        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5550            if filter_completions {
 5551                menu.filter(query.clone(), provider.clone(), window, cx);
 5552            }
 5553            // When `is_incomplete` is false, no need to re-query completions when the current query
 5554            // is a suffix of the initial query.
 5555            if !menu.is_incomplete {
 5556                // If the new query is a suffix of the old query (typing more characters) and
 5557                // the previous result was complete, the existing completions can be filtered.
 5558                //
 5559                // Note that this is always true for snippet completions.
 5560                let query_matches = match (&menu.initial_query, &query) {
 5561                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5562                    (None, _) => true,
 5563                    _ => false,
 5564                };
 5565                if query_matches {
 5566                    let position_matches = if menu.initial_position == position {
 5567                        true
 5568                    } else {
 5569                        let snapshot = self.buffer.read(cx).read(cx);
 5570                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5571                    };
 5572                    if position_matches {
 5573                        return;
 5574                    }
 5575                }
 5576            }
 5577        };
 5578
 5579        let trigger_kind = match trigger {
 5580            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5581                CompletionTriggerKind::TRIGGER_CHARACTER
 5582            }
 5583            _ => CompletionTriggerKind::INVOKED,
 5584        };
 5585        let completion_context = CompletionContext {
 5586            trigger_character: trigger.and_then(|trigger| {
 5587                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5588                    Some(String::from(trigger))
 5589                } else {
 5590                    None
 5591                }
 5592            }),
 5593            trigger_kind,
 5594        };
 5595
 5596        let Anchor {
 5597            excerpt_id: buffer_excerpt_id,
 5598            text_anchor: buffer_position,
 5599            ..
 5600        } = buffer_position;
 5601
 5602        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5603            buffer_snapshot.surrounding_word(buffer_position, None)
 5604        {
 5605            let word_to_exclude = buffer_snapshot
 5606                .text_for_range(word_range.clone())
 5607                .collect::<String>();
 5608            (
 5609                buffer_snapshot.anchor_before(word_range.start)
 5610                    ..buffer_snapshot.anchor_after(buffer_position),
 5611                Some(word_to_exclude),
 5612            )
 5613        } else {
 5614            (buffer_position..buffer_position, None)
 5615        };
 5616
 5617        let language = buffer_snapshot
 5618            .language_at(buffer_position)
 5619            .map(|language| language.name());
 5620
 5621        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5622            .completions
 5623            .clone();
 5624
 5625        let show_completion_documentation = buffer_snapshot
 5626            .settings_at(buffer_position, cx)
 5627            .show_completion_documentation;
 5628
 5629        // The document can be large, so stay in reasonable bounds when searching for words,
 5630        // otherwise completion pop-up might be slow to appear.
 5631        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5632        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5633        let min_word_search = buffer_snapshot.clip_point(
 5634            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5635            Bias::Left,
 5636        );
 5637        let max_word_search = buffer_snapshot.clip_point(
 5638            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5639            Bias::Right,
 5640        );
 5641        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5642            ..buffer_snapshot.point_to_offset(max_word_search);
 5643
 5644        let skip_digits = query
 5645            .as_ref()
 5646            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5647
 5648        let omit_word_completions = !self.word_completions_enabled
 5649            || (!ignore_word_threshold
 5650                && match &query {
 5651                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5652                    None => completion_settings.words_min_length != 0,
 5653                });
 5654
 5655        let (mut words, provider_responses) = match &provider {
 5656            Some(provider) => {
 5657                let provider_responses = provider.completions(
 5658                    buffer_excerpt_id,
 5659                    &buffer,
 5660                    buffer_position,
 5661                    completion_context,
 5662                    window,
 5663                    cx,
 5664                );
 5665
 5666                let words = match (omit_word_completions, completion_settings.words) {
 5667                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5668                        Task::ready(BTreeMap::default())
 5669                    }
 5670                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5671                        .background_spawn(async move {
 5672                            buffer_snapshot.words_in_range(WordsQuery {
 5673                                fuzzy_contents: None,
 5674                                range: word_search_range,
 5675                                skip_digits,
 5676                            })
 5677                        }),
 5678                };
 5679
 5680                (words, provider_responses)
 5681            }
 5682            None => {
 5683                let words = if omit_word_completions {
 5684                    Task::ready(BTreeMap::default())
 5685                } else {
 5686                    cx.background_spawn(async move {
 5687                        buffer_snapshot.words_in_range(WordsQuery {
 5688                            fuzzy_contents: None,
 5689                            range: word_search_range,
 5690                            skip_digits,
 5691                        })
 5692                    })
 5693                };
 5694                (words, Task::ready(Ok(Vec::new())))
 5695            }
 5696        };
 5697
 5698        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5699
 5700        let id = post_inc(&mut self.next_completion_id);
 5701        let task = cx.spawn_in(window, async move |editor, cx| {
 5702            let Ok(()) = editor.update(cx, |this, _| {
 5703                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5704            }) else {
 5705                return;
 5706            };
 5707
 5708            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5709            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5710            let mut completions = Vec::new();
 5711            let mut is_incomplete = false;
 5712            let mut display_options: Option<CompletionDisplayOptions> = None;
 5713            if let Some(provider_responses) = provider_responses.await.log_err()
 5714                && !provider_responses.is_empty()
 5715            {
 5716                for response in provider_responses {
 5717                    completions.extend(response.completions);
 5718                    is_incomplete = is_incomplete || response.is_incomplete;
 5719                    match display_options.as_mut() {
 5720                        None => {
 5721                            display_options = Some(response.display_options);
 5722                        }
 5723                        Some(options) => options.merge(&response.display_options),
 5724                    }
 5725                }
 5726                if completion_settings.words == WordsCompletionMode::Fallback {
 5727                    words = Task::ready(BTreeMap::default());
 5728                }
 5729            }
 5730            let display_options = display_options.unwrap_or_default();
 5731
 5732            let mut words = words.await;
 5733            if let Some(word_to_exclude) = &word_to_exclude {
 5734                words.remove(word_to_exclude);
 5735            }
 5736            for lsp_completion in &completions {
 5737                words.remove(&lsp_completion.new_text);
 5738            }
 5739            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5740                replace_range: word_replace_range.clone(),
 5741                new_text: word.clone(),
 5742                label: CodeLabel::plain(word, None),
 5743                icon_path: None,
 5744                documentation: None,
 5745                source: CompletionSource::BufferWord {
 5746                    word_range,
 5747                    resolved: false,
 5748                },
 5749                insert_text_mode: Some(InsertTextMode::AS_IS),
 5750                confirm: None,
 5751            }));
 5752
 5753            let menu = if completions.is_empty() {
 5754                None
 5755            } else {
 5756                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5757                    let languages = editor
 5758                        .workspace
 5759                        .as_ref()
 5760                        .and_then(|(workspace, _)| workspace.upgrade())
 5761                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5762                    let menu = CompletionsMenu::new(
 5763                        id,
 5764                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5765                        sort_completions,
 5766                        show_completion_documentation,
 5767                        position,
 5768                        query.clone(),
 5769                        is_incomplete,
 5770                        buffer.clone(),
 5771                        completions.into(),
 5772                        display_options,
 5773                        snippet_sort_order,
 5774                        languages,
 5775                        language,
 5776                        cx,
 5777                    );
 5778
 5779                    let query = if filter_completions { query } else { None };
 5780                    let matches_task = if let Some(query) = query {
 5781                        menu.do_async_filtering(query, cx)
 5782                    } else {
 5783                        Task::ready(menu.unfiltered_matches())
 5784                    };
 5785                    (menu, matches_task)
 5786                }) else {
 5787                    return;
 5788                };
 5789
 5790                let matches = matches_task.await;
 5791
 5792                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5793                    // Newer menu already set, so exit.
 5794                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5795                        editor.context_menu.borrow().as_ref()
 5796                        && prev_menu.id > id
 5797                    {
 5798                        return;
 5799                    };
 5800
 5801                    // Only valid to take prev_menu because it the new menu is immediately set
 5802                    // below, or the menu is hidden.
 5803                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5804                        editor.context_menu.borrow_mut().take()
 5805                    {
 5806                        let position_matches =
 5807                            if prev_menu.initial_position == menu.initial_position {
 5808                                true
 5809                            } else {
 5810                                let snapshot = editor.buffer.read(cx).read(cx);
 5811                                prev_menu.initial_position.to_offset(&snapshot)
 5812                                    == menu.initial_position.to_offset(&snapshot)
 5813                            };
 5814                        if position_matches {
 5815                            // Preserve markdown cache before `set_filter_results` because it will
 5816                            // try to populate the documentation cache.
 5817                            menu.preserve_markdown_cache(prev_menu);
 5818                        }
 5819                    };
 5820
 5821                    menu.set_filter_results(matches, provider, window, cx);
 5822                }) else {
 5823                    return;
 5824                };
 5825
 5826                menu.visible().then_some(menu)
 5827            };
 5828
 5829            editor
 5830                .update_in(cx, |editor, window, cx| {
 5831                    if editor.focus_handle.is_focused(window)
 5832                        && let Some(menu) = menu
 5833                    {
 5834                        *editor.context_menu.borrow_mut() =
 5835                            Some(CodeContextMenu::Completions(menu));
 5836
 5837                        crate::hover_popover::hide_hover(editor, cx);
 5838                        if editor.show_edit_predictions_in_menu() {
 5839                            editor.update_visible_edit_prediction(window, cx);
 5840                        } else {
 5841                            editor.discard_edit_prediction(false, cx);
 5842                        }
 5843
 5844                        cx.notify();
 5845                        return;
 5846                    }
 5847
 5848                    if editor.completion_tasks.len() <= 1 {
 5849                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5850                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5851                        // If it was already hidden and we don't show edit predictions in the menu,
 5852                        // we should also show the edit prediction when available.
 5853                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5854                            editor.update_visible_edit_prediction(window, cx);
 5855                        }
 5856                    }
 5857                })
 5858                .ok();
 5859        });
 5860
 5861        self.completion_tasks.push((id, task));
 5862    }
 5863
 5864    #[cfg(feature = "test-support")]
 5865    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5866        let menu = self.context_menu.borrow();
 5867        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5868            let completions = menu.completions.borrow();
 5869            Some(completions.to_vec())
 5870        } else {
 5871            None
 5872        }
 5873    }
 5874
 5875    pub fn with_completions_menu_matching_id<R>(
 5876        &self,
 5877        id: CompletionId,
 5878        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5879    ) -> R {
 5880        let mut context_menu = self.context_menu.borrow_mut();
 5881        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5882            return f(None);
 5883        };
 5884        if completions_menu.id != id {
 5885            return f(None);
 5886        }
 5887        f(Some(completions_menu))
 5888    }
 5889
 5890    pub fn confirm_completion(
 5891        &mut self,
 5892        action: &ConfirmCompletion,
 5893        window: &mut Window,
 5894        cx: &mut Context<Self>,
 5895    ) -> Option<Task<Result<()>>> {
 5896        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5897        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5898    }
 5899
 5900    pub fn confirm_completion_insert(
 5901        &mut self,
 5902        _: &ConfirmCompletionInsert,
 5903        window: &mut Window,
 5904        cx: &mut Context<Self>,
 5905    ) -> Option<Task<Result<()>>> {
 5906        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5907        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5908    }
 5909
 5910    pub fn confirm_completion_replace(
 5911        &mut self,
 5912        _: &ConfirmCompletionReplace,
 5913        window: &mut Window,
 5914        cx: &mut Context<Self>,
 5915    ) -> Option<Task<Result<()>>> {
 5916        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5917        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5918    }
 5919
 5920    pub fn compose_completion(
 5921        &mut self,
 5922        action: &ComposeCompletion,
 5923        window: &mut Window,
 5924        cx: &mut Context<Self>,
 5925    ) -> Option<Task<Result<()>>> {
 5926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5927        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5928    }
 5929
 5930    fn do_completion(
 5931        &mut self,
 5932        item_ix: Option<usize>,
 5933        intent: CompletionIntent,
 5934        window: &mut Window,
 5935        cx: &mut Context<Editor>,
 5936    ) -> Option<Task<Result<()>>> {
 5937        use language::ToOffset as _;
 5938
 5939        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5940        else {
 5941            return None;
 5942        };
 5943
 5944        let candidate_id = {
 5945            let entries = completions_menu.entries.borrow();
 5946            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5947            if self.show_edit_predictions_in_menu() {
 5948                self.discard_edit_prediction(true, cx);
 5949            }
 5950            mat.candidate_id
 5951        };
 5952
 5953        let completion = completions_menu
 5954            .completions
 5955            .borrow()
 5956            .get(candidate_id)?
 5957            .clone();
 5958        cx.stop_propagation();
 5959
 5960        let buffer_handle = completions_menu.buffer.clone();
 5961
 5962        let CompletionEdit {
 5963            new_text,
 5964            snippet,
 5965            replace_range,
 5966        } = process_completion_for_edit(
 5967            &completion,
 5968            intent,
 5969            &buffer_handle,
 5970            &completions_menu.initial_position.text_anchor,
 5971            cx,
 5972        );
 5973
 5974        let buffer = buffer_handle.read(cx);
 5975        let snapshot = self.buffer.read(cx).snapshot(cx);
 5976        let newest_anchor = self.selections.newest_anchor();
 5977        let replace_range_multibuffer = {
 5978            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5979            let multibuffer_anchor = snapshot
 5980                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5981                .unwrap()
 5982                ..snapshot
 5983                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5984                    .unwrap();
 5985            multibuffer_anchor.start.to_offset(&snapshot)
 5986                ..multibuffer_anchor.end.to_offset(&snapshot)
 5987        };
 5988        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5989            return None;
 5990        }
 5991
 5992        let old_text = buffer
 5993            .text_for_range(replace_range.clone())
 5994            .collect::<String>();
 5995        let lookbehind = newest_anchor
 5996            .start
 5997            .text_anchor
 5998            .to_offset(buffer)
 5999            .saturating_sub(replace_range.start);
 6000        let lookahead = replace_range
 6001            .end
 6002            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6003        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6004        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6005
 6006        let selections = self.selections.all::<usize>(cx);
 6007        let mut ranges = Vec::new();
 6008        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6009
 6010        for selection in &selections {
 6011            let range = if selection.id == newest_anchor.id {
 6012                replace_range_multibuffer.clone()
 6013            } else {
 6014                let mut range = selection.range();
 6015
 6016                // if prefix is present, don't duplicate it
 6017                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6018                    range.start = range.start.saturating_sub(lookbehind);
 6019
 6020                    // if suffix is also present, mimic the newest cursor and replace it
 6021                    if selection.id != newest_anchor.id
 6022                        && snapshot.contains_str_at(range.end, suffix)
 6023                    {
 6024                        range.end += lookahead;
 6025                    }
 6026                }
 6027                range
 6028            };
 6029
 6030            ranges.push(range.clone());
 6031
 6032            if !self.linked_edit_ranges.is_empty() {
 6033                let start_anchor = snapshot.anchor_before(range.start);
 6034                let end_anchor = snapshot.anchor_after(range.end);
 6035                if let Some(ranges) = self
 6036                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6037                {
 6038                    for (buffer, edits) in ranges {
 6039                        linked_edits
 6040                            .entry(buffer.clone())
 6041                            .or_default()
 6042                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6043                    }
 6044                }
 6045            }
 6046        }
 6047
 6048        let common_prefix_len = old_text
 6049            .chars()
 6050            .zip(new_text.chars())
 6051            .take_while(|(a, b)| a == b)
 6052            .map(|(a, _)| a.len_utf8())
 6053            .sum::<usize>();
 6054
 6055        cx.emit(EditorEvent::InputHandled {
 6056            utf16_range_to_replace: None,
 6057            text: new_text[common_prefix_len..].into(),
 6058        });
 6059
 6060        self.transact(window, cx, |editor, window, cx| {
 6061            if let Some(mut snippet) = snippet {
 6062                snippet.text = new_text.to_string();
 6063                editor
 6064                    .insert_snippet(&ranges, snippet, window, cx)
 6065                    .log_err();
 6066            } else {
 6067                editor.buffer.update(cx, |multi_buffer, cx| {
 6068                    let auto_indent = match completion.insert_text_mode {
 6069                        Some(InsertTextMode::AS_IS) => None,
 6070                        _ => editor.autoindent_mode.clone(),
 6071                    };
 6072                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6073                    multi_buffer.edit(edits, auto_indent, cx);
 6074                });
 6075            }
 6076            for (buffer, edits) in linked_edits {
 6077                buffer.update(cx, |buffer, cx| {
 6078                    let snapshot = buffer.snapshot();
 6079                    let edits = edits
 6080                        .into_iter()
 6081                        .map(|(range, text)| {
 6082                            use text::ToPoint as TP;
 6083                            let end_point = TP::to_point(&range.end, &snapshot);
 6084                            let start_point = TP::to_point(&range.start, &snapshot);
 6085                            (start_point..end_point, text)
 6086                        })
 6087                        .sorted_by_key(|(range, _)| range.start);
 6088                    buffer.edit(edits, None, cx);
 6089                })
 6090            }
 6091
 6092            editor.refresh_edit_prediction(true, false, window, cx);
 6093        });
 6094        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6095
 6096        let show_new_completions_on_confirm = completion
 6097            .confirm
 6098            .as_ref()
 6099            .is_some_and(|confirm| confirm(intent, window, cx));
 6100        if show_new_completions_on_confirm {
 6101            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6102        }
 6103
 6104        let provider = self.completion_provider.as_ref()?;
 6105        drop(completion);
 6106        let apply_edits = provider.apply_additional_edits_for_completion(
 6107            buffer_handle,
 6108            completions_menu.completions.clone(),
 6109            candidate_id,
 6110            true,
 6111            cx,
 6112        );
 6113
 6114        let editor_settings = EditorSettings::get_global(cx);
 6115        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6116            // After the code completion is finished, users often want to know what signatures are needed.
 6117            // so we should automatically call signature_help
 6118            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6119        }
 6120
 6121        Some(cx.foreground_executor().spawn(async move {
 6122            apply_edits.await?;
 6123            Ok(())
 6124        }))
 6125    }
 6126
 6127    pub fn toggle_code_actions(
 6128        &mut self,
 6129        action: &ToggleCodeActions,
 6130        window: &mut Window,
 6131        cx: &mut Context<Self>,
 6132    ) {
 6133        let quick_launch = action.quick_launch;
 6134        let mut context_menu = self.context_menu.borrow_mut();
 6135        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6136            if code_actions.deployed_from == action.deployed_from {
 6137                // Toggle if we're selecting the same one
 6138                *context_menu = None;
 6139                cx.notify();
 6140                return;
 6141            } else {
 6142                // Otherwise, clear it and start a new one
 6143                *context_menu = None;
 6144                cx.notify();
 6145            }
 6146        }
 6147        drop(context_menu);
 6148        let snapshot = self.snapshot(window, cx);
 6149        let deployed_from = action.deployed_from.clone();
 6150        let action = action.clone();
 6151        self.completion_tasks.clear();
 6152        self.discard_edit_prediction(false, cx);
 6153
 6154        let multibuffer_point = match &action.deployed_from {
 6155            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6156                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6157            }
 6158            _ => self.selections.newest::<Point>(cx).head(),
 6159        };
 6160        let Some((buffer, buffer_row)) = snapshot
 6161            .buffer_snapshot
 6162            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6163            .and_then(|(buffer_snapshot, range)| {
 6164                self.buffer()
 6165                    .read(cx)
 6166                    .buffer(buffer_snapshot.remote_id())
 6167                    .map(|buffer| (buffer, range.start.row))
 6168            })
 6169        else {
 6170            return;
 6171        };
 6172        let buffer_id = buffer.read(cx).remote_id();
 6173        let tasks = self
 6174            .tasks
 6175            .get(&(buffer_id, buffer_row))
 6176            .map(|t| Arc::new(t.to_owned()));
 6177
 6178        if !self.focus_handle.is_focused(window) {
 6179            return;
 6180        }
 6181        let project = self.project.clone();
 6182
 6183        let code_actions_task = match deployed_from {
 6184            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6185            _ => self.code_actions(buffer_row, window, cx),
 6186        };
 6187
 6188        let runnable_task = match deployed_from {
 6189            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6190            _ => {
 6191                let mut task_context_task = Task::ready(None);
 6192                if let Some(tasks) = &tasks
 6193                    && let Some(project) = project
 6194                {
 6195                    task_context_task =
 6196                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6197                }
 6198
 6199                cx.spawn_in(window, {
 6200                    let buffer = buffer.clone();
 6201                    async move |editor, cx| {
 6202                        let task_context = task_context_task.await;
 6203
 6204                        let resolved_tasks =
 6205                            tasks
 6206                                .zip(task_context.clone())
 6207                                .map(|(tasks, task_context)| ResolvedTasks {
 6208                                    templates: tasks.resolve(&task_context).collect(),
 6209                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6210                                        multibuffer_point.row,
 6211                                        tasks.column,
 6212                                    )),
 6213                                });
 6214                        let debug_scenarios = editor
 6215                            .update(cx, |editor, cx| {
 6216                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6217                            })?
 6218                            .await;
 6219                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6220                    }
 6221                })
 6222            }
 6223        };
 6224
 6225        cx.spawn_in(window, async move |editor, cx| {
 6226            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6227            let code_actions = code_actions_task.await;
 6228            let spawn_straight_away = quick_launch
 6229                && resolved_tasks
 6230                    .as_ref()
 6231                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6232                && code_actions
 6233                    .as_ref()
 6234                    .is_none_or(|actions| actions.is_empty())
 6235                && debug_scenarios.is_empty();
 6236
 6237            editor.update_in(cx, |editor, window, cx| {
 6238                crate::hover_popover::hide_hover(editor, cx);
 6239                let actions = CodeActionContents::new(
 6240                    resolved_tasks,
 6241                    code_actions,
 6242                    debug_scenarios,
 6243                    task_context.unwrap_or_default(),
 6244                );
 6245
 6246                // Don't show the menu if there are no actions available
 6247                if actions.is_empty() {
 6248                    cx.notify();
 6249                    return Task::ready(Ok(()));
 6250                }
 6251
 6252                *editor.context_menu.borrow_mut() =
 6253                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6254                        buffer,
 6255                        actions,
 6256                        selected_item: Default::default(),
 6257                        scroll_handle: UniformListScrollHandle::default(),
 6258                        deployed_from,
 6259                    }));
 6260                cx.notify();
 6261                if spawn_straight_away
 6262                    && let Some(task) = editor.confirm_code_action(
 6263                        &ConfirmCodeAction { item_ix: Some(0) },
 6264                        window,
 6265                        cx,
 6266                    )
 6267                {
 6268                    return task;
 6269                }
 6270
 6271                Task::ready(Ok(()))
 6272            })
 6273        })
 6274        .detach_and_log_err(cx);
 6275    }
 6276
 6277    fn debug_scenarios(
 6278        &mut self,
 6279        resolved_tasks: &Option<ResolvedTasks>,
 6280        buffer: &Entity<Buffer>,
 6281        cx: &mut App,
 6282    ) -> Task<Vec<task::DebugScenario>> {
 6283        maybe!({
 6284            let project = self.project()?;
 6285            let dap_store = project.read(cx).dap_store();
 6286            let mut scenarios = vec![];
 6287            let resolved_tasks = resolved_tasks.as_ref()?;
 6288            let buffer = buffer.read(cx);
 6289            let language = buffer.language()?;
 6290            let file = buffer.file();
 6291            let debug_adapter = language_settings(language.name().into(), file, cx)
 6292                .debuggers
 6293                .first()
 6294                .map(SharedString::from)
 6295                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6296
 6297            dap_store.update(cx, |dap_store, cx| {
 6298                for (_, task) in &resolved_tasks.templates {
 6299                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6300                        task.original_task().clone(),
 6301                        debug_adapter.clone().into(),
 6302                        task.display_label().to_owned().into(),
 6303                        cx,
 6304                    );
 6305                    scenarios.push(maybe_scenario);
 6306                }
 6307            });
 6308            Some(cx.background_spawn(async move {
 6309                futures::future::join_all(scenarios)
 6310                    .await
 6311                    .into_iter()
 6312                    .flatten()
 6313                    .collect::<Vec<_>>()
 6314            }))
 6315        })
 6316        .unwrap_or_else(|| Task::ready(vec![]))
 6317    }
 6318
 6319    fn code_actions(
 6320        &mut self,
 6321        buffer_row: u32,
 6322        window: &mut Window,
 6323        cx: &mut Context<Self>,
 6324    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6325        let mut task = self.code_actions_task.take();
 6326        cx.spawn_in(window, async move |editor, cx| {
 6327            while let Some(prev_task) = task {
 6328                prev_task.await.log_err();
 6329                task = editor
 6330                    .update(cx, |this, _| this.code_actions_task.take())
 6331                    .ok()?;
 6332            }
 6333
 6334            editor
 6335                .update(cx, |editor, cx| {
 6336                    editor
 6337                        .available_code_actions
 6338                        .clone()
 6339                        .and_then(|(location, code_actions)| {
 6340                            let snapshot = location.buffer.read(cx).snapshot();
 6341                            let point_range = location.range.to_point(&snapshot);
 6342                            let point_range = point_range.start.row..=point_range.end.row;
 6343                            if point_range.contains(&buffer_row) {
 6344                                Some(code_actions)
 6345                            } else {
 6346                                None
 6347                            }
 6348                        })
 6349                })
 6350                .ok()
 6351                .flatten()
 6352        })
 6353    }
 6354
 6355    pub fn confirm_code_action(
 6356        &mut self,
 6357        action: &ConfirmCodeAction,
 6358        window: &mut Window,
 6359        cx: &mut Context<Self>,
 6360    ) -> Option<Task<Result<()>>> {
 6361        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6362
 6363        let actions_menu =
 6364            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6365                menu
 6366            } else {
 6367                return None;
 6368            };
 6369
 6370        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6371        let action = actions_menu.actions.get(action_ix)?;
 6372        let title = action.label();
 6373        let buffer = actions_menu.buffer;
 6374        let workspace = self.workspace()?;
 6375
 6376        match action {
 6377            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6378                workspace.update(cx, |workspace, cx| {
 6379                    workspace.schedule_resolved_task(
 6380                        task_source_kind,
 6381                        resolved_task,
 6382                        false,
 6383                        window,
 6384                        cx,
 6385                    );
 6386
 6387                    Some(Task::ready(Ok(())))
 6388                })
 6389            }
 6390            CodeActionsItem::CodeAction {
 6391                excerpt_id,
 6392                action,
 6393                provider,
 6394            } => {
 6395                let apply_code_action =
 6396                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6397                let workspace = workspace.downgrade();
 6398                Some(cx.spawn_in(window, async move |editor, cx| {
 6399                    let project_transaction = apply_code_action.await?;
 6400                    Self::open_project_transaction(
 6401                        &editor,
 6402                        workspace,
 6403                        project_transaction,
 6404                        title,
 6405                        cx,
 6406                    )
 6407                    .await
 6408                }))
 6409            }
 6410            CodeActionsItem::DebugScenario(scenario) => {
 6411                let context = actions_menu.actions.context;
 6412
 6413                workspace.update(cx, |workspace, cx| {
 6414                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6415                    workspace.start_debug_session(
 6416                        scenario,
 6417                        context,
 6418                        Some(buffer),
 6419                        None,
 6420                        window,
 6421                        cx,
 6422                    );
 6423                });
 6424                Some(Task::ready(Ok(())))
 6425            }
 6426        }
 6427    }
 6428
 6429    pub async fn open_project_transaction(
 6430        editor: &WeakEntity<Editor>,
 6431        workspace: WeakEntity<Workspace>,
 6432        transaction: ProjectTransaction,
 6433        title: String,
 6434        cx: &mut AsyncWindowContext,
 6435    ) -> Result<()> {
 6436        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6437        cx.update(|_, cx| {
 6438            entries.sort_unstable_by_key(|(buffer, _)| {
 6439                buffer.read(cx).file().map(|f| f.path().clone())
 6440            });
 6441        })?;
 6442        if entries.is_empty() {
 6443            return Ok(());
 6444        }
 6445
 6446        // If the project transaction's edits are all contained within this editor, then
 6447        // avoid opening a new editor to display them.
 6448
 6449        if let [(buffer, transaction)] = &*entries {
 6450            let excerpt = editor.update(cx, |editor, cx| {
 6451                editor
 6452                    .buffer()
 6453                    .read(cx)
 6454                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6455            })?;
 6456            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6457                && excerpted_buffer == *buffer
 6458            {
 6459                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6460                    let excerpt_range = excerpt_range.to_offset(buffer);
 6461                    buffer
 6462                        .edited_ranges_for_transaction::<usize>(transaction)
 6463                        .all(|range| {
 6464                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6465                        })
 6466                })?;
 6467
 6468                if all_edits_within_excerpt {
 6469                    return Ok(());
 6470                }
 6471            }
 6472        }
 6473
 6474        let mut ranges_to_highlight = Vec::new();
 6475        let excerpt_buffer = cx.new(|cx| {
 6476            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6477            for (buffer_handle, transaction) in &entries {
 6478                let edited_ranges = buffer_handle
 6479                    .read(cx)
 6480                    .edited_ranges_for_transaction::<Point>(transaction)
 6481                    .collect::<Vec<_>>();
 6482                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6483                    PathKey::for_buffer(buffer_handle, cx),
 6484                    buffer_handle.clone(),
 6485                    edited_ranges,
 6486                    multibuffer_context_lines(cx),
 6487                    cx,
 6488                );
 6489
 6490                ranges_to_highlight.extend(ranges);
 6491            }
 6492            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6493            multibuffer
 6494        })?;
 6495
 6496        workspace.update_in(cx, |workspace, window, cx| {
 6497            let project = workspace.project().clone();
 6498            let editor =
 6499                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6500            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6501            editor.update(cx, |editor, cx| {
 6502                editor.highlight_background::<Self>(
 6503                    &ranges_to_highlight,
 6504                    |theme| theme.colors().editor_highlighted_line_background,
 6505                    cx,
 6506                );
 6507            });
 6508        })?;
 6509
 6510        Ok(())
 6511    }
 6512
 6513    pub fn clear_code_action_providers(&mut self) {
 6514        self.code_action_providers.clear();
 6515        self.available_code_actions.take();
 6516    }
 6517
 6518    pub fn add_code_action_provider(
 6519        &mut self,
 6520        provider: Rc<dyn CodeActionProvider>,
 6521        window: &mut Window,
 6522        cx: &mut Context<Self>,
 6523    ) {
 6524        if self
 6525            .code_action_providers
 6526            .iter()
 6527            .any(|existing_provider| existing_provider.id() == provider.id())
 6528        {
 6529            return;
 6530        }
 6531
 6532        self.code_action_providers.push(provider);
 6533        self.refresh_code_actions(window, cx);
 6534    }
 6535
 6536    pub fn remove_code_action_provider(
 6537        &mut self,
 6538        id: Arc<str>,
 6539        window: &mut Window,
 6540        cx: &mut Context<Self>,
 6541    ) {
 6542        self.code_action_providers
 6543            .retain(|provider| provider.id() != id);
 6544        self.refresh_code_actions(window, cx);
 6545    }
 6546
 6547    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6548        !self.code_action_providers.is_empty()
 6549            && EditorSettings::get_global(cx).toolbar.code_actions
 6550    }
 6551
 6552    pub fn has_available_code_actions(&self) -> bool {
 6553        self.available_code_actions
 6554            .as_ref()
 6555            .is_some_and(|(_, actions)| !actions.is_empty())
 6556    }
 6557
 6558    fn render_inline_code_actions(
 6559        &self,
 6560        icon_size: ui::IconSize,
 6561        display_row: DisplayRow,
 6562        is_active: bool,
 6563        cx: &mut Context<Self>,
 6564    ) -> AnyElement {
 6565        let show_tooltip = !self.context_menu_visible();
 6566        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6567            .icon_size(icon_size)
 6568            .shape(ui::IconButtonShape::Square)
 6569            .icon_color(ui::Color::Hidden)
 6570            .toggle_state(is_active)
 6571            .when(show_tooltip, |this| {
 6572                this.tooltip({
 6573                    let focus_handle = self.focus_handle.clone();
 6574                    move |window, cx| {
 6575                        Tooltip::for_action_in(
 6576                            "Toggle Code Actions",
 6577                            &ToggleCodeActions {
 6578                                deployed_from: None,
 6579                                quick_launch: false,
 6580                            },
 6581                            &focus_handle,
 6582                            window,
 6583                            cx,
 6584                        )
 6585                    }
 6586                })
 6587            })
 6588            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6589                window.focus(&editor.focus_handle(cx));
 6590                editor.toggle_code_actions(
 6591                    &crate::actions::ToggleCodeActions {
 6592                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6593                            display_row,
 6594                        )),
 6595                        quick_launch: false,
 6596                    },
 6597                    window,
 6598                    cx,
 6599                );
 6600            }))
 6601            .into_any_element()
 6602    }
 6603
 6604    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6605        &self.context_menu
 6606    }
 6607
 6608    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6609        let newest_selection = self.selections.newest_anchor().clone();
 6610        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6611        let buffer = self.buffer.read(cx);
 6612        if newest_selection.head().diff_base_anchor.is_some() {
 6613            return None;
 6614        }
 6615        let (start_buffer, start) =
 6616            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6617        let (end_buffer, end) =
 6618            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6619        if start_buffer != end_buffer {
 6620            return None;
 6621        }
 6622
 6623        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6624            cx.background_executor()
 6625                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6626                .await;
 6627
 6628            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6629                let providers = this.code_action_providers.clone();
 6630                let tasks = this
 6631                    .code_action_providers
 6632                    .iter()
 6633                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6634                    .collect::<Vec<_>>();
 6635                (providers, tasks)
 6636            })?;
 6637
 6638            let mut actions = Vec::new();
 6639            for (provider, provider_actions) in
 6640                providers.into_iter().zip(future::join_all(tasks).await)
 6641            {
 6642                if let Some(provider_actions) = provider_actions.log_err() {
 6643                    actions.extend(provider_actions.into_iter().map(|action| {
 6644                        AvailableCodeAction {
 6645                            excerpt_id: newest_selection.start.excerpt_id,
 6646                            action,
 6647                            provider: provider.clone(),
 6648                        }
 6649                    }));
 6650                }
 6651            }
 6652
 6653            this.update(cx, |this, cx| {
 6654                this.available_code_actions = if actions.is_empty() {
 6655                    None
 6656                } else {
 6657                    Some((
 6658                        Location {
 6659                            buffer: start_buffer,
 6660                            range: start..end,
 6661                        },
 6662                        actions.into(),
 6663                    ))
 6664                };
 6665                cx.notify();
 6666            })
 6667        }));
 6668        None
 6669    }
 6670
 6671    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6672        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6673            self.show_git_blame_inline = false;
 6674
 6675            self.show_git_blame_inline_delay_task =
 6676                Some(cx.spawn_in(window, async move |this, cx| {
 6677                    cx.background_executor().timer(delay).await;
 6678
 6679                    this.update(cx, |this, cx| {
 6680                        this.show_git_blame_inline = true;
 6681                        cx.notify();
 6682                    })
 6683                    .log_err();
 6684                }));
 6685        }
 6686    }
 6687
 6688    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6689        let snapshot = self.snapshot(window, cx);
 6690        let cursor = self.selections.newest::<Point>(cx).head();
 6691        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6692        else {
 6693            return;
 6694        };
 6695
 6696        let Some(blame) = self.blame.as_ref() else {
 6697            return;
 6698        };
 6699
 6700        let row_info = RowInfo {
 6701            buffer_id: Some(buffer.remote_id()),
 6702            buffer_row: Some(point.row),
 6703            ..Default::default()
 6704        };
 6705        let Some((buffer, blame_entry)) = blame
 6706            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6707            .flatten()
 6708        else {
 6709            return;
 6710        };
 6711
 6712        let anchor = self.selections.newest_anchor().head();
 6713        let position = self.to_pixel_point(anchor, &snapshot, window);
 6714        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6715            self.show_blame_popover(
 6716                buffer,
 6717                &blame_entry,
 6718                position + last_bounds.origin,
 6719                true,
 6720                cx,
 6721            );
 6722        };
 6723    }
 6724
 6725    fn show_blame_popover(
 6726        &mut self,
 6727        buffer: BufferId,
 6728        blame_entry: &BlameEntry,
 6729        position: gpui::Point<Pixels>,
 6730        ignore_timeout: bool,
 6731        cx: &mut Context<Self>,
 6732    ) {
 6733        if let Some(state) = &mut self.inline_blame_popover {
 6734            state.hide_task.take();
 6735        } else {
 6736            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6737            let blame_entry = blame_entry.clone();
 6738            let show_task = cx.spawn(async move |editor, cx| {
 6739                if !ignore_timeout {
 6740                    cx.background_executor()
 6741                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6742                        .await;
 6743                }
 6744                editor
 6745                    .update(cx, |editor, cx| {
 6746                        editor.inline_blame_popover_show_task.take();
 6747                        let Some(blame) = editor.blame.as_ref() else {
 6748                            return;
 6749                        };
 6750                        let blame = blame.read(cx);
 6751                        let details = blame.details_for_entry(buffer, &blame_entry);
 6752                        let markdown = cx.new(|cx| {
 6753                            Markdown::new(
 6754                                details
 6755                                    .as_ref()
 6756                                    .map(|message| message.message.clone())
 6757                                    .unwrap_or_default(),
 6758                                None,
 6759                                None,
 6760                                cx,
 6761                            )
 6762                        });
 6763                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6764                            position,
 6765                            hide_task: None,
 6766                            popover_bounds: None,
 6767                            popover_state: InlineBlamePopoverState {
 6768                                scroll_handle: ScrollHandle::new(),
 6769                                commit_message: details,
 6770                                markdown,
 6771                            },
 6772                            keyboard_grace: ignore_timeout,
 6773                        });
 6774                        cx.notify();
 6775                    })
 6776                    .ok();
 6777            });
 6778            self.inline_blame_popover_show_task = Some(show_task);
 6779        }
 6780    }
 6781
 6782    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6783        self.inline_blame_popover_show_task.take();
 6784        if let Some(state) = &mut self.inline_blame_popover {
 6785            let hide_task = cx.spawn(async move |editor, cx| {
 6786                cx.background_executor()
 6787                    .timer(std::time::Duration::from_millis(100))
 6788                    .await;
 6789                editor
 6790                    .update(cx, |editor, cx| {
 6791                        editor.inline_blame_popover.take();
 6792                        cx.notify();
 6793                    })
 6794                    .ok();
 6795            });
 6796            state.hide_task = Some(hide_task);
 6797        }
 6798    }
 6799
 6800    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6801        if self.pending_rename.is_some() {
 6802            return None;
 6803        }
 6804
 6805        let provider = self.semantics_provider.clone()?;
 6806        let buffer = self.buffer.read(cx);
 6807        let newest_selection = self.selections.newest_anchor().clone();
 6808        let cursor_position = newest_selection.head();
 6809        let (cursor_buffer, cursor_buffer_position) =
 6810            buffer.text_anchor_for_position(cursor_position, cx)?;
 6811        let (tail_buffer, tail_buffer_position) =
 6812            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6813        if cursor_buffer != tail_buffer {
 6814            return None;
 6815        }
 6816
 6817        let snapshot = cursor_buffer.read(cx).snapshot();
 6818        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6819        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6820        if start_word_range != end_word_range {
 6821            self.document_highlights_task.take();
 6822            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6823            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6824            return None;
 6825        }
 6826
 6827        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6828        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6829            cx.background_executor()
 6830                .timer(Duration::from_millis(debounce))
 6831                .await;
 6832
 6833            let highlights = if let Some(highlights) = cx
 6834                .update(|cx| {
 6835                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6836                })
 6837                .ok()
 6838                .flatten()
 6839            {
 6840                highlights.await.log_err()
 6841            } else {
 6842                None
 6843            };
 6844
 6845            if let Some(highlights) = highlights {
 6846                this.update(cx, |this, cx| {
 6847                    if this.pending_rename.is_some() {
 6848                        return;
 6849                    }
 6850
 6851                    let buffer = this.buffer.read(cx);
 6852                    if buffer
 6853                        .text_anchor_for_position(cursor_position, cx)
 6854                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6855                    {
 6856                        return;
 6857                    }
 6858
 6859                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6860                    let mut write_ranges = Vec::new();
 6861                    let mut read_ranges = Vec::new();
 6862                    for highlight in highlights {
 6863                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6864                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6865                        {
 6866                            let start = highlight
 6867                                .range
 6868                                .start
 6869                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6870                            let end = highlight
 6871                                .range
 6872                                .end
 6873                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6874                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6875                                continue;
 6876                            }
 6877
 6878                            let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
 6879                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6880                                write_ranges.push(range);
 6881                            } else {
 6882                                read_ranges.push(range);
 6883                            }
 6884                        }
 6885                    }
 6886
 6887                    this.highlight_background::<DocumentHighlightRead>(
 6888                        &read_ranges,
 6889                        |theme| theme.colors().editor_document_highlight_read_background,
 6890                        cx,
 6891                    );
 6892                    this.highlight_background::<DocumentHighlightWrite>(
 6893                        &write_ranges,
 6894                        |theme| theme.colors().editor_document_highlight_write_background,
 6895                        cx,
 6896                    );
 6897                    cx.notify();
 6898                })
 6899                .log_err();
 6900            }
 6901        }));
 6902        None
 6903    }
 6904
 6905    fn prepare_highlight_query_from_selection(
 6906        &mut self,
 6907        cx: &mut Context<Editor>,
 6908    ) -> Option<(String, Range<Anchor>)> {
 6909        if matches!(self.mode, EditorMode::SingleLine) {
 6910            return None;
 6911        }
 6912        if !EditorSettings::get_global(cx).selection_highlight {
 6913            return None;
 6914        }
 6915        if self.selections.count() != 1 || self.selections.line_mode() {
 6916            return None;
 6917        }
 6918        let selection = self.selections.newest::<Point>(cx);
 6919        if selection.is_empty() || selection.start.row != selection.end.row {
 6920            return None;
 6921        }
 6922        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6923        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6924        let query = multi_buffer_snapshot
 6925            .text_for_range(selection_anchor_range.clone())
 6926            .collect::<String>();
 6927        if query.trim().is_empty() {
 6928            return None;
 6929        }
 6930        Some((query, selection_anchor_range))
 6931    }
 6932
 6933    fn update_selection_occurrence_highlights(
 6934        &mut self,
 6935        query_text: String,
 6936        query_range: Range<Anchor>,
 6937        multi_buffer_range_to_query: Range<Point>,
 6938        use_debounce: bool,
 6939        window: &mut Window,
 6940        cx: &mut Context<Editor>,
 6941    ) -> Task<()> {
 6942        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6943        cx.spawn_in(window, async move |editor, cx| {
 6944            if use_debounce {
 6945                cx.background_executor()
 6946                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6947                    .await;
 6948            }
 6949            let match_task = cx.background_spawn(async move {
 6950                let buffer_ranges = multi_buffer_snapshot
 6951                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6952                    .into_iter()
 6953                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6954                let mut match_ranges = Vec::new();
 6955                let Ok(regex) = project::search::SearchQuery::text(
 6956                    query_text.clone(),
 6957                    false,
 6958                    false,
 6959                    false,
 6960                    Default::default(),
 6961                    Default::default(),
 6962                    false,
 6963                    None,
 6964                ) else {
 6965                    return Vec::default();
 6966                };
 6967                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6968                    match_ranges.extend(
 6969                        regex
 6970                            .search(buffer_snapshot, Some(search_range.clone()))
 6971                            .await
 6972                            .into_iter()
 6973                            .filter_map(|match_range| {
 6974                                let match_start = buffer_snapshot
 6975                                    .anchor_after(search_range.start + match_range.start);
 6976                                let match_end = buffer_snapshot
 6977                                    .anchor_before(search_range.start + match_range.end);
 6978                                let match_anchor_range = Anchor::range_in_buffer(
 6979                                    excerpt_id,
 6980                                    buffer_snapshot.remote_id(),
 6981                                    match_start..match_end,
 6982                                );
 6983                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6984                            }),
 6985                    );
 6986                }
 6987                match_ranges
 6988            });
 6989            let match_ranges = match_task.await;
 6990            editor
 6991                .update_in(cx, |editor, _, cx| {
 6992                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6993                    if !match_ranges.is_empty() {
 6994                        editor.highlight_background::<SelectedTextHighlight>(
 6995                            &match_ranges,
 6996                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6997                            cx,
 6998                        )
 6999                    }
 7000                })
 7001                .log_err();
 7002        })
 7003    }
 7004
 7005    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7006        struct NewlineFold;
 7007        let type_id = std::any::TypeId::of::<NewlineFold>();
 7008        if !self.mode.is_single_line() {
 7009            return;
 7010        }
 7011        let snapshot = self.snapshot(window, cx);
 7012        if snapshot.buffer_snapshot.max_point().row == 0 {
 7013            return;
 7014        }
 7015        let task = cx.background_spawn(async move {
 7016            let new_newlines = snapshot
 7017                .buffer_chars_at(0)
 7018                .filter_map(|(c, i)| {
 7019                    if c == '\n' {
 7020                        Some(
 7021                            snapshot.buffer_snapshot.anchor_after(i)
 7022                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7023                        )
 7024                    } else {
 7025                        None
 7026                    }
 7027                })
 7028                .collect::<Vec<_>>();
 7029            let existing_newlines = snapshot
 7030                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7031                .filter_map(|fold| {
 7032                    if fold.placeholder.type_tag == Some(type_id) {
 7033                        Some(fold.range.start..fold.range.end)
 7034                    } else {
 7035                        None
 7036                    }
 7037                })
 7038                .collect::<Vec<_>>();
 7039
 7040            (new_newlines, existing_newlines)
 7041        });
 7042        self.folding_newlines = cx.spawn(async move |this, cx| {
 7043            let (new_newlines, existing_newlines) = task.await;
 7044            if new_newlines == existing_newlines {
 7045                return;
 7046            }
 7047            let placeholder = FoldPlaceholder {
 7048                render: Arc::new(move |_, _, cx| {
 7049                    div()
 7050                        .bg(cx.theme().status().hint_background)
 7051                        .border_b_1()
 7052                        .size_full()
 7053                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7054                        .border_color(cx.theme().status().hint)
 7055                        .child("\\n")
 7056                        .into_any()
 7057                }),
 7058                constrain_width: false,
 7059                merge_adjacent: false,
 7060                type_tag: Some(type_id),
 7061            };
 7062            let creases = new_newlines
 7063                .into_iter()
 7064                .map(|range| Crease::simple(range, placeholder.clone()))
 7065                .collect();
 7066            this.update(cx, |this, cx| {
 7067                this.display_map.update(cx, |display_map, cx| {
 7068                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7069                    display_map.fold(creases, cx);
 7070                });
 7071            })
 7072            .ok();
 7073        });
 7074    }
 7075
 7076    fn refresh_selected_text_highlights(
 7077        &mut self,
 7078        on_buffer_edit: bool,
 7079        window: &mut Window,
 7080        cx: &mut Context<Editor>,
 7081    ) {
 7082        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7083        else {
 7084            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7085            self.quick_selection_highlight_task.take();
 7086            self.debounced_selection_highlight_task.take();
 7087            return;
 7088        };
 7089        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7090        if on_buffer_edit
 7091            || self
 7092                .quick_selection_highlight_task
 7093                .as_ref()
 7094                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7095        {
 7096            let multi_buffer_visible_start = self
 7097                .scroll_manager
 7098                .anchor()
 7099                .anchor
 7100                .to_point(&multi_buffer_snapshot);
 7101            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7102                multi_buffer_visible_start
 7103                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7104                Bias::Left,
 7105            );
 7106            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7107            self.quick_selection_highlight_task = Some((
 7108                query_range.clone(),
 7109                self.update_selection_occurrence_highlights(
 7110                    query_text.clone(),
 7111                    query_range.clone(),
 7112                    multi_buffer_visible_range,
 7113                    false,
 7114                    window,
 7115                    cx,
 7116                ),
 7117            ));
 7118        }
 7119        if on_buffer_edit
 7120            || self
 7121                .debounced_selection_highlight_task
 7122                .as_ref()
 7123                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7124        {
 7125            let multi_buffer_start = multi_buffer_snapshot
 7126                .anchor_before(0)
 7127                .to_point(&multi_buffer_snapshot);
 7128            let multi_buffer_end = multi_buffer_snapshot
 7129                .anchor_after(multi_buffer_snapshot.len())
 7130                .to_point(&multi_buffer_snapshot);
 7131            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7132            self.debounced_selection_highlight_task = Some((
 7133                query_range.clone(),
 7134                self.update_selection_occurrence_highlights(
 7135                    query_text,
 7136                    query_range,
 7137                    multi_buffer_full_range,
 7138                    true,
 7139                    window,
 7140                    cx,
 7141                ),
 7142            ));
 7143        }
 7144    }
 7145
 7146    pub fn refresh_edit_prediction(
 7147        &mut self,
 7148        debounce: bool,
 7149        user_requested: bool,
 7150        window: &mut Window,
 7151        cx: &mut Context<Self>,
 7152    ) -> Option<()> {
 7153        if DisableAiSettings::get_global(cx).disable_ai {
 7154            return None;
 7155        }
 7156
 7157        let provider = self.edit_prediction_provider()?;
 7158        let cursor = self.selections.newest_anchor().head();
 7159        let (buffer, cursor_buffer_position) =
 7160            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7161
 7162        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7163            self.discard_edit_prediction(false, cx);
 7164            return None;
 7165        }
 7166
 7167        self.update_visible_edit_prediction(window, cx);
 7168
 7169        if !user_requested
 7170            && (!self.should_show_edit_predictions()
 7171                || !self.is_focused(window)
 7172                || buffer.read(cx).is_empty())
 7173        {
 7174            self.discard_edit_prediction(false, cx);
 7175            return None;
 7176        }
 7177
 7178        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7179        Some(())
 7180    }
 7181
 7182    fn show_edit_predictions_in_menu(&self) -> bool {
 7183        match self.edit_prediction_settings {
 7184            EditPredictionSettings::Disabled => false,
 7185            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7186        }
 7187    }
 7188
 7189    pub fn edit_predictions_enabled(&self) -> bool {
 7190        match self.edit_prediction_settings {
 7191            EditPredictionSettings::Disabled => false,
 7192            EditPredictionSettings::Enabled { .. } => true,
 7193        }
 7194    }
 7195
 7196    fn edit_prediction_requires_modifier(&self) -> bool {
 7197        match self.edit_prediction_settings {
 7198            EditPredictionSettings::Disabled => false,
 7199            EditPredictionSettings::Enabled {
 7200                preview_requires_modifier,
 7201                ..
 7202            } => preview_requires_modifier,
 7203        }
 7204    }
 7205
 7206    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7207        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7208            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7209            self.discard_edit_prediction(false, cx);
 7210        } else {
 7211            let selection = self.selections.newest_anchor();
 7212            let cursor = selection.head();
 7213
 7214            if let Some((buffer, cursor_buffer_position)) =
 7215                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7216            {
 7217                self.edit_prediction_settings =
 7218                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7219            }
 7220        }
 7221    }
 7222
 7223    fn edit_prediction_settings_at_position(
 7224        &self,
 7225        buffer: &Entity<Buffer>,
 7226        buffer_position: language::Anchor,
 7227        cx: &App,
 7228    ) -> EditPredictionSettings {
 7229        if !self.mode.is_full()
 7230            || !self.show_edit_predictions_override.unwrap_or(true)
 7231            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7232        {
 7233            return EditPredictionSettings::Disabled;
 7234        }
 7235
 7236        let buffer = buffer.read(cx);
 7237
 7238        let file = buffer.file();
 7239
 7240        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7241            return EditPredictionSettings::Disabled;
 7242        };
 7243
 7244        let by_provider = matches!(
 7245            self.menu_edit_predictions_policy,
 7246            MenuEditPredictionsPolicy::ByProvider
 7247        );
 7248
 7249        let show_in_menu = by_provider
 7250            && self
 7251                .edit_prediction_provider
 7252                .as_ref()
 7253                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7254
 7255        let preview_requires_modifier =
 7256            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7257
 7258        EditPredictionSettings::Enabled {
 7259            show_in_menu,
 7260            preview_requires_modifier,
 7261        }
 7262    }
 7263
 7264    fn should_show_edit_predictions(&self) -> bool {
 7265        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7266    }
 7267
 7268    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7269        matches!(
 7270            self.edit_prediction_preview,
 7271            EditPredictionPreview::Active { .. }
 7272        )
 7273    }
 7274
 7275    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7276        let cursor = self.selections.newest_anchor().head();
 7277        if let Some((buffer, cursor_position)) =
 7278            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7279        {
 7280            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7281        } else {
 7282            false
 7283        }
 7284    }
 7285
 7286    pub fn supports_minimap(&self, cx: &App) -> bool {
 7287        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7288    }
 7289
 7290    fn edit_predictions_enabled_in_buffer(
 7291        &self,
 7292        buffer: &Entity<Buffer>,
 7293        buffer_position: language::Anchor,
 7294        cx: &App,
 7295    ) -> bool {
 7296        maybe!({
 7297            if self.read_only(cx) {
 7298                return Some(false);
 7299            }
 7300            let provider = self.edit_prediction_provider()?;
 7301            if !provider.is_enabled(buffer, buffer_position, cx) {
 7302                return Some(false);
 7303            }
 7304            let buffer = buffer.read(cx);
 7305            let Some(file) = buffer.file() else {
 7306                return Some(true);
 7307            };
 7308            let settings = all_language_settings(Some(file), cx);
 7309            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7310        })
 7311        .unwrap_or(false)
 7312    }
 7313
 7314    fn cycle_edit_prediction(
 7315        &mut self,
 7316        direction: Direction,
 7317        window: &mut Window,
 7318        cx: &mut Context<Self>,
 7319    ) -> Option<()> {
 7320        let provider = self.edit_prediction_provider()?;
 7321        let cursor = self.selections.newest_anchor().head();
 7322        let (buffer, cursor_buffer_position) =
 7323            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7324        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7325            return None;
 7326        }
 7327
 7328        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7329        self.update_visible_edit_prediction(window, cx);
 7330
 7331        Some(())
 7332    }
 7333
 7334    pub fn show_edit_prediction(
 7335        &mut self,
 7336        _: &ShowEditPrediction,
 7337        window: &mut Window,
 7338        cx: &mut Context<Self>,
 7339    ) {
 7340        if !self.has_active_edit_prediction() {
 7341            self.refresh_edit_prediction(false, true, window, cx);
 7342            return;
 7343        }
 7344
 7345        self.update_visible_edit_prediction(window, cx);
 7346    }
 7347
 7348    pub fn display_cursor_names(
 7349        &mut self,
 7350        _: &DisplayCursorNames,
 7351        window: &mut Window,
 7352        cx: &mut Context<Self>,
 7353    ) {
 7354        self.show_cursor_names(window, cx);
 7355    }
 7356
 7357    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7358        self.show_cursor_names = true;
 7359        cx.notify();
 7360        cx.spawn_in(window, async move |this, cx| {
 7361            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7362            this.update(cx, |this, cx| {
 7363                this.show_cursor_names = false;
 7364                cx.notify()
 7365            })
 7366            .ok()
 7367        })
 7368        .detach();
 7369    }
 7370
 7371    pub fn next_edit_prediction(
 7372        &mut self,
 7373        _: &NextEditPrediction,
 7374        window: &mut Window,
 7375        cx: &mut Context<Self>,
 7376    ) {
 7377        if self.has_active_edit_prediction() {
 7378            self.cycle_edit_prediction(Direction::Next, window, cx);
 7379        } else {
 7380            let is_copilot_disabled = self
 7381                .refresh_edit_prediction(false, true, window, cx)
 7382                .is_none();
 7383            if is_copilot_disabled {
 7384                cx.propagate();
 7385            }
 7386        }
 7387    }
 7388
 7389    pub fn previous_edit_prediction(
 7390        &mut self,
 7391        _: &PreviousEditPrediction,
 7392        window: &mut Window,
 7393        cx: &mut Context<Self>,
 7394    ) {
 7395        if self.has_active_edit_prediction() {
 7396            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7397        } else {
 7398            let is_copilot_disabled = self
 7399                .refresh_edit_prediction(false, true, window, cx)
 7400                .is_none();
 7401            if is_copilot_disabled {
 7402                cx.propagate();
 7403            }
 7404        }
 7405    }
 7406
 7407    pub fn accept_edit_prediction(
 7408        &mut self,
 7409        _: &AcceptEditPrediction,
 7410        window: &mut Window,
 7411        cx: &mut Context<Self>,
 7412    ) {
 7413        if self.show_edit_predictions_in_menu() {
 7414            self.hide_context_menu(window, cx);
 7415        }
 7416
 7417        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7418            return;
 7419        };
 7420
 7421        match &active_edit_prediction.completion {
 7422            EditPrediction::MoveWithin { target, .. } => {
 7423                let target = *target;
 7424
 7425                if let Some(position_map) = &self.last_position_map {
 7426                    if position_map
 7427                        .visible_row_range
 7428                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7429                        || !self.edit_prediction_requires_modifier()
 7430                    {
 7431                        self.unfold_ranges(&[target..target], true, false, cx);
 7432                        // Note that this is also done in vim's handler of the Tab action.
 7433                        self.change_selections(
 7434                            SelectionEffects::scroll(Autoscroll::newest()),
 7435                            window,
 7436                            cx,
 7437                            |selections| {
 7438                                selections.select_anchor_ranges([target..target]);
 7439                            },
 7440                        );
 7441                        self.clear_row_highlights::<EditPredictionPreview>();
 7442
 7443                        self.edit_prediction_preview
 7444                            .set_previous_scroll_position(None);
 7445                    } else {
 7446                        self.edit_prediction_preview
 7447                            .set_previous_scroll_position(Some(
 7448                                position_map.snapshot.scroll_anchor,
 7449                            ));
 7450
 7451                        self.highlight_rows::<EditPredictionPreview>(
 7452                            target..target,
 7453                            cx.theme().colors().editor_highlighted_line_background,
 7454                            RowHighlightOptions {
 7455                                autoscroll: true,
 7456                                ..Default::default()
 7457                            },
 7458                            cx,
 7459                        );
 7460                        self.request_autoscroll(Autoscroll::fit(), cx);
 7461                    }
 7462                }
 7463            }
 7464            EditPrediction::MoveOutside { snapshot, target } => {
 7465                if let Some(workspace) = self.workspace() {
 7466                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7467                        .detach_and_log_err(cx);
 7468                }
 7469            }
 7470            EditPrediction::Edit { edits, .. } => {
 7471                self.report_edit_prediction_event(
 7472                    active_edit_prediction.completion_id.clone(),
 7473                    true,
 7474                    cx,
 7475                );
 7476
 7477                if let Some(provider) = self.edit_prediction_provider() {
 7478                    provider.accept(cx);
 7479                }
 7480
 7481                // Store the transaction ID and selections before applying the edit
 7482                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7483
 7484                let snapshot = self.buffer.read(cx).snapshot(cx);
 7485                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7486
 7487                self.buffer.update(cx, |buffer, cx| {
 7488                    buffer.edit(edits.iter().cloned(), None, cx)
 7489                });
 7490
 7491                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7492                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7493                });
 7494
 7495                let selections = self.selections.disjoint_anchors_arc();
 7496                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7497                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7498                    if has_new_transaction {
 7499                        self.selection_history
 7500                            .insert_transaction(transaction_id_now, selections);
 7501                    }
 7502                }
 7503
 7504                self.update_visible_edit_prediction(window, cx);
 7505                if self.active_edit_prediction.is_none() {
 7506                    self.refresh_edit_prediction(true, true, window, cx);
 7507                }
 7508
 7509                cx.notify();
 7510            }
 7511        }
 7512
 7513        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7514    }
 7515
 7516    pub fn accept_partial_edit_prediction(
 7517        &mut self,
 7518        _: &AcceptPartialEditPrediction,
 7519        window: &mut Window,
 7520        cx: &mut Context<Self>,
 7521    ) {
 7522        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7523            return;
 7524        };
 7525        if self.selections.count() != 1 {
 7526            return;
 7527        }
 7528
 7529        match &active_edit_prediction.completion {
 7530            EditPrediction::MoveWithin { target, .. } => {
 7531                let target = *target;
 7532                self.change_selections(
 7533                    SelectionEffects::scroll(Autoscroll::newest()),
 7534                    window,
 7535                    cx,
 7536                    |selections| {
 7537                        selections.select_anchor_ranges([target..target]);
 7538                    },
 7539                );
 7540            }
 7541            EditPrediction::MoveOutside { snapshot, target } => {
 7542                if let Some(workspace) = self.workspace() {
 7543                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7544                        .detach_and_log_err(cx);
 7545                }
 7546            }
 7547            EditPrediction::Edit { edits, .. } => {
 7548                self.report_edit_prediction_event(
 7549                    active_edit_prediction.completion_id.clone(),
 7550                    true,
 7551                    cx,
 7552                );
 7553
 7554                // Find an insertion that starts at the cursor position.
 7555                let snapshot = self.buffer.read(cx).snapshot(cx);
 7556                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7557                let insertion = edits.iter().find_map(|(range, text)| {
 7558                    let range = range.to_offset(&snapshot);
 7559                    if range.is_empty() && range.start == cursor_offset {
 7560                        Some(text)
 7561                    } else {
 7562                        None
 7563                    }
 7564                });
 7565
 7566                if let Some(text) = insertion {
 7567                    let mut partial_completion = text
 7568                        .chars()
 7569                        .by_ref()
 7570                        .take_while(|c| c.is_alphabetic())
 7571                        .collect::<String>();
 7572                    if partial_completion.is_empty() {
 7573                        partial_completion = text
 7574                            .chars()
 7575                            .by_ref()
 7576                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7577                            .collect::<String>();
 7578                    }
 7579
 7580                    cx.emit(EditorEvent::InputHandled {
 7581                        utf16_range_to_replace: None,
 7582                        text: partial_completion.clone().into(),
 7583                    });
 7584
 7585                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7586
 7587                    self.refresh_edit_prediction(true, true, window, cx);
 7588                    cx.notify();
 7589                } else {
 7590                    self.accept_edit_prediction(&Default::default(), window, cx);
 7591                }
 7592            }
 7593        }
 7594    }
 7595
 7596    fn discard_edit_prediction(
 7597        &mut self,
 7598        should_report_edit_prediction_event: bool,
 7599        cx: &mut Context<Self>,
 7600    ) -> bool {
 7601        if should_report_edit_prediction_event {
 7602            let completion_id = self
 7603                .active_edit_prediction
 7604                .as_ref()
 7605                .and_then(|active_completion| active_completion.completion_id.clone());
 7606
 7607            self.report_edit_prediction_event(completion_id, false, cx);
 7608        }
 7609
 7610        if let Some(provider) = self.edit_prediction_provider() {
 7611            provider.discard(cx);
 7612        }
 7613
 7614        self.take_active_edit_prediction(cx)
 7615    }
 7616
 7617    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7618        let Some(provider) = self.edit_prediction_provider() else {
 7619            return;
 7620        };
 7621
 7622        let Some((_, buffer, _)) = self
 7623            .buffer
 7624            .read(cx)
 7625            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7626        else {
 7627            return;
 7628        };
 7629
 7630        let extension = buffer
 7631            .read(cx)
 7632            .file()
 7633            .and_then(|file| Some(file.path().extension()?.to_string()));
 7634
 7635        let event_type = match accepted {
 7636            true => "Edit Prediction Accepted",
 7637            false => "Edit Prediction Discarded",
 7638        };
 7639        telemetry::event!(
 7640            event_type,
 7641            provider = provider.name(),
 7642            prediction_id = id,
 7643            suggestion_accepted = accepted,
 7644            file_extension = extension,
 7645        );
 7646    }
 7647
 7648    fn open_editor_at_anchor(
 7649        snapshot: &language::BufferSnapshot,
 7650        target: language::Anchor,
 7651        workspace: &Entity<Workspace>,
 7652        window: &mut Window,
 7653        cx: &mut App,
 7654    ) -> Task<Result<()>> {
 7655        workspace.update(cx, |workspace, cx| {
 7656            let path = snapshot.file().map(|file| file.full_path(cx));
 7657            let Some(path) =
 7658                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7659            else {
 7660                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7661            };
 7662            let target = text::ToPoint::to_point(&target, snapshot);
 7663            let item = workspace.open_path(path, None, true, window, cx);
 7664            window.spawn(cx, async move |cx| {
 7665                let Some(editor) = item.await?.downcast::<Editor>() else {
 7666                    return Ok(());
 7667                };
 7668                editor
 7669                    .update_in(cx, |editor, window, cx| {
 7670                        editor.go_to_singleton_buffer_point(target, window, cx);
 7671                    })
 7672                    .ok();
 7673                anyhow::Ok(())
 7674            })
 7675        })
 7676    }
 7677
 7678    pub fn has_active_edit_prediction(&self) -> bool {
 7679        self.active_edit_prediction.is_some()
 7680    }
 7681
 7682    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7683        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7684            return false;
 7685        };
 7686
 7687        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7688        self.clear_highlights::<EditPredictionHighlight>(cx);
 7689        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7690        true
 7691    }
 7692
 7693    /// Returns true when we're displaying the edit prediction popover below the cursor
 7694    /// like we are not previewing and the LSP autocomplete menu is visible
 7695    /// or we are in `when_holding_modifier` mode.
 7696    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7697        if self.edit_prediction_preview_is_active()
 7698            || !self.show_edit_predictions_in_menu()
 7699            || !self.edit_predictions_enabled()
 7700        {
 7701            return false;
 7702        }
 7703
 7704        if self.has_visible_completions_menu() {
 7705            return true;
 7706        }
 7707
 7708        has_completion && self.edit_prediction_requires_modifier()
 7709    }
 7710
 7711    fn handle_modifiers_changed(
 7712        &mut self,
 7713        modifiers: Modifiers,
 7714        position_map: &PositionMap,
 7715        window: &mut Window,
 7716        cx: &mut Context<Self>,
 7717    ) {
 7718        if self.show_edit_predictions_in_menu() {
 7719            self.update_edit_prediction_preview(&modifiers, window, cx);
 7720        }
 7721
 7722        self.update_selection_mode(&modifiers, position_map, window, cx);
 7723
 7724        let mouse_position = window.mouse_position();
 7725        if !position_map.text_hitbox.is_hovered(window) {
 7726            return;
 7727        }
 7728
 7729        self.update_hovered_link(
 7730            position_map.point_for_position(mouse_position),
 7731            &position_map.snapshot,
 7732            modifiers,
 7733            window,
 7734            cx,
 7735        )
 7736    }
 7737
 7738    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7739        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7740        if invert {
 7741            match multi_cursor_setting {
 7742                MultiCursorModifier::Alt => modifiers.alt,
 7743                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7744            }
 7745        } else {
 7746            match multi_cursor_setting {
 7747                MultiCursorModifier::Alt => modifiers.secondary(),
 7748                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7749            }
 7750        }
 7751    }
 7752
 7753    fn columnar_selection_mode(
 7754        modifiers: &Modifiers,
 7755        cx: &mut Context<Self>,
 7756    ) -> Option<ColumnarMode> {
 7757        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7758            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7759                Some(ColumnarMode::FromMouse)
 7760            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7761                Some(ColumnarMode::FromSelection)
 7762            } else {
 7763                None
 7764            }
 7765        } else {
 7766            None
 7767        }
 7768    }
 7769
 7770    fn update_selection_mode(
 7771        &mut self,
 7772        modifiers: &Modifiers,
 7773        position_map: &PositionMap,
 7774        window: &mut Window,
 7775        cx: &mut Context<Self>,
 7776    ) {
 7777        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7778            return;
 7779        };
 7780        if self.selections.pending_anchor().is_none() {
 7781            return;
 7782        }
 7783
 7784        let mouse_position = window.mouse_position();
 7785        let point_for_position = position_map.point_for_position(mouse_position);
 7786        let position = point_for_position.previous_valid;
 7787
 7788        self.select(
 7789            SelectPhase::BeginColumnar {
 7790                position,
 7791                reset: false,
 7792                mode,
 7793                goal_column: point_for_position.exact_unclipped.column(),
 7794            },
 7795            window,
 7796            cx,
 7797        );
 7798    }
 7799
 7800    fn update_edit_prediction_preview(
 7801        &mut self,
 7802        modifiers: &Modifiers,
 7803        window: &mut Window,
 7804        cx: &mut Context<Self>,
 7805    ) {
 7806        let mut modifiers_held = false;
 7807        if let Some(accept_keystroke) = self
 7808            .accept_edit_prediction_keybind(false, window, cx)
 7809            .keystroke()
 7810        {
 7811            modifiers_held = modifiers_held
 7812                || (accept_keystroke.modifiers() == modifiers
 7813                    && accept_keystroke.modifiers().modified());
 7814        };
 7815        if let Some(accept_partial_keystroke) = self
 7816            .accept_edit_prediction_keybind(true, window, cx)
 7817            .keystroke()
 7818        {
 7819            modifiers_held = modifiers_held
 7820                || (accept_partial_keystroke.modifiers() == modifiers
 7821                    && accept_partial_keystroke.modifiers().modified());
 7822        }
 7823
 7824        if modifiers_held {
 7825            if matches!(
 7826                self.edit_prediction_preview,
 7827                EditPredictionPreview::Inactive { .. }
 7828            ) {
 7829                self.edit_prediction_preview = EditPredictionPreview::Active {
 7830                    previous_scroll_position: None,
 7831                    since: Instant::now(),
 7832                };
 7833
 7834                self.update_visible_edit_prediction(window, cx);
 7835                cx.notify();
 7836            }
 7837        } else if let EditPredictionPreview::Active {
 7838            previous_scroll_position,
 7839            since,
 7840        } = self.edit_prediction_preview
 7841        {
 7842            if let (Some(previous_scroll_position), Some(position_map)) =
 7843                (previous_scroll_position, self.last_position_map.as_ref())
 7844            {
 7845                self.set_scroll_position(
 7846                    previous_scroll_position
 7847                        .scroll_position(&position_map.snapshot.display_snapshot),
 7848                    window,
 7849                    cx,
 7850                );
 7851            }
 7852
 7853            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7854                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7855            };
 7856            self.clear_row_highlights::<EditPredictionPreview>();
 7857            self.update_visible_edit_prediction(window, cx);
 7858            cx.notify();
 7859        }
 7860    }
 7861
 7862    fn update_visible_edit_prediction(
 7863        &mut self,
 7864        _window: &mut Window,
 7865        cx: &mut Context<Self>,
 7866    ) -> Option<()> {
 7867        if DisableAiSettings::get_global(cx).disable_ai {
 7868            return None;
 7869        }
 7870
 7871        if self.ime_transaction.is_some() {
 7872            self.discard_edit_prediction(false, cx);
 7873            return None;
 7874        }
 7875
 7876        let selection = self.selections.newest_anchor();
 7877        let cursor = selection.head();
 7878        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7879        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7880        let excerpt_id = cursor.excerpt_id;
 7881
 7882        let show_in_menu = self.show_edit_predictions_in_menu();
 7883        let completions_menu_has_precedence = !show_in_menu
 7884            && (self.context_menu.borrow().is_some()
 7885                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7886
 7887        if completions_menu_has_precedence
 7888            || !offset_selection.is_empty()
 7889            || self
 7890                .active_edit_prediction
 7891                .as_ref()
 7892                .is_some_and(|completion| {
 7893                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7894                        return false;
 7895                    };
 7896                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7897                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7898                    !invalidation_range.contains(&offset_selection.head())
 7899                })
 7900        {
 7901            self.discard_edit_prediction(false, cx);
 7902            return None;
 7903        }
 7904
 7905        self.take_active_edit_prediction(cx);
 7906        let Some(provider) = self.edit_prediction_provider() else {
 7907            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7908            return None;
 7909        };
 7910
 7911        let (buffer, cursor_buffer_position) =
 7912            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7913
 7914        self.edit_prediction_settings =
 7915            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7916
 7917        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7918
 7919        if self.edit_prediction_indent_conflict {
 7920            let cursor_point = cursor.to_point(&multibuffer);
 7921
 7922            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7923
 7924            if let Some((_, indent)) = indents.iter().next()
 7925                && indent.len == cursor_point.column
 7926            {
 7927                self.edit_prediction_indent_conflict = false;
 7928            }
 7929        }
 7930
 7931        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7932
 7933        let (completion_id, edits, edit_preview) = match edit_prediction {
 7934            edit_prediction::EditPrediction::Local {
 7935                id,
 7936                edits,
 7937                edit_preview,
 7938            } => (id, edits, edit_preview),
 7939            edit_prediction::EditPrediction::Jump {
 7940                id,
 7941                snapshot,
 7942                target,
 7943            } => {
 7944                self.stale_edit_prediction_in_menu = None;
 7945                self.active_edit_prediction = Some(EditPredictionState {
 7946                    inlay_ids: vec![],
 7947                    completion: EditPrediction::MoveOutside { snapshot, target },
 7948                    completion_id: id,
 7949                    invalidation_range: None,
 7950                });
 7951                cx.notify();
 7952                return Some(());
 7953            }
 7954        };
 7955
 7956        let edits = edits
 7957            .into_iter()
 7958            .flat_map(|(range, new_text)| {
 7959                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7960                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7961                Some((start..end, new_text))
 7962            })
 7963            .collect::<Vec<_>>();
 7964        if edits.is_empty() {
 7965            return None;
 7966        }
 7967
 7968        let first_edit_start = edits.first().unwrap().0.start;
 7969        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7970        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7971
 7972        let last_edit_end = edits.last().unwrap().0.end;
 7973        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7974        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7975
 7976        let cursor_row = cursor.to_point(&multibuffer).row;
 7977
 7978        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7979
 7980        let mut inlay_ids = Vec::new();
 7981        let invalidation_row_range;
 7982        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7983            Some(cursor_row..edit_end_row)
 7984        } else if cursor_row > edit_end_row {
 7985            Some(edit_start_row..cursor_row)
 7986        } else {
 7987            None
 7988        };
 7989        let supports_jump = self
 7990            .edit_prediction_provider
 7991            .as_ref()
 7992            .map(|provider| provider.provider.supports_jump_to_edit())
 7993            .unwrap_or(true);
 7994
 7995        let is_move = supports_jump
 7996            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7997        let completion = if is_move {
 7998            invalidation_row_range =
 7999                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8000            let target = first_edit_start;
 8001            EditPrediction::MoveWithin { target, snapshot }
 8002        } else {
 8003            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8004                && !self.edit_predictions_hidden_for_vim_mode;
 8005
 8006            if show_completions_in_buffer {
 8007                if edits
 8008                    .iter()
 8009                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8010                {
 8011                    let mut inlays = Vec::new();
 8012                    for (range, new_text) in &edits {
 8013                        let inlay = Inlay::edit_prediction(
 8014                            post_inc(&mut self.next_inlay_id),
 8015                            range.start,
 8016                            new_text.as_str(),
 8017                        );
 8018                        inlay_ids.push(inlay.id);
 8019                        inlays.push(inlay);
 8020                    }
 8021
 8022                    self.splice_inlays(&[], inlays, cx);
 8023                } else {
 8024                    let background_color = cx.theme().status().deleted_background;
 8025                    self.highlight_text::<EditPredictionHighlight>(
 8026                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8027                        HighlightStyle {
 8028                            background_color: Some(background_color),
 8029                            ..Default::default()
 8030                        },
 8031                        cx,
 8032                    );
 8033                }
 8034            }
 8035
 8036            invalidation_row_range = edit_start_row..edit_end_row;
 8037
 8038            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8039                if provider.show_tab_accept_marker() {
 8040                    EditDisplayMode::TabAccept
 8041                } else {
 8042                    EditDisplayMode::Inline
 8043                }
 8044            } else {
 8045                EditDisplayMode::DiffPopover
 8046            };
 8047
 8048            EditPrediction::Edit {
 8049                edits,
 8050                edit_preview,
 8051                display_mode,
 8052                snapshot,
 8053            }
 8054        };
 8055
 8056        let invalidation_range = multibuffer
 8057            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8058            ..multibuffer.anchor_after(Point::new(
 8059                invalidation_row_range.end,
 8060                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8061            ));
 8062
 8063        self.stale_edit_prediction_in_menu = None;
 8064        self.active_edit_prediction = Some(EditPredictionState {
 8065            inlay_ids,
 8066            completion,
 8067            completion_id,
 8068            invalidation_range: Some(invalidation_range),
 8069        });
 8070
 8071        cx.notify();
 8072
 8073        Some(())
 8074    }
 8075
 8076    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8077        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8078    }
 8079
 8080    fn clear_tasks(&mut self) {
 8081        self.tasks.clear()
 8082    }
 8083
 8084    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8085        if self.tasks.insert(key, value).is_some() {
 8086            // This case should hopefully be rare, but just in case...
 8087            log::error!(
 8088                "multiple different run targets found on a single line, only the last target will be rendered"
 8089            )
 8090        }
 8091    }
 8092
 8093    /// Get all display points of breakpoints that will be rendered within editor
 8094    ///
 8095    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8096    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8097    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8098    fn active_breakpoints(
 8099        &self,
 8100        range: Range<DisplayRow>,
 8101        window: &mut Window,
 8102        cx: &mut Context<Self>,
 8103    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8104        let mut breakpoint_display_points = HashMap::default();
 8105
 8106        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8107            return breakpoint_display_points;
 8108        };
 8109
 8110        let snapshot = self.snapshot(window, cx);
 8111
 8112        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8113        let Some(project) = self.project() else {
 8114            return breakpoint_display_points;
 8115        };
 8116
 8117        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8118            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8119
 8120        for (buffer_snapshot, range, excerpt_id) in
 8121            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8122        {
 8123            let Some(buffer) = project
 8124                .read(cx)
 8125                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8126            else {
 8127                continue;
 8128            };
 8129            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8130                &buffer,
 8131                Some(
 8132                    buffer_snapshot.anchor_before(range.start)
 8133                        ..buffer_snapshot.anchor_after(range.end),
 8134                ),
 8135                buffer_snapshot,
 8136                cx,
 8137            );
 8138            for (breakpoint, state) in breakpoints {
 8139                let multi_buffer_anchor =
 8140                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8141                let position = multi_buffer_anchor
 8142                    .to_point(multi_buffer_snapshot)
 8143                    .to_display_point(&snapshot);
 8144
 8145                breakpoint_display_points.insert(
 8146                    position.row(),
 8147                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8148                );
 8149            }
 8150        }
 8151
 8152        breakpoint_display_points
 8153    }
 8154
 8155    fn breakpoint_context_menu(
 8156        &self,
 8157        anchor: Anchor,
 8158        window: &mut Window,
 8159        cx: &mut Context<Self>,
 8160    ) -> Entity<ui::ContextMenu> {
 8161        let weak_editor = cx.weak_entity();
 8162        let focus_handle = self.focus_handle(cx);
 8163
 8164        let row = self
 8165            .buffer
 8166            .read(cx)
 8167            .snapshot(cx)
 8168            .summary_for_anchor::<Point>(&anchor)
 8169            .row;
 8170
 8171        let breakpoint = self
 8172            .breakpoint_at_row(row, window, cx)
 8173            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8174
 8175        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8176            "Edit Log Breakpoint"
 8177        } else {
 8178            "Set Log Breakpoint"
 8179        };
 8180
 8181        let condition_breakpoint_msg = if breakpoint
 8182            .as_ref()
 8183            .is_some_and(|bp| bp.1.condition.is_some())
 8184        {
 8185            "Edit Condition Breakpoint"
 8186        } else {
 8187            "Set Condition Breakpoint"
 8188        };
 8189
 8190        let hit_condition_breakpoint_msg = if breakpoint
 8191            .as_ref()
 8192            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8193        {
 8194            "Edit Hit Condition Breakpoint"
 8195        } else {
 8196            "Set Hit Condition Breakpoint"
 8197        };
 8198
 8199        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8200            "Unset Breakpoint"
 8201        } else {
 8202            "Set Breakpoint"
 8203        };
 8204
 8205        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8206
 8207        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8208            BreakpointState::Enabled => Some("Disable"),
 8209            BreakpointState::Disabled => Some("Enable"),
 8210        });
 8211
 8212        let (anchor, breakpoint) =
 8213            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8214
 8215        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8216            menu.on_blur_subscription(Subscription::new(|| {}))
 8217                .context(focus_handle)
 8218                .when(run_to_cursor, |this| {
 8219                    let weak_editor = weak_editor.clone();
 8220                    this.entry("Run to cursor", None, move |window, cx| {
 8221                        weak_editor
 8222                            .update(cx, |editor, cx| {
 8223                                editor.change_selections(
 8224                                    SelectionEffects::no_scroll(),
 8225                                    window,
 8226                                    cx,
 8227                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8228                                );
 8229                            })
 8230                            .ok();
 8231
 8232                        window.dispatch_action(Box::new(RunToCursor), cx);
 8233                    })
 8234                    .separator()
 8235                })
 8236                .when_some(toggle_state_msg, |this, msg| {
 8237                    this.entry(msg, None, {
 8238                        let weak_editor = weak_editor.clone();
 8239                        let breakpoint = breakpoint.clone();
 8240                        move |_window, cx| {
 8241                            weak_editor
 8242                                .update(cx, |this, cx| {
 8243                                    this.edit_breakpoint_at_anchor(
 8244                                        anchor,
 8245                                        breakpoint.as_ref().clone(),
 8246                                        BreakpointEditAction::InvertState,
 8247                                        cx,
 8248                                    );
 8249                                })
 8250                                .log_err();
 8251                        }
 8252                    })
 8253                })
 8254                .entry(set_breakpoint_msg, None, {
 8255                    let weak_editor = weak_editor.clone();
 8256                    let breakpoint = breakpoint.clone();
 8257                    move |_window, cx| {
 8258                        weak_editor
 8259                            .update(cx, |this, cx| {
 8260                                this.edit_breakpoint_at_anchor(
 8261                                    anchor,
 8262                                    breakpoint.as_ref().clone(),
 8263                                    BreakpointEditAction::Toggle,
 8264                                    cx,
 8265                                );
 8266                            })
 8267                            .log_err();
 8268                    }
 8269                })
 8270                .entry(log_breakpoint_msg, None, {
 8271                    let breakpoint = breakpoint.clone();
 8272                    let weak_editor = weak_editor.clone();
 8273                    move |window, cx| {
 8274                        weak_editor
 8275                            .update(cx, |this, cx| {
 8276                                this.add_edit_breakpoint_block(
 8277                                    anchor,
 8278                                    breakpoint.as_ref(),
 8279                                    BreakpointPromptEditAction::Log,
 8280                                    window,
 8281                                    cx,
 8282                                );
 8283                            })
 8284                            .log_err();
 8285                    }
 8286                })
 8287                .entry(condition_breakpoint_msg, None, {
 8288                    let breakpoint = breakpoint.clone();
 8289                    let weak_editor = weak_editor.clone();
 8290                    move |window, cx| {
 8291                        weak_editor
 8292                            .update(cx, |this, cx| {
 8293                                this.add_edit_breakpoint_block(
 8294                                    anchor,
 8295                                    breakpoint.as_ref(),
 8296                                    BreakpointPromptEditAction::Condition,
 8297                                    window,
 8298                                    cx,
 8299                                );
 8300                            })
 8301                            .log_err();
 8302                    }
 8303                })
 8304                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8305                    weak_editor
 8306                        .update(cx, |this, cx| {
 8307                            this.add_edit_breakpoint_block(
 8308                                anchor,
 8309                                breakpoint.as_ref(),
 8310                                BreakpointPromptEditAction::HitCondition,
 8311                                window,
 8312                                cx,
 8313                            );
 8314                        })
 8315                        .log_err();
 8316                })
 8317        })
 8318    }
 8319
 8320    fn render_breakpoint(
 8321        &self,
 8322        position: Anchor,
 8323        row: DisplayRow,
 8324        breakpoint: &Breakpoint,
 8325        state: Option<BreakpointSessionState>,
 8326        cx: &mut Context<Self>,
 8327    ) -> IconButton {
 8328        let is_rejected = state.is_some_and(|s| !s.verified);
 8329        // Is it a breakpoint that shows up when hovering over gutter?
 8330        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8331            (false, false),
 8332            |PhantomBreakpointIndicator {
 8333                 is_active,
 8334                 display_row,
 8335                 collides_with_existing_breakpoint,
 8336             }| {
 8337                (
 8338                    is_active && display_row == row,
 8339                    collides_with_existing_breakpoint,
 8340                )
 8341            },
 8342        );
 8343
 8344        let (color, icon) = {
 8345            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8346                (false, false) => ui::IconName::DebugBreakpoint,
 8347                (true, false) => ui::IconName::DebugLogBreakpoint,
 8348                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8349                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8350            };
 8351
 8352            let color = if is_phantom {
 8353                Color::Hint
 8354            } else if is_rejected {
 8355                Color::Disabled
 8356            } else {
 8357                Color::Debugger
 8358            };
 8359
 8360            (color, icon)
 8361        };
 8362
 8363        let breakpoint = Arc::from(breakpoint.clone());
 8364
 8365        let alt_as_text = gpui::Keystroke {
 8366            modifiers: Modifiers::secondary_key(),
 8367            ..Default::default()
 8368        };
 8369        let primary_action_text = if breakpoint.is_disabled() {
 8370            "Enable breakpoint"
 8371        } else if is_phantom && !collides_with_existing {
 8372            "Set breakpoint"
 8373        } else {
 8374            "Unset breakpoint"
 8375        };
 8376        let focus_handle = self.focus_handle.clone();
 8377
 8378        let meta = if is_rejected {
 8379            SharedString::from("No executable code is associated with this line.")
 8380        } else if collides_with_existing && !breakpoint.is_disabled() {
 8381            SharedString::from(format!(
 8382                "{alt_as_text}-click to disable,\nright-click for more options."
 8383            ))
 8384        } else {
 8385            SharedString::from("Right-click for more options.")
 8386        };
 8387        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8388            .icon_size(IconSize::XSmall)
 8389            .size(ui::ButtonSize::None)
 8390            .when(is_rejected, |this| {
 8391                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8392            })
 8393            .icon_color(color)
 8394            .style(ButtonStyle::Transparent)
 8395            .on_click(cx.listener({
 8396                move |editor, event: &ClickEvent, window, cx| {
 8397                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8398                        BreakpointEditAction::InvertState
 8399                    } else {
 8400                        BreakpointEditAction::Toggle
 8401                    };
 8402
 8403                    window.focus(&editor.focus_handle(cx));
 8404                    editor.edit_breakpoint_at_anchor(
 8405                        position,
 8406                        breakpoint.as_ref().clone(),
 8407                        edit_action,
 8408                        cx,
 8409                    );
 8410                }
 8411            }))
 8412            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8413                editor.set_breakpoint_context_menu(
 8414                    row,
 8415                    Some(position),
 8416                    event.position(),
 8417                    window,
 8418                    cx,
 8419                );
 8420            }))
 8421            .tooltip(move |window, cx| {
 8422                Tooltip::with_meta_in(
 8423                    primary_action_text,
 8424                    Some(&ToggleBreakpoint),
 8425                    meta.clone(),
 8426                    &focus_handle,
 8427                    window,
 8428                    cx,
 8429                )
 8430            })
 8431    }
 8432
 8433    fn build_tasks_context(
 8434        project: &Entity<Project>,
 8435        buffer: &Entity<Buffer>,
 8436        buffer_row: u32,
 8437        tasks: &Arc<RunnableTasks>,
 8438        cx: &mut Context<Self>,
 8439    ) -> Task<Option<task::TaskContext>> {
 8440        let position = Point::new(buffer_row, tasks.column);
 8441        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8442        let location = Location {
 8443            buffer: buffer.clone(),
 8444            range: range_start..range_start,
 8445        };
 8446        // Fill in the environmental variables from the tree-sitter captures
 8447        let mut captured_task_variables = TaskVariables::default();
 8448        for (capture_name, value) in tasks.extra_variables.clone() {
 8449            captured_task_variables.insert(
 8450                task::VariableName::Custom(capture_name.into()),
 8451                value.clone(),
 8452            );
 8453        }
 8454        project.update(cx, |project, cx| {
 8455            project.task_store().update(cx, |task_store, cx| {
 8456                task_store.task_context_for_location(captured_task_variables, location, cx)
 8457            })
 8458        })
 8459    }
 8460
 8461    pub fn spawn_nearest_task(
 8462        &mut self,
 8463        action: &SpawnNearestTask,
 8464        window: &mut Window,
 8465        cx: &mut Context<Self>,
 8466    ) {
 8467        let Some((workspace, _)) = self.workspace.clone() else {
 8468            return;
 8469        };
 8470        let Some(project) = self.project.clone() else {
 8471            return;
 8472        };
 8473
 8474        // Try to find a closest, enclosing node using tree-sitter that has a task
 8475        let Some((buffer, buffer_row, tasks)) = self
 8476            .find_enclosing_node_task(cx)
 8477            // Or find the task that's closest in row-distance.
 8478            .or_else(|| self.find_closest_task(cx))
 8479        else {
 8480            return;
 8481        };
 8482
 8483        let reveal_strategy = action.reveal;
 8484        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8485        cx.spawn_in(window, async move |_, cx| {
 8486            let context = task_context.await?;
 8487            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8488
 8489            let resolved = &mut resolved_task.resolved;
 8490            resolved.reveal = reveal_strategy;
 8491
 8492            workspace
 8493                .update_in(cx, |workspace, window, cx| {
 8494                    workspace.schedule_resolved_task(
 8495                        task_source_kind,
 8496                        resolved_task,
 8497                        false,
 8498                        window,
 8499                        cx,
 8500                    );
 8501                })
 8502                .ok()
 8503        })
 8504        .detach();
 8505    }
 8506
 8507    fn find_closest_task(
 8508        &mut self,
 8509        cx: &mut Context<Self>,
 8510    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8511        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8512
 8513        let ((buffer_id, row), tasks) = self
 8514            .tasks
 8515            .iter()
 8516            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8517
 8518        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8519        let tasks = Arc::new(tasks.to_owned());
 8520        Some((buffer, *row, tasks))
 8521    }
 8522
 8523    fn find_enclosing_node_task(
 8524        &mut self,
 8525        cx: &mut Context<Self>,
 8526    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8527        let snapshot = self.buffer.read(cx).snapshot(cx);
 8528        let offset = self.selections.newest::<usize>(cx).head();
 8529        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8530        let buffer_id = excerpt.buffer().remote_id();
 8531
 8532        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8533        let mut cursor = layer.node().walk();
 8534
 8535        while cursor.goto_first_child_for_byte(offset).is_some() {
 8536            if cursor.node().end_byte() == offset {
 8537                cursor.goto_next_sibling();
 8538            }
 8539        }
 8540
 8541        // Ascend to the smallest ancestor that contains the range and has a task.
 8542        loop {
 8543            let node = cursor.node();
 8544            let node_range = node.byte_range();
 8545            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8546
 8547            // Check if this node contains our offset
 8548            if node_range.start <= offset && node_range.end >= offset {
 8549                // If it contains offset, check for task
 8550                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8551                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8552                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8553                }
 8554            }
 8555
 8556            if !cursor.goto_parent() {
 8557                break;
 8558            }
 8559        }
 8560        None
 8561    }
 8562
 8563    fn render_run_indicator(
 8564        &self,
 8565        _style: &EditorStyle,
 8566        is_active: bool,
 8567        row: DisplayRow,
 8568        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8569        cx: &mut Context<Self>,
 8570    ) -> IconButton {
 8571        let color = Color::Muted;
 8572        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8573
 8574        IconButton::new(
 8575            ("run_indicator", row.0 as usize),
 8576            ui::IconName::PlayOutlined,
 8577        )
 8578        .shape(ui::IconButtonShape::Square)
 8579        .icon_size(IconSize::XSmall)
 8580        .icon_color(color)
 8581        .toggle_state(is_active)
 8582        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8583            let quick_launch = match e {
 8584                ClickEvent::Keyboard(_) => true,
 8585                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8586            };
 8587
 8588            window.focus(&editor.focus_handle(cx));
 8589            editor.toggle_code_actions(
 8590                &ToggleCodeActions {
 8591                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8592                    quick_launch,
 8593                },
 8594                window,
 8595                cx,
 8596            );
 8597        }))
 8598        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8599            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8600        }))
 8601    }
 8602
 8603    pub fn context_menu_visible(&self) -> bool {
 8604        !self.edit_prediction_preview_is_active()
 8605            && self
 8606                .context_menu
 8607                .borrow()
 8608                .as_ref()
 8609                .is_some_and(|menu| menu.visible())
 8610    }
 8611
 8612    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8613        self.context_menu
 8614            .borrow()
 8615            .as_ref()
 8616            .map(|menu| menu.origin())
 8617    }
 8618
 8619    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8620        self.context_menu_options = Some(options);
 8621    }
 8622
 8623    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8624    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8625
 8626    fn render_edit_prediction_popover(
 8627        &mut self,
 8628        text_bounds: &Bounds<Pixels>,
 8629        content_origin: gpui::Point<Pixels>,
 8630        right_margin: Pixels,
 8631        editor_snapshot: &EditorSnapshot,
 8632        visible_row_range: Range<DisplayRow>,
 8633        scroll_top: ScrollOffset,
 8634        scroll_bottom: ScrollOffset,
 8635        line_layouts: &[LineWithInvisibles],
 8636        line_height: Pixels,
 8637        scroll_position: gpui::Point<ScrollOffset>,
 8638        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8639        newest_selection_head: Option<DisplayPoint>,
 8640        editor_width: Pixels,
 8641        style: &EditorStyle,
 8642        window: &mut Window,
 8643        cx: &mut App,
 8644    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8645        if self.mode().is_minimap() {
 8646            return None;
 8647        }
 8648        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8649
 8650        if self.edit_prediction_visible_in_cursor_popover(true) {
 8651            return None;
 8652        }
 8653
 8654        match &active_edit_prediction.completion {
 8655            EditPrediction::MoveWithin { target, .. } => {
 8656                let target_display_point = target.to_display_point(editor_snapshot);
 8657
 8658                if self.edit_prediction_requires_modifier() {
 8659                    if !self.edit_prediction_preview_is_active() {
 8660                        return None;
 8661                    }
 8662
 8663                    self.render_edit_prediction_modifier_jump_popover(
 8664                        text_bounds,
 8665                        content_origin,
 8666                        visible_row_range,
 8667                        line_layouts,
 8668                        line_height,
 8669                        scroll_pixel_position,
 8670                        newest_selection_head,
 8671                        target_display_point,
 8672                        window,
 8673                        cx,
 8674                    )
 8675                } else {
 8676                    self.render_edit_prediction_eager_jump_popover(
 8677                        text_bounds,
 8678                        content_origin,
 8679                        editor_snapshot,
 8680                        visible_row_range,
 8681                        scroll_top,
 8682                        scroll_bottom,
 8683                        line_height,
 8684                        scroll_pixel_position,
 8685                        target_display_point,
 8686                        editor_width,
 8687                        window,
 8688                        cx,
 8689                    )
 8690                }
 8691            }
 8692            EditPrediction::Edit {
 8693                display_mode: EditDisplayMode::Inline,
 8694                ..
 8695            } => None,
 8696            EditPrediction::Edit {
 8697                display_mode: EditDisplayMode::TabAccept,
 8698                edits,
 8699                ..
 8700            } => {
 8701                let range = &edits.first()?.0;
 8702                let target_display_point = range.end.to_display_point(editor_snapshot);
 8703
 8704                self.render_edit_prediction_end_of_line_popover(
 8705                    "Accept",
 8706                    editor_snapshot,
 8707                    visible_row_range,
 8708                    target_display_point,
 8709                    line_height,
 8710                    scroll_pixel_position,
 8711                    content_origin,
 8712                    editor_width,
 8713                    window,
 8714                    cx,
 8715                )
 8716            }
 8717            EditPrediction::Edit {
 8718                edits,
 8719                edit_preview,
 8720                display_mode: EditDisplayMode::DiffPopover,
 8721                snapshot,
 8722            } => self.render_edit_prediction_diff_popover(
 8723                text_bounds,
 8724                content_origin,
 8725                right_margin,
 8726                editor_snapshot,
 8727                visible_row_range,
 8728                line_layouts,
 8729                line_height,
 8730                scroll_position,
 8731                scroll_pixel_position,
 8732                newest_selection_head,
 8733                editor_width,
 8734                style,
 8735                edits,
 8736                edit_preview,
 8737                snapshot,
 8738                window,
 8739                cx,
 8740            ),
 8741            EditPrediction::MoveOutside { snapshot, .. } => {
 8742                let file_name = snapshot
 8743                    .file()
 8744                    .map(|file| file.file_name(cx))
 8745                    .unwrap_or("untitled");
 8746                let mut element = self
 8747                    .render_edit_prediction_line_popover(
 8748                        format!("Jump to {file_name}"),
 8749                        Some(IconName::ZedPredict),
 8750                        window,
 8751                        cx,
 8752                    )
 8753                    .into_any();
 8754
 8755                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8756                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8757                let origin_y = text_bounds.size.height - size.height - px(30.);
 8758                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8759                element.prepaint_at(origin, window, cx);
 8760
 8761                Some((element, origin))
 8762            }
 8763        }
 8764    }
 8765
 8766    fn render_edit_prediction_modifier_jump_popover(
 8767        &mut self,
 8768        text_bounds: &Bounds<Pixels>,
 8769        content_origin: gpui::Point<Pixels>,
 8770        visible_row_range: Range<DisplayRow>,
 8771        line_layouts: &[LineWithInvisibles],
 8772        line_height: Pixels,
 8773        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8774        newest_selection_head: Option<DisplayPoint>,
 8775        target_display_point: DisplayPoint,
 8776        window: &mut Window,
 8777        cx: &mut App,
 8778    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8779        let scrolled_content_origin =
 8780            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8781
 8782        const SCROLL_PADDING_Y: Pixels = px(12.);
 8783
 8784        if target_display_point.row() < visible_row_range.start {
 8785            return self.render_edit_prediction_scroll_popover(
 8786                |_| SCROLL_PADDING_Y,
 8787                IconName::ArrowUp,
 8788                visible_row_range,
 8789                line_layouts,
 8790                newest_selection_head,
 8791                scrolled_content_origin,
 8792                window,
 8793                cx,
 8794            );
 8795        } else if target_display_point.row() >= visible_row_range.end {
 8796            return self.render_edit_prediction_scroll_popover(
 8797                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8798                IconName::ArrowDown,
 8799                visible_row_range,
 8800                line_layouts,
 8801                newest_selection_head,
 8802                scrolled_content_origin,
 8803                window,
 8804                cx,
 8805            );
 8806        }
 8807
 8808        const POLE_WIDTH: Pixels = px(2.);
 8809
 8810        let line_layout =
 8811            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8812        let target_column = target_display_point.column() as usize;
 8813
 8814        let target_x = line_layout.x_for_index(target_column);
 8815        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8816            - scroll_pixel_position.y;
 8817
 8818        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8819
 8820        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8821        border_color.l += 0.001;
 8822
 8823        let mut element = v_flex()
 8824            .items_end()
 8825            .when(flag_on_right, |el| el.items_start())
 8826            .child(if flag_on_right {
 8827                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8828                    .rounded_bl(px(0.))
 8829                    .rounded_tl(px(0.))
 8830                    .border_l_2()
 8831                    .border_color(border_color)
 8832            } else {
 8833                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8834                    .rounded_br(px(0.))
 8835                    .rounded_tr(px(0.))
 8836                    .border_r_2()
 8837                    .border_color(border_color)
 8838            })
 8839            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8840            .into_any();
 8841
 8842        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8843
 8844        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8845            - point(
 8846                if flag_on_right {
 8847                    POLE_WIDTH
 8848                } else {
 8849                    size.width - POLE_WIDTH
 8850                },
 8851                size.height - line_height,
 8852            );
 8853
 8854        origin.x = origin.x.max(content_origin.x);
 8855
 8856        element.prepaint_at(origin, window, cx);
 8857
 8858        Some((element, origin))
 8859    }
 8860
 8861    fn render_edit_prediction_scroll_popover(
 8862        &mut self,
 8863        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8864        scroll_icon: IconName,
 8865        visible_row_range: Range<DisplayRow>,
 8866        line_layouts: &[LineWithInvisibles],
 8867        newest_selection_head: Option<DisplayPoint>,
 8868        scrolled_content_origin: gpui::Point<Pixels>,
 8869        window: &mut Window,
 8870        cx: &mut App,
 8871    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8872        let mut element = self
 8873            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8874            .into_any();
 8875
 8876        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8877
 8878        let cursor = newest_selection_head?;
 8879        let cursor_row_layout =
 8880            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8881        let cursor_column = cursor.column() as usize;
 8882
 8883        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8884
 8885        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8886
 8887        element.prepaint_at(origin, window, cx);
 8888        Some((element, origin))
 8889    }
 8890
 8891    fn render_edit_prediction_eager_jump_popover(
 8892        &mut self,
 8893        text_bounds: &Bounds<Pixels>,
 8894        content_origin: gpui::Point<Pixels>,
 8895        editor_snapshot: &EditorSnapshot,
 8896        visible_row_range: Range<DisplayRow>,
 8897        scroll_top: ScrollOffset,
 8898        scroll_bottom: ScrollOffset,
 8899        line_height: Pixels,
 8900        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8901        target_display_point: DisplayPoint,
 8902        editor_width: Pixels,
 8903        window: &mut Window,
 8904        cx: &mut App,
 8905    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8906        if target_display_point.row().as_f64() < scroll_top {
 8907            let mut element = self
 8908                .render_edit_prediction_line_popover(
 8909                    "Jump to Edit",
 8910                    Some(IconName::ArrowUp),
 8911                    window,
 8912                    cx,
 8913                )
 8914                .into_any();
 8915
 8916            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8917            let offset = point(
 8918                (text_bounds.size.width - size.width) / 2.,
 8919                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8920            );
 8921
 8922            let origin = text_bounds.origin + offset;
 8923            element.prepaint_at(origin, window, cx);
 8924            Some((element, origin))
 8925        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8926            let mut element = self
 8927                .render_edit_prediction_line_popover(
 8928                    "Jump to Edit",
 8929                    Some(IconName::ArrowDown),
 8930                    window,
 8931                    cx,
 8932                )
 8933                .into_any();
 8934
 8935            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8936            let offset = point(
 8937                (text_bounds.size.width - size.width) / 2.,
 8938                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8939            );
 8940
 8941            let origin = text_bounds.origin + offset;
 8942            element.prepaint_at(origin, window, cx);
 8943            Some((element, origin))
 8944        } else {
 8945            self.render_edit_prediction_end_of_line_popover(
 8946                "Jump to Edit",
 8947                editor_snapshot,
 8948                visible_row_range,
 8949                target_display_point,
 8950                line_height,
 8951                scroll_pixel_position,
 8952                content_origin,
 8953                editor_width,
 8954                window,
 8955                cx,
 8956            )
 8957        }
 8958    }
 8959
 8960    fn render_edit_prediction_end_of_line_popover(
 8961        self: &mut Editor,
 8962        label: &'static str,
 8963        editor_snapshot: &EditorSnapshot,
 8964        visible_row_range: Range<DisplayRow>,
 8965        target_display_point: DisplayPoint,
 8966        line_height: Pixels,
 8967        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8968        content_origin: gpui::Point<Pixels>,
 8969        editor_width: Pixels,
 8970        window: &mut Window,
 8971        cx: &mut App,
 8972    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8973        let target_line_end = DisplayPoint::new(
 8974            target_display_point.row(),
 8975            editor_snapshot.line_len(target_display_point.row()),
 8976        );
 8977
 8978        let mut element = self
 8979            .render_edit_prediction_line_popover(label, None, window, cx)
 8980            .into_any();
 8981
 8982        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8983
 8984        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8985
 8986        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8987        let mut origin = start_point
 8988            + line_origin
 8989            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8990        origin.x = origin.x.max(content_origin.x);
 8991
 8992        let max_x = content_origin.x + editor_width - size.width;
 8993
 8994        if origin.x > max_x {
 8995            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8996
 8997            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8998                origin.y += offset;
 8999                IconName::ArrowUp
 9000            } else {
 9001                origin.y -= offset;
 9002                IconName::ArrowDown
 9003            };
 9004
 9005            element = self
 9006                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9007                .into_any();
 9008
 9009            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9010
 9011            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9012        }
 9013
 9014        element.prepaint_at(origin, window, cx);
 9015        Some((element, origin))
 9016    }
 9017
 9018    fn render_edit_prediction_diff_popover(
 9019        self: &Editor,
 9020        text_bounds: &Bounds<Pixels>,
 9021        content_origin: gpui::Point<Pixels>,
 9022        right_margin: Pixels,
 9023        editor_snapshot: &EditorSnapshot,
 9024        visible_row_range: Range<DisplayRow>,
 9025        line_layouts: &[LineWithInvisibles],
 9026        line_height: Pixels,
 9027        scroll_position: gpui::Point<ScrollOffset>,
 9028        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9029        newest_selection_head: Option<DisplayPoint>,
 9030        editor_width: Pixels,
 9031        style: &EditorStyle,
 9032        edits: &Vec<(Range<Anchor>, String)>,
 9033        edit_preview: &Option<language::EditPreview>,
 9034        snapshot: &language::BufferSnapshot,
 9035        window: &mut Window,
 9036        cx: &mut App,
 9037    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9038        let edit_start = edits
 9039            .first()
 9040            .unwrap()
 9041            .0
 9042            .start
 9043            .to_display_point(editor_snapshot);
 9044        let edit_end = edits
 9045            .last()
 9046            .unwrap()
 9047            .0
 9048            .end
 9049            .to_display_point(editor_snapshot);
 9050
 9051        let is_visible = visible_row_range.contains(&edit_start.row())
 9052            || visible_row_range.contains(&edit_end.row());
 9053        if !is_visible {
 9054            return None;
 9055        }
 9056
 9057        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9058            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9059        } else {
 9060            // Fallback for providers without edit_preview
 9061            crate::edit_prediction_fallback_text(edits, cx)
 9062        };
 9063
 9064        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9065        let line_count = highlighted_edits.text.lines().count();
 9066
 9067        const BORDER_WIDTH: Pixels = px(1.);
 9068
 9069        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9070        let has_keybind = keybind.is_some();
 9071
 9072        let mut element = h_flex()
 9073            .items_start()
 9074            .child(
 9075                h_flex()
 9076                    .bg(cx.theme().colors().editor_background)
 9077                    .border(BORDER_WIDTH)
 9078                    .shadow_xs()
 9079                    .border_color(cx.theme().colors().border)
 9080                    .rounded_l_lg()
 9081                    .when(line_count > 1, |el| el.rounded_br_lg())
 9082                    .pr_1()
 9083                    .child(styled_text),
 9084            )
 9085            .child(
 9086                h_flex()
 9087                    .h(line_height + BORDER_WIDTH * 2.)
 9088                    .px_1p5()
 9089                    .gap_1()
 9090                    // Workaround: For some reason, there's a gap if we don't do this
 9091                    .ml(-BORDER_WIDTH)
 9092                    .shadow(vec![gpui::BoxShadow {
 9093                        color: gpui::black().opacity(0.05),
 9094                        offset: point(px(1.), px(1.)),
 9095                        blur_radius: px(2.),
 9096                        spread_radius: px(0.),
 9097                    }])
 9098                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9099                    .border(BORDER_WIDTH)
 9100                    .border_color(cx.theme().colors().border)
 9101                    .rounded_r_lg()
 9102                    .id("edit_prediction_diff_popover_keybind")
 9103                    .when(!has_keybind, |el| {
 9104                        let status_colors = cx.theme().status();
 9105
 9106                        el.bg(status_colors.error_background)
 9107                            .border_color(status_colors.error.opacity(0.6))
 9108                            .child(Icon::new(IconName::Info).color(Color::Error))
 9109                            .cursor_default()
 9110                            .hoverable_tooltip(move |_window, cx| {
 9111                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9112                            })
 9113                    })
 9114                    .children(keybind),
 9115            )
 9116            .into_any();
 9117
 9118        let longest_row =
 9119            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9120        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9121            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9122        } else {
 9123            layout_line(
 9124                longest_row,
 9125                editor_snapshot,
 9126                style,
 9127                editor_width,
 9128                |_| false,
 9129                window,
 9130                cx,
 9131            )
 9132            .width
 9133        };
 9134
 9135        let viewport_bounds =
 9136            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9137                right: -right_margin,
 9138                ..Default::default()
 9139            });
 9140
 9141        let x_after_longest = Pixels::from(
 9142            ScrollPixelOffset::from(
 9143                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9144            ) - scroll_pixel_position.x,
 9145        );
 9146
 9147        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9148
 9149        // Fully visible if it can be displayed within the window (allow overlapping other
 9150        // panes). However, this is only allowed if the popover starts within text_bounds.
 9151        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9152            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9153
 9154        let mut origin = if can_position_to_the_right {
 9155            point(
 9156                x_after_longest,
 9157                text_bounds.origin.y
 9158                    + Pixels::from(
 9159                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9160                            - scroll_pixel_position.y,
 9161                    ),
 9162            )
 9163        } else {
 9164            let cursor_row = newest_selection_head.map(|head| head.row());
 9165            let above_edit = edit_start
 9166                .row()
 9167                .0
 9168                .checked_sub(line_count as u32)
 9169                .map(DisplayRow);
 9170            let below_edit = Some(edit_end.row() + 1);
 9171            let above_cursor =
 9172                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9173            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9174
 9175            // Place the edit popover adjacent to the edit if there is a location
 9176            // available that is onscreen and does not obscure the cursor. Otherwise,
 9177            // place it adjacent to the cursor.
 9178            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9179                .into_iter()
 9180                .flatten()
 9181                .find(|&start_row| {
 9182                    let end_row = start_row + line_count as u32;
 9183                    visible_row_range.contains(&start_row)
 9184                        && visible_row_range.contains(&end_row)
 9185                        && cursor_row
 9186                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9187                })?;
 9188
 9189            content_origin
 9190                + point(
 9191                    Pixels::from(-scroll_pixel_position.x),
 9192                    Pixels::from(
 9193                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9194                    ),
 9195                )
 9196        };
 9197
 9198        origin.x -= BORDER_WIDTH;
 9199
 9200        window.defer_draw(element, origin, 1);
 9201
 9202        // Do not return an element, since it will already be drawn due to defer_draw.
 9203        None
 9204    }
 9205
 9206    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9207        px(30.)
 9208    }
 9209
 9210    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9211        if self.read_only(cx) {
 9212            cx.theme().players().read_only()
 9213        } else {
 9214            self.style.as_ref().unwrap().local_player
 9215        }
 9216    }
 9217
 9218    fn render_edit_prediction_accept_keybind(
 9219        &self,
 9220        window: &mut Window,
 9221        cx: &App,
 9222    ) -> Option<AnyElement> {
 9223        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9224        let accept_keystroke = accept_binding.keystroke()?;
 9225
 9226        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9227
 9228        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9229            Color::Accent
 9230        } else {
 9231            Color::Muted
 9232        };
 9233
 9234        h_flex()
 9235            .px_0p5()
 9236            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9237            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9238            .text_size(TextSize::XSmall.rems(cx))
 9239            .child(h_flex().children(ui::render_modifiers(
 9240                accept_keystroke.modifiers(),
 9241                PlatformStyle::platform(),
 9242                Some(modifiers_color),
 9243                Some(IconSize::XSmall.rems().into()),
 9244                true,
 9245            )))
 9246            .when(is_platform_style_mac, |parent| {
 9247                parent.child(accept_keystroke.key().to_string())
 9248            })
 9249            .when(!is_platform_style_mac, |parent| {
 9250                parent.child(
 9251                    Key::new(
 9252                        util::capitalize(accept_keystroke.key()),
 9253                        Some(Color::Default),
 9254                    )
 9255                    .size(Some(IconSize::XSmall.rems().into())),
 9256                )
 9257            })
 9258            .into_any()
 9259            .into()
 9260    }
 9261
 9262    fn render_edit_prediction_line_popover(
 9263        &self,
 9264        label: impl Into<SharedString>,
 9265        icon: Option<IconName>,
 9266        window: &mut Window,
 9267        cx: &App,
 9268    ) -> Stateful<Div> {
 9269        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9270
 9271        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9272        let has_keybind = keybind.is_some();
 9273
 9274        h_flex()
 9275            .id("ep-line-popover")
 9276            .py_0p5()
 9277            .pl_1()
 9278            .pr(padding_right)
 9279            .gap_1()
 9280            .rounded_md()
 9281            .border_1()
 9282            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9283            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9284            .shadow_xs()
 9285            .when(!has_keybind, |el| {
 9286                let status_colors = cx.theme().status();
 9287
 9288                el.bg(status_colors.error_background)
 9289                    .border_color(status_colors.error.opacity(0.6))
 9290                    .pl_2()
 9291                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9292                    .cursor_default()
 9293                    .hoverable_tooltip(move |_window, cx| {
 9294                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9295                    })
 9296            })
 9297            .children(keybind)
 9298            .child(
 9299                Label::new(label)
 9300                    .size(LabelSize::Small)
 9301                    .when(!has_keybind, |el| {
 9302                        el.color(cx.theme().status().error.into()).strikethrough()
 9303                    }),
 9304            )
 9305            .when(!has_keybind, |el| {
 9306                el.child(
 9307                    h_flex().ml_1().child(
 9308                        Icon::new(IconName::Info)
 9309                            .size(IconSize::Small)
 9310                            .color(cx.theme().status().error.into()),
 9311                    ),
 9312                )
 9313            })
 9314            .when_some(icon, |element, icon| {
 9315                element.child(
 9316                    div()
 9317                        .mt(px(1.5))
 9318                        .child(Icon::new(icon).size(IconSize::Small)),
 9319                )
 9320            })
 9321    }
 9322
 9323    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9324        let accent_color = cx.theme().colors().text_accent;
 9325        let editor_bg_color = cx.theme().colors().editor_background;
 9326        editor_bg_color.blend(accent_color.opacity(0.1))
 9327    }
 9328
 9329    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9330        let accent_color = cx.theme().colors().text_accent;
 9331        let editor_bg_color = cx.theme().colors().editor_background;
 9332        editor_bg_color.blend(accent_color.opacity(0.6))
 9333    }
 9334    fn get_prediction_provider_icon_name(
 9335        provider: &Option<RegisteredEditPredictionProvider>,
 9336    ) -> IconName {
 9337        match provider {
 9338            Some(provider) => match provider.provider.name() {
 9339                "copilot" => IconName::Copilot,
 9340                "supermaven" => IconName::Supermaven,
 9341                _ => IconName::ZedPredict,
 9342            },
 9343            None => IconName::ZedPredict,
 9344        }
 9345    }
 9346
 9347    fn render_edit_prediction_cursor_popover(
 9348        &self,
 9349        min_width: Pixels,
 9350        max_width: Pixels,
 9351        cursor_point: Point,
 9352        style: &EditorStyle,
 9353        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9354        _window: &Window,
 9355        cx: &mut Context<Editor>,
 9356    ) -> Option<AnyElement> {
 9357        let provider = self.edit_prediction_provider.as_ref()?;
 9358        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9359
 9360        let is_refreshing = provider.provider.is_refreshing(cx);
 9361
 9362        fn pending_completion_container(icon: IconName) -> Div {
 9363            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9364        }
 9365
 9366        let completion = match &self.active_edit_prediction {
 9367            Some(prediction) => {
 9368                if !self.has_visible_completions_menu() {
 9369                    const RADIUS: Pixels = px(6.);
 9370                    const BORDER_WIDTH: Pixels = px(1.);
 9371
 9372                    return Some(
 9373                        h_flex()
 9374                            .elevation_2(cx)
 9375                            .border(BORDER_WIDTH)
 9376                            .border_color(cx.theme().colors().border)
 9377                            .when(accept_keystroke.is_none(), |el| {
 9378                                el.border_color(cx.theme().status().error)
 9379                            })
 9380                            .rounded(RADIUS)
 9381                            .rounded_tl(px(0.))
 9382                            .overflow_hidden()
 9383                            .child(div().px_1p5().child(match &prediction.completion {
 9384                                EditPrediction::MoveWithin { target, snapshot } => {
 9385                                    use text::ToPoint as _;
 9386                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9387                                    {
 9388                                        Icon::new(IconName::ZedPredictDown)
 9389                                    } else {
 9390                                        Icon::new(IconName::ZedPredictUp)
 9391                                    }
 9392                                }
 9393                                EditPrediction::MoveOutside { .. } => {
 9394                                    // TODO [zeta2] custom icon for external jump?
 9395                                    Icon::new(provider_icon)
 9396                                }
 9397                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9398                            }))
 9399                            .child(
 9400                                h_flex()
 9401                                    .gap_1()
 9402                                    .py_1()
 9403                                    .px_2()
 9404                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9405                                    .border_l_1()
 9406                                    .border_color(cx.theme().colors().border)
 9407                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9408                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9409                                        el.child(
 9410                                            Label::new("Hold")
 9411                                                .size(LabelSize::Small)
 9412                                                .when(accept_keystroke.is_none(), |el| {
 9413                                                    el.strikethrough()
 9414                                                })
 9415                                                .line_height_style(LineHeightStyle::UiLabel),
 9416                                        )
 9417                                    })
 9418                                    .id("edit_prediction_cursor_popover_keybind")
 9419                                    .when(accept_keystroke.is_none(), |el| {
 9420                                        let status_colors = cx.theme().status();
 9421
 9422                                        el.bg(status_colors.error_background)
 9423                                            .border_color(status_colors.error.opacity(0.6))
 9424                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9425                                            .cursor_default()
 9426                                            .hoverable_tooltip(move |_window, cx| {
 9427                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9428                                                    .into()
 9429                                            })
 9430                                    })
 9431                                    .when_some(
 9432                                        accept_keystroke.as_ref(),
 9433                                        |el, accept_keystroke| {
 9434                                            el.child(h_flex().children(ui::render_modifiers(
 9435                                                accept_keystroke.modifiers(),
 9436                                                PlatformStyle::platform(),
 9437                                                Some(Color::Default),
 9438                                                Some(IconSize::XSmall.rems().into()),
 9439                                                false,
 9440                                            )))
 9441                                        },
 9442                                    ),
 9443                            )
 9444                            .into_any(),
 9445                    );
 9446                }
 9447
 9448                self.render_edit_prediction_cursor_popover_preview(
 9449                    prediction,
 9450                    cursor_point,
 9451                    style,
 9452                    cx,
 9453                )?
 9454            }
 9455
 9456            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9457                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9458                    stale_completion,
 9459                    cursor_point,
 9460                    style,
 9461                    cx,
 9462                )?,
 9463
 9464                None => pending_completion_container(provider_icon)
 9465                    .child(Label::new("...").size(LabelSize::Small)),
 9466            },
 9467
 9468            None => pending_completion_container(provider_icon)
 9469                .child(Label::new("...").size(LabelSize::Small)),
 9470        };
 9471
 9472        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9473            completion
 9474                .with_animation(
 9475                    "loading-completion",
 9476                    Animation::new(Duration::from_secs(2))
 9477                        .repeat()
 9478                        .with_easing(pulsating_between(0.4, 0.8)),
 9479                    |label, delta| label.opacity(delta),
 9480                )
 9481                .into_any_element()
 9482        } else {
 9483            completion.into_any_element()
 9484        };
 9485
 9486        let has_completion = self.active_edit_prediction.is_some();
 9487
 9488        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9489        Some(
 9490            h_flex()
 9491                .min_w(min_width)
 9492                .max_w(max_width)
 9493                .flex_1()
 9494                .elevation_2(cx)
 9495                .border_color(cx.theme().colors().border)
 9496                .child(
 9497                    div()
 9498                        .flex_1()
 9499                        .py_1()
 9500                        .px_2()
 9501                        .overflow_hidden()
 9502                        .child(completion),
 9503                )
 9504                .when_some(accept_keystroke, |el, accept_keystroke| {
 9505                    if !accept_keystroke.modifiers().modified() {
 9506                        return el;
 9507                    }
 9508
 9509                    el.child(
 9510                        h_flex()
 9511                            .h_full()
 9512                            .border_l_1()
 9513                            .rounded_r_lg()
 9514                            .border_color(cx.theme().colors().border)
 9515                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9516                            .gap_1()
 9517                            .py_1()
 9518                            .px_2()
 9519                            .child(
 9520                                h_flex()
 9521                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9522                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9523                                    .child(h_flex().children(ui::render_modifiers(
 9524                                        accept_keystroke.modifiers(),
 9525                                        PlatformStyle::platform(),
 9526                                        Some(if !has_completion {
 9527                                            Color::Muted
 9528                                        } else {
 9529                                            Color::Default
 9530                                        }),
 9531                                        None,
 9532                                        false,
 9533                                    ))),
 9534                            )
 9535                            .child(Label::new("Preview").into_any_element())
 9536                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9537                    )
 9538                })
 9539                .into_any(),
 9540        )
 9541    }
 9542
 9543    fn render_edit_prediction_cursor_popover_preview(
 9544        &self,
 9545        completion: &EditPredictionState,
 9546        cursor_point: Point,
 9547        style: &EditorStyle,
 9548        cx: &mut Context<Editor>,
 9549    ) -> Option<Div> {
 9550        use text::ToPoint as _;
 9551
 9552        fn render_relative_row_jump(
 9553            prefix: impl Into<String>,
 9554            current_row: u32,
 9555            target_row: u32,
 9556        ) -> Div {
 9557            let (row_diff, arrow) = if target_row < current_row {
 9558                (current_row - target_row, IconName::ArrowUp)
 9559            } else {
 9560                (target_row - current_row, IconName::ArrowDown)
 9561            };
 9562
 9563            h_flex()
 9564                .child(
 9565                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9566                        .color(Color::Muted)
 9567                        .size(LabelSize::Small),
 9568                )
 9569                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9570        }
 9571
 9572        let supports_jump = self
 9573            .edit_prediction_provider
 9574            .as_ref()
 9575            .map(|provider| provider.provider.supports_jump_to_edit())
 9576            .unwrap_or(true);
 9577
 9578        match &completion.completion {
 9579            EditPrediction::MoveWithin {
 9580                target, snapshot, ..
 9581            } => {
 9582                if !supports_jump {
 9583                    return None;
 9584                }
 9585
 9586                Some(
 9587                    h_flex()
 9588                        .px_2()
 9589                        .gap_2()
 9590                        .flex_1()
 9591                        .child(
 9592                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9593                                Icon::new(IconName::ZedPredictDown)
 9594                            } else {
 9595                                Icon::new(IconName::ZedPredictUp)
 9596                            },
 9597                        )
 9598                        .child(Label::new("Jump to Edit")),
 9599                )
 9600            }
 9601            EditPrediction::MoveOutside { snapshot, .. } => {
 9602                let file_name = snapshot
 9603                    .file()
 9604                    .map(|file| file.file_name(cx))
 9605                    .unwrap_or("untitled");
 9606                Some(
 9607                    h_flex()
 9608                        .px_2()
 9609                        .gap_2()
 9610                        .flex_1()
 9611                        .child(Icon::new(IconName::ZedPredict))
 9612                        .child(Label::new(format!("Jump to {file_name}"))),
 9613                )
 9614            }
 9615            EditPrediction::Edit {
 9616                edits,
 9617                edit_preview,
 9618                snapshot,
 9619                display_mode: _,
 9620            } => {
 9621                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9622
 9623                let (highlighted_edits, has_more_lines) =
 9624                    if let Some(edit_preview) = edit_preview.as_ref() {
 9625                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9626                            .first_line_preview()
 9627                    } else {
 9628                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9629                    };
 9630
 9631                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9632                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9633
 9634                let preview = h_flex()
 9635                    .gap_1()
 9636                    .min_w_16()
 9637                    .child(styled_text)
 9638                    .when(has_more_lines, |parent| parent.child(""));
 9639
 9640                let left = if supports_jump && first_edit_row != cursor_point.row {
 9641                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9642                        .into_any_element()
 9643                } else {
 9644                    let icon_name =
 9645                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9646                    Icon::new(icon_name).into_any_element()
 9647                };
 9648
 9649                Some(
 9650                    h_flex()
 9651                        .h_full()
 9652                        .flex_1()
 9653                        .gap_2()
 9654                        .pr_1()
 9655                        .overflow_x_hidden()
 9656                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9657                        .child(left)
 9658                        .child(preview),
 9659                )
 9660            }
 9661        }
 9662    }
 9663
 9664    pub fn render_context_menu(
 9665        &self,
 9666        style: &EditorStyle,
 9667        max_height_in_lines: u32,
 9668        window: &mut Window,
 9669        cx: &mut Context<Editor>,
 9670    ) -> Option<AnyElement> {
 9671        let menu = self.context_menu.borrow();
 9672        let menu = menu.as_ref()?;
 9673        if !menu.visible() {
 9674            return None;
 9675        };
 9676        Some(menu.render(style, max_height_in_lines, window, cx))
 9677    }
 9678
 9679    fn render_context_menu_aside(
 9680        &mut self,
 9681        max_size: Size<Pixels>,
 9682        window: &mut Window,
 9683        cx: &mut Context<Editor>,
 9684    ) -> Option<AnyElement> {
 9685        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9686            if menu.visible() {
 9687                menu.render_aside(max_size, window, cx)
 9688            } else {
 9689                None
 9690            }
 9691        })
 9692    }
 9693
 9694    fn hide_context_menu(
 9695        &mut self,
 9696        window: &mut Window,
 9697        cx: &mut Context<Self>,
 9698    ) -> Option<CodeContextMenu> {
 9699        cx.notify();
 9700        self.completion_tasks.clear();
 9701        let context_menu = self.context_menu.borrow_mut().take();
 9702        self.stale_edit_prediction_in_menu.take();
 9703        self.update_visible_edit_prediction(window, cx);
 9704        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9705            && let Some(completion_provider) = &self.completion_provider
 9706        {
 9707            completion_provider.selection_changed(None, window, cx);
 9708        }
 9709        context_menu
 9710    }
 9711
 9712    fn show_snippet_choices(
 9713        &mut self,
 9714        choices: &Vec<String>,
 9715        selection: Range<Anchor>,
 9716        cx: &mut Context<Self>,
 9717    ) {
 9718        let Some((_, buffer, _)) = self
 9719            .buffer()
 9720            .read(cx)
 9721            .excerpt_containing(selection.start, cx)
 9722        else {
 9723            return;
 9724        };
 9725        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9726        else {
 9727            return;
 9728        };
 9729        if buffer != end_buffer {
 9730            log::error!("expected anchor range to have matching buffer IDs");
 9731            return;
 9732        }
 9733
 9734        let id = post_inc(&mut self.next_completion_id);
 9735        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9736        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9737            CompletionsMenu::new_snippet_choices(
 9738                id,
 9739                true,
 9740                choices,
 9741                selection,
 9742                buffer,
 9743                snippet_sort_order,
 9744            ),
 9745        ));
 9746    }
 9747
 9748    pub fn insert_snippet(
 9749        &mut self,
 9750        insertion_ranges: &[Range<usize>],
 9751        snippet: Snippet,
 9752        window: &mut Window,
 9753        cx: &mut Context<Self>,
 9754    ) -> Result<()> {
 9755        struct Tabstop<T> {
 9756            is_end_tabstop: bool,
 9757            ranges: Vec<Range<T>>,
 9758            choices: Option<Vec<String>>,
 9759        }
 9760
 9761        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9762            let snippet_text: Arc<str> = snippet.text.clone().into();
 9763            let edits = insertion_ranges
 9764                .iter()
 9765                .cloned()
 9766                .map(|range| (range, snippet_text.clone()));
 9767            let autoindent_mode = AutoindentMode::Block {
 9768                original_indent_columns: Vec::new(),
 9769            };
 9770            buffer.edit(edits, Some(autoindent_mode), cx);
 9771
 9772            let snapshot = &*buffer.read(cx);
 9773            let snippet = &snippet;
 9774            snippet
 9775                .tabstops
 9776                .iter()
 9777                .map(|tabstop| {
 9778                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9779                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9780                    });
 9781                    let mut tabstop_ranges = tabstop
 9782                        .ranges
 9783                        .iter()
 9784                        .flat_map(|tabstop_range| {
 9785                            let mut delta = 0_isize;
 9786                            insertion_ranges.iter().map(move |insertion_range| {
 9787                                let insertion_start = insertion_range.start as isize + delta;
 9788                                delta +=
 9789                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9790
 9791                                let start = ((insertion_start + tabstop_range.start) as usize)
 9792                                    .min(snapshot.len());
 9793                                let end = ((insertion_start + tabstop_range.end) as usize)
 9794                                    .min(snapshot.len());
 9795                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9796                            })
 9797                        })
 9798                        .collect::<Vec<_>>();
 9799                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9800
 9801                    Tabstop {
 9802                        is_end_tabstop,
 9803                        ranges: tabstop_ranges,
 9804                        choices: tabstop.choices.clone(),
 9805                    }
 9806                })
 9807                .collect::<Vec<_>>()
 9808        });
 9809        if let Some(tabstop) = tabstops.first() {
 9810            self.change_selections(Default::default(), window, cx, |s| {
 9811                // Reverse order so that the first range is the newest created selection.
 9812                // Completions will use it and autoscroll will prioritize it.
 9813                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9814            });
 9815
 9816            if let Some(choices) = &tabstop.choices
 9817                && let Some(selection) = tabstop.ranges.first()
 9818            {
 9819                self.show_snippet_choices(choices, selection.clone(), cx)
 9820            }
 9821
 9822            // If we're already at the last tabstop and it's at the end of the snippet,
 9823            // we're done, we don't need to keep the state around.
 9824            if !tabstop.is_end_tabstop {
 9825                let choices = tabstops
 9826                    .iter()
 9827                    .map(|tabstop| tabstop.choices.clone())
 9828                    .collect();
 9829
 9830                let ranges = tabstops
 9831                    .into_iter()
 9832                    .map(|tabstop| tabstop.ranges)
 9833                    .collect::<Vec<_>>();
 9834
 9835                self.snippet_stack.push(SnippetState {
 9836                    active_index: 0,
 9837                    ranges,
 9838                    choices,
 9839                });
 9840            }
 9841
 9842            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9843            if self.autoclose_regions.is_empty() {
 9844                let snapshot = self.buffer.read(cx).snapshot(cx);
 9845                let mut all_selections = self.selections.all::<Point>(cx);
 9846                for selection in &mut all_selections {
 9847                    let selection_head = selection.head();
 9848                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9849                        continue;
 9850                    };
 9851
 9852                    let mut bracket_pair = None;
 9853                    let max_lookup_length = scope
 9854                        .brackets()
 9855                        .map(|(pair, _)| {
 9856                            pair.start
 9857                                .as_str()
 9858                                .chars()
 9859                                .count()
 9860                                .max(pair.end.as_str().chars().count())
 9861                        })
 9862                        .max();
 9863                    if let Some(max_lookup_length) = max_lookup_length {
 9864                        let next_text = snapshot
 9865                            .chars_at(selection_head)
 9866                            .take(max_lookup_length)
 9867                            .collect::<String>();
 9868                        let prev_text = snapshot
 9869                            .reversed_chars_at(selection_head)
 9870                            .take(max_lookup_length)
 9871                            .collect::<String>();
 9872
 9873                        for (pair, enabled) in scope.brackets() {
 9874                            if enabled
 9875                                && pair.close
 9876                                && prev_text.starts_with(pair.start.as_str())
 9877                                && next_text.starts_with(pair.end.as_str())
 9878                            {
 9879                                bracket_pair = Some(pair.clone());
 9880                                break;
 9881                            }
 9882                        }
 9883                    }
 9884
 9885                    if let Some(pair) = bracket_pair {
 9886                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9887                        let autoclose_enabled =
 9888                            self.use_autoclose && snapshot_settings.use_autoclose;
 9889                        if autoclose_enabled {
 9890                            let start = snapshot.anchor_after(selection_head);
 9891                            let end = snapshot.anchor_after(selection_head);
 9892                            self.autoclose_regions.push(AutocloseRegion {
 9893                                selection_id: selection.id,
 9894                                range: start..end,
 9895                                pair,
 9896                            });
 9897                        }
 9898                    }
 9899                }
 9900            }
 9901        }
 9902        Ok(())
 9903    }
 9904
 9905    pub fn move_to_next_snippet_tabstop(
 9906        &mut self,
 9907        window: &mut Window,
 9908        cx: &mut Context<Self>,
 9909    ) -> bool {
 9910        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9911    }
 9912
 9913    pub fn move_to_prev_snippet_tabstop(
 9914        &mut self,
 9915        window: &mut Window,
 9916        cx: &mut Context<Self>,
 9917    ) -> bool {
 9918        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9919    }
 9920
 9921    pub fn move_to_snippet_tabstop(
 9922        &mut self,
 9923        bias: Bias,
 9924        window: &mut Window,
 9925        cx: &mut Context<Self>,
 9926    ) -> bool {
 9927        if let Some(mut snippet) = self.snippet_stack.pop() {
 9928            match bias {
 9929                Bias::Left => {
 9930                    if snippet.active_index > 0 {
 9931                        snippet.active_index -= 1;
 9932                    } else {
 9933                        self.snippet_stack.push(snippet);
 9934                        return false;
 9935                    }
 9936                }
 9937                Bias::Right => {
 9938                    if snippet.active_index + 1 < snippet.ranges.len() {
 9939                        snippet.active_index += 1;
 9940                    } else {
 9941                        self.snippet_stack.push(snippet);
 9942                        return false;
 9943                    }
 9944                }
 9945            }
 9946            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9947                self.change_selections(Default::default(), window, cx, |s| {
 9948                    // Reverse order so that the first range is the newest created selection.
 9949                    // Completions will use it and autoscroll will prioritize it.
 9950                    s.select_ranges(current_ranges.iter().rev().cloned())
 9951                });
 9952
 9953                if let Some(choices) = &snippet.choices[snippet.active_index]
 9954                    && let Some(selection) = current_ranges.first()
 9955                {
 9956                    self.show_snippet_choices(choices, selection.clone(), cx);
 9957                }
 9958
 9959                // If snippet state is not at the last tabstop, push it back on the stack
 9960                if snippet.active_index + 1 < snippet.ranges.len() {
 9961                    self.snippet_stack.push(snippet);
 9962                }
 9963                return true;
 9964            }
 9965        }
 9966
 9967        false
 9968    }
 9969
 9970    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9971        self.transact(window, cx, |this, window, cx| {
 9972            this.select_all(&SelectAll, window, cx);
 9973            this.insert("", window, cx);
 9974        });
 9975    }
 9976
 9977    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9978        if self.read_only(cx) {
 9979            return;
 9980        }
 9981        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9982        self.transact(window, cx, |this, window, cx| {
 9983            this.select_autoclose_pair(window, cx);
 9984            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9985            if !this.linked_edit_ranges.is_empty() {
 9986                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9987                let snapshot = this.buffer.read(cx).snapshot(cx);
 9988
 9989                for selection in selections.iter() {
 9990                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9991                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9992                    if selection_start.buffer_id != selection_end.buffer_id {
 9993                        continue;
 9994                    }
 9995                    if let Some(ranges) =
 9996                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9997                    {
 9998                        for (buffer, entries) in ranges {
 9999                            linked_ranges.entry(buffer).or_default().extend(entries);
10000                        }
10001                    }
10002                }
10003            }
10004
10005            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10006            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10007            for selection in &mut selections {
10008                if selection.is_empty() {
10009                    let old_head = selection.head();
10010                    let mut new_head =
10011                        movement::left(&display_map, old_head.to_display_point(&display_map))
10012                            .to_point(&display_map);
10013                    if let Some((buffer, line_buffer_range)) = display_map
10014                        .buffer_snapshot
10015                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10016                    {
10017                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10018                        let indent_len = match indent_size.kind {
10019                            IndentKind::Space => {
10020                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10021                            }
10022                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10023                        };
10024                        if old_head.column <= indent_size.len && old_head.column > 0 {
10025                            let indent_len = indent_len.get();
10026                            new_head = cmp::min(
10027                                new_head,
10028                                MultiBufferPoint::new(
10029                                    old_head.row,
10030                                    ((old_head.column - 1) / indent_len) * indent_len,
10031                                ),
10032                            );
10033                        }
10034                    }
10035
10036                    selection.set_head(new_head, SelectionGoal::None);
10037                }
10038            }
10039
10040            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10041            this.insert("", window, cx);
10042            let empty_str: Arc<str> = Arc::from("");
10043            for (buffer, edits) in linked_ranges {
10044                let snapshot = buffer.read(cx).snapshot();
10045                use text::ToPoint as TP;
10046
10047                let edits = edits
10048                    .into_iter()
10049                    .map(|range| {
10050                        let end_point = TP::to_point(&range.end, &snapshot);
10051                        let mut start_point = TP::to_point(&range.start, &snapshot);
10052
10053                        if end_point == start_point {
10054                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10055                                .saturating_sub(1);
10056                            start_point =
10057                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10058                        };
10059
10060                        (start_point..end_point, empty_str.clone())
10061                    })
10062                    .sorted_by_key(|(range, _)| range.start)
10063                    .collect::<Vec<_>>();
10064                buffer.update(cx, |this, cx| {
10065                    this.edit(edits, None, cx);
10066                })
10067            }
10068            this.refresh_edit_prediction(true, false, window, cx);
10069            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
10070        });
10071    }
10072
10073    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10074        if self.read_only(cx) {
10075            return;
10076        }
10077        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10078        self.transact(window, cx, |this, window, cx| {
10079            this.change_selections(Default::default(), window, cx, |s| {
10080                s.move_with(|map, selection| {
10081                    if selection.is_empty() {
10082                        let cursor = movement::right(map, selection.head());
10083                        selection.end = cursor;
10084                        selection.reversed = true;
10085                        selection.goal = SelectionGoal::None;
10086                    }
10087                })
10088            });
10089            this.insert("", window, cx);
10090            this.refresh_edit_prediction(true, false, window, cx);
10091        });
10092    }
10093
10094    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10095        if self.mode.is_single_line() {
10096            cx.propagate();
10097            return;
10098        }
10099
10100        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10101        if self.move_to_prev_snippet_tabstop(window, cx) {
10102            return;
10103        }
10104        self.outdent(&Outdent, window, cx);
10105    }
10106
10107    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10108        if self.mode.is_single_line() {
10109            cx.propagate();
10110            return;
10111        }
10112
10113        if self.move_to_next_snippet_tabstop(window, cx) {
10114            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10115            return;
10116        }
10117        if self.read_only(cx) {
10118            return;
10119        }
10120        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10121        let mut selections = self.selections.all_adjusted(cx);
10122        let buffer = self.buffer.read(cx);
10123        let snapshot = buffer.snapshot(cx);
10124        let rows_iter = selections.iter().map(|s| s.head().row);
10125        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10126
10127        let has_some_cursor_in_whitespace = selections
10128            .iter()
10129            .filter(|selection| selection.is_empty())
10130            .any(|selection| {
10131                let cursor = selection.head();
10132                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10133                cursor.column < current_indent.len
10134            });
10135
10136        let mut edits = Vec::new();
10137        let mut prev_edited_row = 0;
10138        let mut row_delta = 0;
10139        for selection in &mut selections {
10140            if selection.start.row != prev_edited_row {
10141                row_delta = 0;
10142            }
10143            prev_edited_row = selection.end.row;
10144
10145            // If the selection is non-empty, then increase the indentation of the selected lines.
10146            if !selection.is_empty() {
10147                row_delta =
10148                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10149                continue;
10150            }
10151
10152            let cursor = selection.head();
10153            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10154            if let Some(suggested_indent) =
10155                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10156            {
10157                // Don't do anything if already at suggested indent
10158                // and there is any other cursor which is not
10159                if has_some_cursor_in_whitespace
10160                    && cursor.column == current_indent.len
10161                    && current_indent.len == suggested_indent.len
10162                {
10163                    continue;
10164                }
10165
10166                // Adjust line and move cursor to suggested indent
10167                // if cursor is not at suggested indent
10168                if cursor.column < suggested_indent.len
10169                    && cursor.column <= current_indent.len
10170                    && current_indent.len <= suggested_indent.len
10171                {
10172                    selection.start = Point::new(cursor.row, suggested_indent.len);
10173                    selection.end = selection.start;
10174                    if row_delta == 0 {
10175                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10176                            cursor.row,
10177                            current_indent,
10178                            suggested_indent,
10179                        ));
10180                        row_delta = suggested_indent.len - current_indent.len;
10181                    }
10182                    continue;
10183                }
10184
10185                // If current indent is more than suggested indent
10186                // only move cursor to current indent and skip indent
10187                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10188                    selection.start = Point::new(cursor.row, current_indent.len);
10189                    selection.end = selection.start;
10190                    continue;
10191                }
10192            }
10193
10194            // Otherwise, insert a hard or soft tab.
10195            let settings = buffer.language_settings_at(cursor, cx);
10196            let tab_size = if settings.hard_tabs {
10197                IndentSize::tab()
10198            } else {
10199                let tab_size = settings.tab_size.get();
10200                let indent_remainder = snapshot
10201                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10202                    .flat_map(str::chars)
10203                    .fold(row_delta % tab_size, |counter: u32, c| {
10204                        if c == '\t' {
10205                            0
10206                        } else {
10207                            (counter + 1) % tab_size
10208                        }
10209                    });
10210
10211                let chars_to_next_tab_stop = tab_size - indent_remainder;
10212                IndentSize::spaces(chars_to_next_tab_stop)
10213            };
10214            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10215            selection.end = selection.start;
10216            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10217            row_delta += tab_size.len;
10218        }
10219
10220        self.transact(window, cx, |this, window, cx| {
10221            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10222            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10223            this.refresh_edit_prediction(true, false, window, cx);
10224        });
10225    }
10226
10227    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10228        if self.read_only(cx) {
10229            return;
10230        }
10231        if self.mode.is_single_line() {
10232            cx.propagate();
10233            return;
10234        }
10235
10236        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10237        let mut selections = self.selections.all::<Point>(cx);
10238        let mut prev_edited_row = 0;
10239        let mut row_delta = 0;
10240        let mut edits = Vec::new();
10241        let buffer = self.buffer.read(cx);
10242        let snapshot = buffer.snapshot(cx);
10243        for selection in &mut selections {
10244            if selection.start.row != prev_edited_row {
10245                row_delta = 0;
10246            }
10247            prev_edited_row = selection.end.row;
10248
10249            row_delta =
10250                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10251        }
10252
10253        self.transact(window, cx, |this, window, cx| {
10254            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10255            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10256        });
10257    }
10258
10259    fn indent_selection(
10260        buffer: &MultiBuffer,
10261        snapshot: &MultiBufferSnapshot,
10262        selection: &mut Selection<Point>,
10263        edits: &mut Vec<(Range<Point>, String)>,
10264        delta_for_start_row: u32,
10265        cx: &App,
10266    ) -> u32 {
10267        let settings = buffer.language_settings_at(selection.start, cx);
10268        let tab_size = settings.tab_size.get();
10269        let indent_kind = if settings.hard_tabs {
10270            IndentKind::Tab
10271        } else {
10272            IndentKind::Space
10273        };
10274        let mut start_row = selection.start.row;
10275        let mut end_row = selection.end.row + 1;
10276
10277        // If a selection ends at the beginning of a line, don't indent
10278        // that last line.
10279        if selection.end.column == 0 && selection.end.row > selection.start.row {
10280            end_row -= 1;
10281        }
10282
10283        // Avoid re-indenting a row that has already been indented by a
10284        // previous selection, but still update this selection's column
10285        // to reflect that indentation.
10286        if delta_for_start_row > 0 {
10287            start_row += 1;
10288            selection.start.column += delta_for_start_row;
10289            if selection.end.row == selection.start.row {
10290                selection.end.column += delta_for_start_row;
10291            }
10292        }
10293
10294        let mut delta_for_end_row = 0;
10295        let has_multiple_rows = start_row + 1 != end_row;
10296        for row in start_row..end_row {
10297            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10298            let indent_delta = match (current_indent.kind, indent_kind) {
10299                (IndentKind::Space, IndentKind::Space) => {
10300                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10301                    IndentSize::spaces(columns_to_next_tab_stop)
10302                }
10303                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10304                (_, IndentKind::Tab) => IndentSize::tab(),
10305            };
10306
10307            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10308                0
10309            } else {
10310                selection.start.column
10311            };
10312            let row_start = Point::new(row, start);
10313            edits.push((
10314                row_start..row_start,
10315                indent_delta.chars().collect::<String>(),
10316            ));
10317
10318            // Update this selection's endpoints to reflect the indentation.
10319            if row == selection.start.row {
10320                selection.start.column += indent_delta.len;
10321            }
10322            if row == selection.end.row {
10323                selection.end.column += indent_delta.len;
10324                delta_for_end_row = indent_delta.len;
10325            }
10326        }
10327
10328        if selection.start.row == selection.end.row {
10329            delta_for_start_row + delta_for_end_row
10330        } else {
10331            delta_for_end_row
10332        }
10333    }
10334
10335    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10336        if self.read_only(cx) {
10337            return;
10338        }
10339        if self.mode.is_single_line() {
10340            cx.propagate();
10341            return;
10342        }
10343
10344        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10345        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10346        let selections = self.selections.all::<Point>(cx);
10347        let mut deletion_ranges = Vec::new();
10348        let mut last_outdent = None;
10349        {
10350            let buffer = self.buffer.read(cx);
10351            let snapshot = buffer.snapshot(cx);
10352            for selection in &selections {
10353                let settings = buffer.language_settings_at(selection.start, cx);
10354                let tab_size = settings.tab_size.get();
10355                let mut rows = selection.spanned_rows(false, &display_map);
10356
10357                // Avoid re-outdenting a row that has already been outdented by a
10358                // previous selection.
10359                if let Some(last_row) = last_outdent
10360                    && last_row == rows.start
10361                {
10362                    rows.start = rows.start.next_row();
10363                }
10364                let has_multiple_rows = rows.len() > 1;
10365                for row in rows.iter_rows() {
10366                    let indent_size = snapshot.indent_size_for_line(row);
10367                    if indent_size.len > 0 {
10368                        let deletion_len = match indent_size.kind {
10369                            IndentKind::Space => {
10370                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10371                                if columns_to_prev_tab_stop == 0 {
10372                                    tab_size
10373                                } else {
10374                                    columns_to_prev_tab_stop
10375                                }
10376                            }
10377                            IndentKind::Tab => 1,
10378                        };
10379                        let start = if has_multiple_rows
10380                            || deletion_len > selection.start.column
10381                            || indent_size.len < selection.start.column
10382                        {
10383                            0
10384                        } else {
10385                            selection.start.column - deletion_len
10386                        };
10387                        deletion_ranges.push(
10388                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10389                        );
10390                        last_outdent = Some(row);
10391                    }
10392                }
10393            }
10394        }
10395
10396        self.transact(window, cx, |this, window, cx| {
10397            this.buffer.update(cx, |buffer, cx| {
10398                let empty_str: Arc<str> = Arc::default();
10399                buffer.edit(
10400                    deletion_ranges
10401                        .into_iter()
10402                        .map(|range| (range, empty_str.clone())),
10403                    None,
10404                    cx,
10405                );
10406            });
10407            let selections = this.selections.all::<usize>(cx);
10408            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10409        });
10410    }
10411
10412    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10413        if self.read_only(cx) {
10414            return;
10415        }
10416        if self.mode.is_single_line() {
10417            cx.propagate();
10418            return;
10419        }
10420
10421        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10422        let selections = self
10423            .selections
10424            .all::<usize>(cx)
10425            .into_iter()
10426            .map(|s| s.range());
10427
10428        self.transact(window, cx, |this, window, cx| {
10429            this.buffer.update(cx, |buffer, cx| {
10430                buffer.autoindent_ranges(selections, cx);
10431            });
10432            let selections = this.selections.all::<usize>(cx);
10433            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10434        });
10435    }
10436
10437    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10438        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10439        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10440        let selections = self.selections.all::<Point>(cx);
10441
10442        let mut new_cursors = Vec::new();
10443        let mut edit_ranges = Vec::new();
10444        let mut selections = selections.iter().peekable();
10445        while let Some(selection) = selections.next() {
10446            let mut rows = selection.spanned_rows(false, &display_map);
10447
10448            // Accumulate contiguous regions of rows that we want to delete.
10449            while let Some(next_selection) = selections.peek() {
10450                let next_rows = next_selection.spanned_rows(false, &display_map);
10451                if next_rows.start <= rows.end {
10452                    rows.end = next_rows.end;
10453                    selections.next().unwrap();
10454                } else {
10455                    break;
10456                }
10457            }
10458
10459            let buffer = &display_map.buffer_snapshot;
10460            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10461            let edit_end = if buffer.max_point().row >= rows.end.0 {
10462                // If there's a line after the range, delete the \n from the end of the row range
10463                Point::new(rows.end.0, 0).to_offset(buffer)
10464            } else {
10465                // If there isn't a line after the range, delete the \n from the line before the
10466                // start of the row range
10467                edit_start = edit_start.saturating_sub(1);
10468                buffer.len()
10469            };
10470
10471            let (cursor, goal) = movement::down_by_rows(
10472                &display_map,
10473                selection.head().to_display_point(&display_map),
10474                rows.len() as u32,
10475                selection.goal,
10476                false,
10477                &self.text_layout_details(window),
10478            );
10479
10480            new_cursors.push((
10481                selection.id,
10482                buffer.anchor_after(cursor.to_point(&display_map)),
10483                goal,
10484            ));
10485            edit_ranges.push(edit_start..edit_end);
10486        }
10487
10488        self.transact(window, cx, |this, window, cx| {
10489            let buffer = this.buffer.update(cx, |buffer, cx| {
10490                let empty_str: Arc<str> = Arc::default();
10491                buffer.edit(
10492                    edit_ranges
10493                        .into_iter()
10494                        .map(|range| (range, empty_str.clone())),
10495                    None,
10496                    cx,
10497                );
10498                buffer.snapshot(cx)
10499            });
10500            let new_selections = new_cursors
10501                .into_iter()
10502                .map(|(id, cursor, goal)| {
10503                    let cursor = cursor.to_point(&buffer);
10504                    Selection {
10505                        id,
10506                        start: cursor,
10507                        end: cursor,
10508                        reversed: false,
10509                        goal,
10510                    }
10511                })
10512                .collect();
10513
10514            this.change_selections(Default::default(), window, cx, |s| {
10515                s.select(new_selections);
10516            });
10517        });
10518    }
10519
10520    pub fn join_lines_impl(
10521        &mut self,
10522        insert_whitespace: bool,
10523        window: &mut Window,
10524        cx: &mut Context<Self>,
10525    ) {
10526        if self.read_only(cx) {
10527            return;
10528        }
10529        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10530        for selection in self.selections.all::<Point>(cx) {
10531            let start = MultiBufferRow(selection.start.row);
10532            // Treat single line selections as if they include the next line. Otherwise this action
10533            // would do nothing for single line selections individual cursors.
10534            let end = if selection.start.row == selection.end.row {
10535                MultiBufferRow(selection.start.row + 1)
10536            } else {
10537                MultiBufferRow(selection.end.row)
10538            };
10539
10540            if let Some(last_row_range) = row_ranges.last_mut()
10541                && start <= last_row_range.end
10542            {
10543                last_row_range.end = end;
10544                continue;
10545            }
10546            row_ranges.push(start..end);
10547        }
10548
10549        let snapshot = self.buffer.read(cx).snapshot(cx);
10550        let mut cursor_positions = Vec::new();
10551        for row_range in &row_ranges {
10552            let anchor = snapshot.anchor_before(Point::new(
10553                row_range.end.previous_row().0,
10554                snapshot.line_len(row_range.end.previous_row()),
10555            ));
10556            cursor_positions.push(anchor..anchor);
10557        }
10558
10559        self.transact(window, cx, |this, window, cx| {
10560            for row_range in row_ranges.into_iter().rev() {
10561                for row in row_range.iter_rows().rev() {
10562                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10563                    let next_line_row = row.next_row();
10564                    let indent = snapshot.indent_size_for_line(next_line_row);
10565                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10566
10567                    let replace =
10568                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10569                            " "
10570                        } else {
10571                            ""
10572                        };
10573
10574                    this.buffer.update(cx, |buffer, cx| {
10575                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10576                    });
10577                }
10578            }
10579
10580            this.change_selections(Default::default(), window, cx, |s| {
10581                s.select_anchor_ranges(cursor_positions)
10582            });
10583        });
10584    }
10585
10586    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10587        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10588        self.join_lines_impl(true, window, cx);
10589    }
10590
10591    pub fn sort_lines_case_sensitive(
10592        &mut self,
10593        _: &SortLinesCaseSensitive,
10594        window: &mut Window,
10595        cx: &mut Context<Self>,
10596    ) {
10597        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10598    }
10599
10600    pub fn sort_lines_by_length(
10601        &mut self,
10602        _: &SortLinesByLength,
10603        window: &mut Window,
10604        cx: &mut Context<Self>,
10605    ) {
10606        self.manipulate_immutable_lines(window, cx, |lines| {
10607            lines.sort_by_key(|&line| line.chars().count())
10608        })
10609    }
10610
10611    pub fn sort_lines_case_insensitive(
10612        &mut self,
10613        _: &SortLinesCaseInsensitive,
10614        window: &mut Window,
10615        cx: &mut Context<Self>,
10616    ) {
10617        self.manipulate_immutable_lines(window, cx, |lines| {
10618            lines.sort_by_key(|line| line.to_lowercase())
10619        })
10620    }
10621
10622    pub fn unique_lines_case_insensitive(
10623        &mut self,
10624        _: &UniqueLinesCaseInsensitive,
10625        window: &mut Window,
10626        cx: &mut Context<Self>,
10627    ) {
10628        self.manipulate_immutable_lines(window, cx, |lines| {
10629            let mut seen = HashSet::default();
10630            lines.retain(|line| seen.insert(line.to_lowercase()));
10631        })
10632    }
10633
10634    pub fn unique_lines_case_sensitive(
10635        &mut self,
10636        _: &UniqueLinesCaseSensitive,
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));
10643        })
10644    }
10645
10646    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10647        let snapshot = self.buffer.read(cx).snapshot(cx);
10648        for selection in self.selections.disjoint_anchors_arc().iter() {
10649            if snapshot
10650                .language_at(selection.start)
10651                .and_then(|lang| lang.config().wrap_characters.as_ref())
10652                .is_some()
10653            {
10654                return true;
10655            }
10656        }
10657        false
10658    }
10659
10660    fn wrap_selections_in_tag(
10661        &mut self,
10662        _: &WrapSelectionsInTag,
10663        window: &mut Window,
10664        cx: &mut Context<Self>,
10665    ) {
10666        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10667
10668        let snapshot = self.buffer.read(cx).snapshot(cx);
10669
10670        let mut edits = Vec::new();
10671        let mut boundaries = Vec::new();
10672
10673        for selection in self.selections.all::<Point>(cx).iter() {
10674            let Some(wrap_config) = snapshot
10675                .language_at(selection.start)
10676                .and_then(|lang| lang.config().wrap_characters.clone())
10677            else {
10678                continue;
10679            };
10680
10681            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10682            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10683
10684            let start_before = snapshot.anchor_before(selection.start);
10685            let end_after = snapshot.anchor_after(selection.end);
10686
10687            edits.push((start_before..start_before, open_tag));
10688            edits.push((end_after..end_after, close_tag));
10689
10690            boundaries.push((
10691                start_before,
10692                end_after,
10693                wrap_config.start_prefix.len(),
10694                wrap_config.end_suffix.len(),
10695            ));
10696        }
10697
10698        if edits.is_empty() {
10699            return;
10700        }
10701
10702        self.transact(window, cx, |this, window, cx| {
10703            let buffer = this.buffer.update(cx, |buffer, cx| {
10704                buffer.edit(edits, None, cx);
10705                buffer.snapshot(cx)
10706            });
10707
10708            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10709            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10710                boundaries.into_iter()
10711            {
10712                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10713                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10714                new_selections.push(open_offset..open_offset);
10715                new_selections.push(close_offset..close_offset);
10716            }
10717
10718            this.change_selections(Default::default(), window, cx, |s| {
10719                s.select_ranges(new_selections);
10720            });
10721
10722            this.request_autoscroll(Autoscroll::fit(), cx);
10723        });
10724    }
10725
10726    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10727        let Some(project) = self.project.clone() else {
10728            return;
10729        };
10730        self.reload(project, window, cx)
10731            .detach_and_notify_err(window, cx);
10732    }
10733
10734    pub fn restore_file(
10735        &mut self,
10736        _: &::git::RestoreFile,
10737        window: &mut Window,
10738        cx: &mut Context<Self>,
10739    ) {
10740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10741        let mut buffer_ids = HashSet::default();
10742        let snapshot = self.buffer().read(cx).snapshot(cx);
10743        for selection in self.selections.all::<usize>(cx) {
10744            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10745        }
10746
10747        let buffer = self.buffer().read(cx);
10748        let ranges = buffer_ids
10749            .into_iter()
10750            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10751            .collect::<Vec<_>>();
10752
10753        self.restore_hunks_in_ranges(ranges, window, cx);
10754    }
10755
10756    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10757        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10758        let selections = self
10759            .selections
10760            .all(cx)
10761            .into_iter()
10762            .map(|s| s.range())
10763            .collect();
10764        self.restore_hunks_in_ranges(selections, window, cx);
10765    }
10766
10767    pub fn restore_hunks_in_ranges(
10768        &mut self,
10769        ranges: Vec<Range<Point>>,
10770        window: &mut Window,
10771        cx: &mut Context<Editor>,
10772    ) {
10773        let mut revert_changes = HashMap::default();
10774        let chunk_by = self
10775            .snapshot(window, cx)
10776            .hunks_for_ranges(ranges)
10777            .into_iter()
10778            .chunk_by(|hunk| hunk.buffer_id);
10779        for (buffer_id, hunks) in &chunk_by {
10780            let hunks = hunks.collect::<Vec<_>>();
10781            for hunk in &hunks {
10782                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10783            }
10784            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10785        }
10786        drop(chunk_by);
10787        if !revert_changes.is_empty() {
10788            self.transact(window, cx, |editor, window, cx| {
10789                editor.restore(revert_changes, window, cx);
10790            });
10791        }
10792    }
10793
10794    pub fn open_active_item_in_terminal(
10795        &mut self,
10796        _: &OpenInTerminal,
10797        window: &mut Window,
10798        cx: &mut Context<Self>,
10799    ) {
10800        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10801            let project_path = buffer.read(cx).project_path(cx)?;
10802            let project = self.project()?.read(cx);
10803            let entry = project.entry_for_path(&project_path, cx)?;
10804            let parent = match &entry.canonical_path {
10805                Some(canonical_path) => canonical_path.to_path_buf(),
10806                None => project.absolute_path(&project_path, cx)?,
10807            }
10808            .parent()?
10809            .to_path_buf();
10810            Some(parent)
10811        }) {
10812            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10813        }
10814    }
10815
10816    fn set_breakpoint_context_menu(
10817        &mut self,
10818        display_row: DisplayRow,
10819        position: Option<Anchor>,
10820        clicked_point: gpui::Point<Pixels>,
10821        window: &mut Window,
10822        cx: &mut Context<Self>,
10823    ) {
10824        let source = self
10825            .buffer
10826            .read(cx)
10827            .snapshot(cx)
10828            .anchor_before(Point::new(display_row.0, 0u32));
10829
10830        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10831
10832        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10833            self,
10834            source,
10835            clicked_point,
10836            context_menu,
10837            window,
10838            cx,
10839        );
10840    }
10841
10842    fn add_edit_breakpoint_block(
10843        &mut self,
10844        anchor: Anchor,
10845        breakpoint: &Breakpoint,
10846        edit_action: BreakpointPromptEditAction,
10847        window: &mut Window,
10848        cx: &mut Context<Self>,
10849    ) {
10850        let weak_editor = cx.weak_entity();
10851        let bp_prompt = cx.new(|cx| {
10852            BreakpointPromptEditor::new(
10853                weak_editor,
10854                anchor,
10855                breakpoint.clone(),
10856                edit_action,
10857                window,
10858                cx,
10859            )
10860        });
10861
10862        let height = bp_prompt.update(cx, |this, cx| {
10863            this.prompt
10864                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10865        });
10866        let cloned_prompt = bp_prompt.clone();
10867        let blocks = vec![BlockProperties {
10868            style: BlockStyle::Sticky,
10869            placement: BlockPlacement::Above(anchor),
10870            height: Some(height),
10871            render: Arc::new(move |cx| {
10872                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10873                cloned_prompt.clone().into_any_element()
10874            }),
10875            priority: 0,
10876        }];
10877
10878        let focus_handle = bp_prompt.focus_handle(cx);
10879        window.focus(&focus_handle);
10880
10881        let block_ids = self.insert_blocks(blocks, None, cx);
10882        bp_prompt.update(cx, |prompt, _| {
10883            prompt.add_block_ids(block_ids);
10884        });
10885    }
10886
10887    pub(crate) fn breakpoint_at_row(
10888        &self,
10889        row: u32,
10890        window: &mut Window,
10891        cx: &mut Context<Self>,
10892    ) -> Option<(Anchor, Breakpoint)> {
10893        let snapshot = self.snapshot(window, cx);
10894        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10895
10896        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10897    }
10898
10899    pub(crate) fn breakpoint_at_anchor(
10900        &self,
10901        breakpoint_position: Anchor,
10902        snapshot: &EditorSnapshot,
10903        cx: &mut Context<Self>,
10904    ) -> Option<(Anchor, Breakpoint)> {
10905        let buffer = self
10906            .buffer
10907            .read(cx)
10908            .buffer_for_anchor(breakpoint_position, cx)?;
10909
10910        let enclosing_excerpt = breakpoint_position.excerpt_id;
10911        let buffer_snapshot = buffer.read(cx).snapshot();
10912
10913        let row = buffer_snapshot
10914            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10915            .row;
10916
10917        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10918        let anchor_end = snapshot
10919            .buffer_snapshot
10920            .anchor_after(Point::new(row, line_len));
10921
10922        self.breakpoint_store
10923            .as_ref()?
10924            .read_with(cx, |breakpoint_store, cx| {
10925                breakpoint_store
10926                    .breakpoints(
10927                        &buffer,
10928                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10929                        &buffer_snapshot,
10930                        cx,
10931                    )
10932                    .next()
10933                    .and_then(|(bp, _)| {
10934                        let breakpoint_row = buffer_snapshot
10935                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10936                            .row;
10937
10938                        if breakpoint_row == row {
10939                            snapshot
10940                                .buffer_snapshot
10941                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10942                                .map(|position| (position, bp.bp.clone()))
10943                        } else {
10944                            None
10945                        }
10946                    })
10947            })
10948    }
10949
10950    pub fn edit_log_breakpoint(
10951        &mut self,
10952        _: &EditLogBreakpoint,
10953        window: &mut Window,
10954        cx: &mut Context<Self>,
10955    ) {
10956        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10957            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10958                message: None,
10959                state: BreakpointState::Enabled,
10960                condition: None,
10961                hit_condition: None,
10962            });
10963
10964            self.add_edit_breakpoint_block(
10965                anchor,
10966                &breakpoint,
10967                BreakpointPromptEditAction::Log,
10968                window,
10969                cx,
10970            );
10971        }
10972    }
10973
10974    fn breakpoints_at_cursors(
10975        &self,
10976        window: &mut Window,
10977        cx: &mut Context<Self>,
10978    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10979        let snapshot = self.snapshot(window, cx);
10980        let cursors = self
10981            .selections
10982            .disjoint_anchors_arc()
10983            .iter()
10984            .map(|selection| {
10985                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10986
10987                let breakpoint_position = self
10988                    .breakpoint_at_row(cursor_position.row, window, cx)
10989                    .map(|bp| bp.0)
10990                    .unwrap_or_else(|| {
10991                        snapshot
10992                            .display_snapshot
10993                            .buffer_snapshot
10994                            .anchor_after(Point::new(cursor_position.row, 0))
10995                    });
10996
10997                let breakpoint = self
10998                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10999                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11000
11001                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11002            })
11003            // 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.
11004            .collect::<HashMap<Anchor, _>>();
11005
11006        cursors.into_iter().collect()
11007    }
11008
11009    pub fn enable_breakpoint(
11010        &mut self,
11011        _: &crate::actions::EnableBreakpoint,
11012        window: &mut Window,
11013        cx: &mut Context<Self>,
11014    ) {
11015        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11016            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11017                continue;
11018            };
11019            self.edit_breakpoint_at_anchor(
11020                anchor,
11021                breakpoint,
11022                BreakpointEditAction::InvertState,
11023                cx,
11024            );
11025        }
11026    }
11027
11028    pub fn disable_breakpoint(
11029        &mut self,
11030        _: &crate::actions::DisableBreakpoint,
11031        window: &mut Window,
11032        cx: &mut Context<Self>,
11033    ) {
11034        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11035            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11036                continue;
11037            };
11038            self.edit_breakpoint_at_anchor(
11039                anchor,
11040                breakpoint,
11041                BreakpointEditAction::InvertState,
11042                cx,
11043            );
11044        }
11045    }
11046
11047    pub fn toggle_breakpoint(
11048        &mut self,
11049        _: &crate::actions::ToggleBreakpoint,
11050        window: &mut Window,
11051        cx: &mut Context<Self>,
11052    ) {
11053        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11054            if let Some(breakpoint) = breakpoint {
11055                self.edit_breakpoint_at_anchor(
11056                    anchor,
11057                    breakpoint,
11058                    BreakpointEditAction::Toggle,
11059                    cx,
11060                );
11061            } else {
11062                self.edit_breakpoint_at_anchor(
11063                    anchor,
11064                    Breakpoint::new_standard(),
11065                    BreakpointEditAction::Toggle,
11066                    cx,
11067                );
11068            }
11069        }
11070    }
11071
11072    pub fn edit_breakpoint_at_anchor(
11073        &mut self,
11074        breakpoint_position: Anchor,
11075        breakpoint: Breakpoint,
11076        edit_action: BreakpointEditAction,
11077        cx: &mut Context<Self>,
11078    ) {
11079        let Some(breakpoint_store) = &self.breakpoint_store else {
11080            return;
11081        };
11082
11083        let Some(buffer) = self
11084            .buffer
11085            .read(cx)
11086            .buffer_for_anchor(breakpoint_position, cx)
11087        else {
11088            return;
11089        };
11090
11091        breakpoint_store.update(cx, |breakpoint_store, cx| {
11092            breakpoint_store.toggle_breakpoint(
11093                buffer,
11094                BreakpointWithPosition {
11095                    position: breakpoint_position.text_anchor,
11096                    bp: breakpoint,
11097                },
11098                edit_action,
11099                cx,
11100            );
11101        });
11102
11103        cx.notify();
11104    }
11105
11106    #[cfg(any(test, feature = "test-support"))]
11107    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11108        self.breakpoint_store.clone()
11109    }
11110
11111    pub fn prepare_restore_change(
11112        &self,
11113        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11114        hunk: &MultiBufferDiffHunk,
11115        cx: &mut App,
11116    ) -> Option<()> {
11117        if hunk.is_created_file() {
11118            return None;
11119        }
11120        let buffer = self.buffer.read(cx);
11121        let diff = buffer.diff_for(hunk.buffer_id)?;
11122        let buffer = buffer.buffer(hunk.buffer_id)?;
11123        let buffer = buffer.read(cx);
11124        let original_text = diff
11125            .read(cx)
11126            .base_text()
11127            .as_rope()
11128            .slice(hunk.diff_base_byte_range.clone());
11129        let buffer_snapshot = buffer.snapshot();
11130        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11131        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11132            probe
11133                .0
11134                .start
11135                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11136                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11137        }) {
11138            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11139            Some(())
11140        } else {
11141            None
11142        }
11143    }
11144
11145    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11146        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11147    }
11148
11149    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11150        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11151    }
11152
11153    fn manipulate_lines<M>(
11154        &mut self,
11155        window: &mut Window,
11156        cx: &mut Context<Self>,
11157        mut manipulate: M,
11158    ) where
11159        M: FnMut(&str) -> LineManipulationResult,
11160    {
11161        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11162
11163        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11164        let buffer = self.buffer.read(cx).snapshot(cx);
11165
11166        let mut edits = Vec::new();
11167
11168        let selections = self.selections.all::<Point>(cx);
11169        let mut selections = selections.iter().peekable();
11170        let mut contiguous_row_selections = Vec::new();
11171        let mut new_selections = Vec::new();
11172        let mut added_lines = 0;
11173        let mut removed_lines = 0;
11174
11175        while let Some(selection) = selections.next() {
11176            let (start_row, end_row) = consume_contiguous_rows(
11177                &mut contiguous_row_selections,
11178                selection,
11179                &display_map,
11180                &mut selections,
11181            );
11182
11183            let start_point = Point::new(start_row.0, 0);
11184            let end_point = Point::new(
11185                end_row.previous_row().0,
11186                buffer.line_len(end_row.previous_row()),
11187            );
11188            let text = buffer
11189                .text_for_range(start_point..end_point)
11190                .collect::<String>();
11191
11192            let LineManipulationResult {
11193                new_text,
11194                line_count_before,
11195                line_count_after,
11196            } = manipulate(&text);
11197
11198            edits.push((start_point..end_point, new_text));
11199
11200            // Selections must change based on added and removed line count
11201            let start_row =
11202                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11203            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11204            new_selections.push(Selection {
11205                id: selection.id,
11206                start: start_row,
11207                end: end_row,
11208                goal: SelectionGoal::None,
11209                reversed: selection.reversed,
11210            });
11211
11212            if line_count_after > line_count_before {
11213                added_lines += line_count_after - line_count_before;
11214            } else if line_count_before > line_count_after {
11215                removed_lines += line_count_before - line_count_after;
11216            }
11217        }
11218
11219        self.transact(window, cx, |this, window, cx| {
11220            let buffer = this.buffer.update(cx, |buffer, cx| {
11221                buffer.edit(edits, None, cx);
11222                buffer.snapshot(cx)
11223            });
11224
11225            // Recalculate offsets on newly edited buffer
11226            let new_selections = new_selections
11227                .iter()
11228                .map(|s| {
11229                    let start_point = Point::new(s.start.0, 0);
11230                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11231                    Selection {
11232                        id: s.id,
11233                        start: buffer.point_to_offset(start_point),
11234                        end: buffer.point_to_offset(end_point),
11235                        goal: s.goal,
11236                        reversed: s.reversed,
11237                    }
11238                })
11239                .collect();
11240
11241            this.change_selections(Default::default(), window, cx, |s| {
11242                s.select(new_selections);
11243            });
11244
11245            this.request_autoscroll(Autoscroll::fit(), cx);
11246        });
11247    }
11248
11249    fn manipulate_immutable_lines<Fn>(
11250        &mut self,
11251        window: &mut Window,
11252        cx: &mut Context<Self>,
11253        mut callback: Fn,
11254    ) where
11255        Fn: FnMut(&mut Vec<&str>),
11256    {
11257        self.manipulate_lines(window, cx, |text| {
11258            let mut lines: Vec<&str> = text.split('\n').collect();
11259            let line_count_before = lines.len();
11260
11261            callback(&mut lines);
11262
11263            LineManipulationResult {
11264                new_text: lines.join("\n"),
11265                line_count_before,
11266                line_count_after: lines.len(),
11267            }
11268        });
11269    }
11270
11271    fn manipulate_mutable_lines<Fn>(
11272        &mut self,
11273        window: &mut Window,
11274        cx: &mut Context<Self>,
11275        mut callback: Fn,
11276    ) where
11277        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11278    {
11279        self.manipulate_lines(window, cx, |text| {
11280            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11281            let line_count_before = lines.len();
11282
11283            callback(&mut lines);
11284
11285            LineManipulationResult {
11286                new_text: lines.join("\n"),
11287                line_count_before,
11288                line_count_after: lines.len(),
11289            }
11290        });
11291    }
11292
11293    pub fn convert_indentation_to_spaces(
11294        &mut self,
11295        _: &ConvertIndentationToSpaces,
11296        window: &mut Window,
11297        cx: &mut Context<Self>,
11298    ) {
11299        let settings = self.buffer.read(cx).language_settings(cx);
11300        let tab_size = settings.tab_size.get() as usize;
11301
11302        self.manipulate_mutable_lines(window, cx, |lines| {
11303            // Allocates a reasonably sized scratch buffer once for the whole loop
11304            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11305            // Avoids recomputing spaces that could be inserted many times
11306            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11307                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11308                .collect();
11309
11310            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11311                let mut chars = line.as_ref().chars();
11312                let mut col = 0;
11313                let mut changed = false;
11314
11315                for ch in chars.by_ref() {
11316                    match ch {
11317                        ' ' => {
11318                            reindented_line.push(' ');
11319                            col += 1;
11320                        }
11321                        '\t' => {
11322                            // \t are converted to spaces depending on the current column
11323                            let spaces_len = tab_size - (col % tab_size);
11324                            reindented_line.extend(&space_cache[spaces_len - 1]);
11325                            col += spaces_len;
11326                            changed = true;
11327                        }
11328                        _ => {
11329                            // If we dont append before break, the character is consumed
11330                            reindented_line.push(ch);
11331                            break;
11332                        }
11333                    }
11334                }
11335
11336                if !changed {
11337                    reindented_line.clear();
11338                    continue;
11339                }
11340                // Append the rest of the line and replace old reference with new one
11341                reindented_line.extend(chars);
11342                *line = Cow::Owned(reindented_line.clone());
11343                reindented_line.clear();
11344            }
11345        });
11346    }
11347
11348    pub fn convert_indentation_to_tabs(
11349        &mut self,
11350        _: &ConvertIndentationToTabs,
11351        window: &mut Window,
11352        cx: &mut Context<Self>,
11353    ) {
11354        let settings = self.buffer.read(cx).language_settings(cx);
11355        let tab_size = settings.tab_size.get() as usize;
11356
11357        self.manipulate_mutable_lines(window, cx, |lines| {
11358            // Allocates a reasonably sized buffer once for the whole loop
11359            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11360            // Avoids recomputing spaces that could be inserted many times
11361            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11362                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11363                .collect();
11364
11365            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11366                let mut chars = line.chars();
11367                let mut spaces_count = 0;
11368                let mut first_non_indent_char = None;
11369                let mut changed = false;
11370
11371                for ch in chars.by_ref() {
11372                    match ch {
11373                        ' ' => {
11374                            // Keep track of spaces. Append \t when we reach tab_size
11375                            spaces_count += 1;
11376                            changed = true;
11377                            if spaces_count == tab_size {
11378                                reindented_line.push('\t');
11379                                spaces_count = 0;
11380                            }
11381                        }
11382                        '\t' => {
11383                            reindented_line.push('\t');
11384                            spaces_count = 0;
11385                        }
11386                        _ => {
11387                            // Dont append it yet, we might have remaining spaces
11388                            first_non_indent_char = Some(ch);
11389                            break;
11390                        }
11391                    }
11392                }
11393
11394                if !changed {
11395                    reindented_line.clear();
11396                    continue;
11397                }
11398                // Remaining spaces that didn't make a full tab stop
11399                if spaces_count > 0 {
11400                    reindented_line.extend(&space_cache[spaces_count - 1]);
11401                }
11402                // If we consume an extra character that was not indentation, add it back
11403                if let Some(extra_char) = first_non_indent_char {
11404                    reindented_line.push(extra_char);
11405                }
11406                // Append the rest of the line and replace old reference with new one
11407                reindented_line.extend(chars);
11408                *line = Cow::Owned(reindented_line.clone());
11409                reindented_line.clear();
11410            }
11411        });
11412    }
11413
11414    pub fn convert_to_upper_case(
11415        &mut self,
11416        _: &ConvertToUpperCase,
11417        window: &mut Window,
11418        cx: &mut Context<Self>,
11419    ) {
11420        self.manipulate_text(window, cx, |text| text.to_uppercase())
11421    }
11422
11423    pub fn convert_to_lower_case(
11424        &mut self,
11425        _: &ConvertToLowerCase,
11426        window: &mut Window,
11427        cx: &mut Context<Self>,
11428    ) {
11429        self.manipulate_text(window, cx, |text| text.to_lowercase())
11430    }
11431
11432    pub fn convert_to_title_case(
11433        &mut self,
11434        _: &ConvertToTitleCase,
11435        window: &mut Window,
11436        cx: &mut Context<Self>,
11437    ) {
11438        self.manipulate_text(window, cx, |text| {
11439            text.split('\n')
11440                .map(|line| line.to_case(Case::Title))
11441                .join("\n")
11442        })
11443    }
11444
11445    pub fn convert_to_snake_case(
11446        &mut self,
11447        _: &ConvertToSnakeCase,
11448        window: &mut Window,
11449        cx: &mut Context<Self>,
11450    ) {
11451        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11452    }
11453
11454    pub fn convert_to_kebab_case(
11455        &mut self,
11456        _: &ConvertToKebabCase,
11457        window: &mut Window,
11458        cx: &mut Context<Self>,
11459    ) {
11460        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11461    }
11462
11463    pub fn convert_to_upper_camel_case(
11464        &mut self,
11465        _: &ConvertToUpperCamelCase,
11466        window: &mut Window,
11467        cx: &mut Context<Self>,
11468    ) {
11469        self.manipulate_text(window, cx, |text| {
11470            text.split('\n')
11471                .map(|line| line.to_case(Case::UpperCamel))
11472                .join("\n")
11473        })
11474    }
11475
11476    pub fn convert_to_lower_camel_case(
11477        &mut self,
11478        _: &ConvertToLowerCamelCase,
11479        window: &mut Window,
11480        cx: &mut Context<Self>,
11481    ) {
11482        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11483    }
11484
11485    pub fn convert_to_opposite_case(
11486        &mut self,
11487        _: &ConvertToOppositeCase,
11488        window: &mut Window,
11489        cx: &mut Context<Self>,
11490    ) {
11491        self.manipulate_text(window, cx, |text| {
11492            text.chars()
11493                .fold(String::with_capacity(text.len()), |mut t, c| {
11494                    if c.is_uppercase() {
11495                        t.extend(c.to_lowercase());
11496                    } else {
11497                        t.extend(c.to_uppercase());
11498                    }
11499                    t
11500                })
11501        })
11502    }
11503
11504    pub fn convert_to_sentence_case(
11505        &mut self,
11506        _: &ConvertToSentenceCase,
11507        window: &mut Window,
11508        cx: &mut Context<Self>,
11509    ) {
11510        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11511    }
11512
11513    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11514        self.manipulate_text(window, cx, |text| {
11515            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11516            if has_upper_case_characters {
11517                text.to_lowercase()
11518            } else {
11519                text.to_uppercase()
11520            }
11521        })
11522    }
11523
11524    pub fn convert_to_rot13(
11525        &mut self,
11526        _: &ConvertToRot13,
11527        window: &mut Window,
11528        cx: &mut Context<Self>,
11529    ) {
11530        self.manipulate_text(window, cx, |text| {
11531            text.chars()
11532                .map(|c| match c {
11533                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11534                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11535                    _ => c,
11536                })
11537                .collect()
11538        })
11539    }
11540
11541    pub fn convert_to_rot47(
11542        &mut self,
11543        _: &ConvertToRot47,
11544        window: &mut Window,
11545        cx: &mut Context<Self>,
11546    ) {
11547        self.manipulate_text(window, cx, |text| {
11548            text.chars()
11549                .map(|c| {
11550                    let code_point = c as u32;
11551                    if code_point >= 33 && code_point <= 126 {
11552                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11553                    }
11554                    c
11555                })
11556                .collect()
11557        })
11558    }
11559
11560    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11561    where
11562        Fn: FnMut(&str) -> String,
11563    {
11564        let buffer = self.buffer.read(cx).snapshot(cx);
11565
11566        let mut new_selections = Vec::new();
11567        let mut edits = Vec::new();
11568        let mut selection_adjustment = 0i32;
11569
11570        for selection in self.selections.all_adjusted(cx) {
11571            let selection_is_empty = selection.is_empty();
11572
11573            let (start, end) = if selection_is_empty {
11574                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11575                (word_range.start, word_range.end)
11576            } else {
11577                (
11578                    buffer.point_to_offset(selection.start),
11579                    buffer.point_to_offset(selection.end),
11580                )
11581            };
11582
11583            let text = buffer.text_for_range(start..end).collect::<String>();
11584            let old_length = text.len() as i32;
11585            let text = callback(&text);
11586
11587            new_selections.push(Selection {
11588                start: (start as i32 - selection_adjustment) as usize,
11589                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11590                goal: SelectionGoal::None,
11591                id: selection.id,
11592                reversed: selection.reversed,
11593            });
11594
11595            selection_adjustment += old_length - text.len() as i32;
11596
11597            edits.push((start..end, text));
11598        }
11599
11600        self.transact(window, cx, |this, window, cx| {
11601            this.buffer.update(cx, |buffer, cx| {
11602                buffer.edit(edits, None, cx);
11603            });
11604
11605            this.change_selections(Default::default(), window, cx, |s| {
11606                s.select(new_selections);
11607            });
11608
11609            this.request_autoscroll(Autoscroll::fit(), cx);
11610        });
11611    }
11612
11613    pub fn move_selection_on_drop(
11614        &mut self,
11615        selection: &Selection<Anchor>,
11616        target: DisplayPoint,
11617        is_cut: bool,
11618        window: &mut Window,
11619        cx: &mut Context<Self>,
11620    ) {
11621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11622        let buffer = &display_map.buffer_snapshot;
11623        let mut edits = Vec::new();
11624        let insert_point = display_map
11625            .clip_point(target, Bias::Left)
11626            .to_point(&display_map);
11627        let text = buffer
11628            .text_for_range(selection.start..selection.end)
11629            .collect::<String>();
11630        if is_cut {
11631            edits.push(((selection.start..selection.end), String::new()));
11632        }
11633        let insert_anchor = buffer.anchor_before(insert_point);
11634        edits.push(((insert_anchor..insert_anchor), text));
11635        let last_edit_start = insert_anchor.bias_left(buffer);
11636        let last_edit_end = insert_anchor.bias_right(buffer);
11637        self.transact(window, cx, |this, window, cx| {
11638            this.buffer.update(cx, |buffer, cx| {
11639                buffer.edit(edits, None, cx);
11640            });
11641            this.change_selections(Default::default(), window, cx, |s| {
11642                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11643            });
11644        });
11645    }
11646
11647    pub fn clear_selection_drag_state(&mut self) {
11648        self.selection_drag_state = SelectionDragState::None;
11649    }
11650
11651    pub fn duplicate(
11652        &mut self,
11653        upwards: bool,
11654        whole_lines: bool,
11655        window: &mut Window,
11656        cx: &mut Context<Self>,
11657    ) {
11658        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11659
11660        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11661        let buffer = &display_map.buffer_snapshot;
11662        let selections = self.selections.all::<Point>(cx);
11663
11664        let mut edits = Vec::new();
11665        let mut selections_iter = selections.iter().peekable();
11666        while let Some(selection) = selections_iter.next() {
11667            let mut rows = selection.spanned_rows(false, &display_map);
11668            // duplicate line-wise
11669            if whole_lines || selection.start == selection.end {
11670                // Avoid duplicating the same lines twice.
11671                while let Some(next_selection) = selections_iter.peek() {
11672                    let next_rows = next_selection.spanned_rows(false, &display_map);
11673                    if next_rows.start < rows.end {
11674                        rows.end = next_rows.end;
11675                        selections_iter.next().unwrap();
11676                    } else {
11677                        break;
11678                    }
11679                }
11680
11681                // Copy the text from the selected row region and splice it either at the start
11682                // or end of the region.
11683                let start = Point::new(rows.start.0, 0);
11684                let end = Point::new(
11685                    rows.end.previous_row().0,
11686                    buffer.line_len(rows.end.previous_row()),
11687                );
11688                let text = buffer
11689                    .text_for_range(start..end)
11690                    .chain(Some("\n"))
11691                    .collect::<String>();
11692                let insert_location = if upwards {
11693                    Point::new(rows.end.0, 0)
11694                } else {
11695                    start
11696                };
11697                edits.push((insert_location..insert_location, text));
11698            } else {
11699                // duplicate character-wise
11700                let start = selection.start;
11701                let end = selection.end;
11702                let text = buffer.text_for_range(start..end).collect::<String>();
11703                edits.push((selection.end..selection.end, text));
11704            }
11705        }
11706
11707        self.transact(window, cx, |this, _, cx| {
11708            this.buffer.update(cx, |buffer, cx| {
11709                buffer.edit(edits, None, cx);
11710            });
11711
11712            this.request_autoscroll(Autoscroll::fit(), cx);
11713        });
11714    }
11715
11716    pub fn duplicate_line_up(
11717        &mut self,
11718        _: &DuplicateLineUp,
11719        window: &mut Window,
11720        cx: &mut Context<Self>,
11721    ) {
11722        self.duplicate(true, true, window, cx);
11723    }
11724
11725    pub fn duplicate_line_down(
11726        &mut self,
11727        _: &DuplicateLineDown,
11728        window: &mut Window,
11729        cx: &mut Context<Self>,
11730    ) {
11731        self.duplicate(false, true, window, cx);
11732    }
11733
11734    pub fn duplicate_selection(
11735        &mut self,
11736        _: &DuplicateSelection,
11737        window: &mut Window,
11738        cx: &mut Context<Self>,
11739    ) {
11740        self.duplicate(false, false, window, cx);
11741    }
11742
11743    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11744        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11745        if self.mode.is_single_line() {
11746            cx.propagate();
11747            return;
11748        }
11749
11750        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11751        let buffer = self.buffer.read(cx).snapshot(cx);
11752
11753        let mut edits = Vec::new();
11754        let mut unfold_ranges = Vec::new();
11755        let mut refold_creases = Vec::new();
11756
11757        let selections = self.selections.all::<Point>(cx);
11758        let mut selections = selections.iter().peekable();
11759        let mut contiguous_row_selections = Vec::new();
11760        let mut new_selections = Vec::new();
11761
11762        while let Some(selection) = selections.next() {
11763            // Find all the selections that span a contiguous row range
11764            let (start_row, end_row) = consume_contiguous_rows(
11765                &mut contiguous_row_selections,
11766                selection,
11767                &display_map,
11768                &mut selections,
11769            );
11770
11771            // Move the text spanned by the row range to be before the line preceding the row range
11772            if start_row.0 > 0 {
11773                let range_to_move = Point::new(
11774                    start_row.previous_row().0,
11775                    buffer.line_len(start_row.previous_row()),
11776                )
11777                    ..Point::new(
11778                        end_row.previous_row().0,
11779                        buffer.line_len(end_row.previous_row()),
11780                    );
11781                let insertion_point = display_map
11782                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11783                    .0;
11784
11785                // Don't move lines across excerpts
11786                if buffer
11787                    .excerpt_containing(insertion_point..range_to_move.end)
11788                    .is_some()
11789                {
11790                    let text = buffer
11791                        .text_for_range(range_to_move.clone())
11792                        .flat_map(|s| s.chars())
11793                        .skip(1)
11794                        .chain(['\n'])
11795                        .collect::<String>();
11796
11797                    edits.push((
11798                        buffer.anchor_after(range_to_move.start)
11799                            ..buffer.anchor_before(range_to_move.end),
11800                        String::new(),
11801                    ));
11802                    let insertion_anchor = buffer.anchor_after(insertion_point);
11803                    edits.push((insertion_anchor..insertion_anchor, text));
11804
11805                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11806
11807                    // Move selections up
11808                    new_selections.extend(contiguous_row_selections.drain(..).map(
11809                        |mut selection| {
11810                            selection.start.row -= row_delta;
11811                            selection.end.row -= row_delta;
11812                            selection
11813                        },
11814                    ));
11815
11816                    // Move folds up
11817                    unfold_ranges.push(range_to_move.clone());
11818                    for fold in display_map.folds_in_range(
11819                        buffer.anchor_before(range_to_move.start)
11820                            ..buffer.anchor_after(range_to_move.end),
11821                    ) {
11822                        let mut start = fold.range.start.to_point(&buffer);
11823                        let mut end = fold.range.end.to_point(&buffer);
11824                        start.row -= row_delta;
11825                        end.row -= row_delta;
11826                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11827                    }
11828                }
11829            }
11830
11831            // If we didn't move line(s), preserve the existing selections
11832            new_selections.append(&mut contiguous_row_selections);
11833        }
11834
11835        self.transact(window, cx, |this, window, cx| {
11836            this.unfold_ranges(&unfold_ranges, true, true, cx);
11837            this.buffer.update(cx, |buffer, cx| {
11838                for (range, text) in edits {
11839                    buffer.edit([(range, text)], None, cx);
11840                }
11841            });
11842            this.fold_creases(refold_creases, true, window, cx);
11843            this.change_selections(Default::default(), window, cx, |s| {
11844                s.select(new_selections);
11845            })
11846        });
11847    }
11848
11849    pub fn move_line_down(
11850        &mut self,
11851        _: &MoveLineDown,
11852        window: &mut Window,
11853        cx: &mut Context<Self>,
11854    ) {
11855        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11856        if self.mode.is_single_line() {
11857            cx.propagate();
11858            return;
11859        }
11860
11861        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11862        let buffer = self.buffer.read(cx).snapshot(cx);
11863
11864        let mut edits = Vec::new();
11865        let mut unfold_ranges = Vec::new();
11866        let mut refold_creases = Vec::new();
11867
11868        let selections = self.selections.all::<Point>(cx);
11869        let mut selections = selections.iter().peekable();
11870        let mut contiguous_row_selections = Vec::new();
11871        let mut new_selections = Vec::new();
11872
11873        while let Some(selection) = selections.next() {
11874            // Find all the selections that span a contiguous row range
11875            let (start_row, end_row) = consume_contiguous_rows(
11876                &mut contiguous_row_selections,
11877                selection,
11878                &display_map,
11879                &mut selections,
11880            );
11881
11882            // Move the text spanned by the row range to be after the last line of the row range
11883            if end_row.0 <= buffer.max_point().row {
11884                let range_to_move =
11885                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11886                let insertion_point = display_map
11887                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11888                    .0;
11889
11890                // Don't move lines across excerpt boundaries
11891                if buffer
11892                    .excerpt_containing(range_to_move.start..insertion_point)
11893                    .is_some()
11894                {
11895                    let mut text = String::from("\n");
11896                    text.extend(buffer.text_for_range(range_to_move.clone()));
11897                    text.pop(); // Drop trailing newline
11898                    edits.push((
11899                        buffer.anchor_after(range_to_move.start)
11900                            ..buffer.anchor_before(range_to_move.end),
11901                        String::new(),
11902                    ));
11903                    let insertion_anchor = buffer.anchor_after(insertion_point);
11904                    edits.push((insertion_anchor..insertion_anchor, text));
11905
11906                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11907
11908                    // Move selections down
11909                    new_selections.extend(contiguous_row_selections.drain(..).map(
11910                        |mut selection| {
11911                            selection.start.row += row_delta;
11912                            selection.end.row += row_delta;
11913                            selection
11914                        },
11915                    ));
11916
11917                    // Move folds down
11918                    unfold_ranges.push(range_to_move.clone());
11919                    for fold in display_map.folds_in_range(
11920                        buffer.anchor_before(range_to_move.start)
11921                            ..buffer.anchor_after(range_to_move.end),
11922                    ) {
11923                        let mut start = fold.range.start.to_point(&buffer);
11924                        let mut end = fold.range.end.to_point(&buffer);
11925                        start.row += row_delta;
11926                        end.row += row_delta;
11927                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11928                    }
11929                }
11930            }
11931
11932            // If we didn't move line(s), preserve the existing selections
11933            new_selections.append(&mut contiguous_row_selections);
11934        }
11935
11936        self.transact(window, cx, |this, window, cx| {
11937            this.unfold_ranges(&unfold_ranges, true, true, cx);
11938            this.buffer.update(cx, |buffer, cx| {
11939                for (range, text) in edits {
11940                    buffer.edit([(range, text)], None, cx);
11941                }
11942            });
11943            this.fold_creases(refold_creases, true, window, cx);
11944            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11945        });
11946    }
11947
11948    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11950        let text_layout_details = &self.text_layout_details(window);
11951        self.transact(window, cx, |this, window, cx| {
11952            let edits = this.change_selections(Default::default(), window, cx, |s| {
11953                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11954                s.move_with(|display_map, selection| {
11955                    if !selection.is_empty() {
11956                        return;
11957                    }
11958
11959                    let mut head = selection.head();
11960                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11961                    if head.column() == display_map.line_len(head.row()) {
11962                        transpose_offset = display_map
11963                            .buffer_snapshot
11964                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11965                    }
11966
11967                    if transpose_offset == 0 {
11968                        return;
11969                    }
11970
11971                    *head.column_mut() += 1;
11972                    head = display_map.clip_point(head, Bias::Right);
11973                    let goal = SelectionGoal::HorizontalPosition(
11974                        display_map
11975                            .x_for_display_point(head, text_layout_details)
11976                            .into(),
11977                    );
11978                    selection.collapse_to(head, goal);
11979
11980                    let transpose_start = display_map
11981                        .buffer_snapshot
11982                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11983                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11984                        let transpose_end = display_map
11985                            .buffer_snapshot
11986                            .clip_offset(transpose_offset + 1, Bias::Right);
11987                        if let Some(ch) =
11988                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11989                        {
11990                            edits.push((transpose_start..transpose_offset, String::new()));
11991                            edits.push((transpose_end..transpose_end, ch.to_string()));
11992                        }
11993                    }
11994                });
11995                edits
11996            });
11997            this.buffer
11998                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11999            let selections = this.selections.all::<usize>(cx);
12000            this.change_selections(Default::default(), window, cx, |s| {
12001                s.select(selections);
12002            });
12003        });
12004    }
12005
12006    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12007        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12008        if self.mode.is_single_line() {
12009            cx.propagate();
12010            return;
12011        }
12012
12013        self.rewrap_impl(RewrapOptions::default(), cx)
12014    }
12015
12016    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12017        let buffer = self.buffer.read(cx).snapshot(cx);
12018        let selections = self.selections.all::<Point>(cx);
12019
12020        #[derive(Clone, Debug, PartialEq)]
12021        enum CommentFormat {
12022            /// single line comment, with prefix for line
12023            Line(String),
12024            /// single line within a block comment, with prefix for line
12025            BlockLine(String),
12026            /// a single line of a block comment that includes the initial delimiter
12027            BlockCommentWithStart(BlockCommentConfig),
12028            /// a single line of a block comment that includes the ending delimiter
12029            BlockCommentWithEnd(BlockCommentConfig),
12030        }
12031
12032        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12033        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12034            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12035                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12036                .peekable();
12037
12038            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12039                row
12040            } else {
12041                return Vec::new();
12042            };
12043
12044            let language_settings = buffer.language_settings_at(selection.head(), cx);
12045            let language_scope = buffer.language_scope_at(selection.head());
12046
12047            let indent_and_prefix_for_row =
12048                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12049                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12050                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12051                        &language_scope
12052                    {
12053                        let indent_end = Point::new(row, indent.len);
12054                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12055                        let line_text_after_indent = buffer
12056                            .text_for_range(indent_end..line_end)
12057                            .collect::<String>();
12058
12059                        let is_within_comment_override = buffer
12060                            .language_scope_at(indent_end)
12061                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12062                        let comment_delimiters = if is_within_comment_override {
12063                            // we are within a comment syntax node, but we don't
12064                            // yet know what kind of comment: block, doc or line
12065                            match (
12066                                language_scope.documentation_comment(),
12067                                language_scope.block_comment(),
12068                            ) {
12069                                (Some(config), _) | (_, Some(config))
12070                                    if buffer.contains_str_at(indent_end, &config.start) =>
12071                                {
12072                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12073                                }
12074                                (Some(config), _) | (_, Some(config))
12075                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12076                                {
12077                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12078                                }
12079                                (Some(config), _) | (_, Some(config))
12080                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12081                                {
12082                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12083                                }
12084                                (_, _) => language_scope
12085                                    .line_comment_prefixes()
12086                                    .iter()
12087                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12088                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12089                            }
12090                        } else {
12091                            // we not in an overridden comment node, but we may
12092                            // be within a non-overridden line comment node
12093                            language_scope
12094                                .line_comment_prefixes()
12095                                .iter()
12096                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12097                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12098                        };
12099
12100                        let rewrap_prefix = language_scope
12101                            .rewrap_prefixes()
12102                            .iter()
12103                            .find_map(|prefix_regex| {
12104                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12105                                    if mat.start() == 0 {
12106                                        Some(mat.as_str().to_string())
12107                                    } else {
12108                                        None
12109                                    }
12110                                })
12111                            })
12112                            .flatten();
12113                        (comment_delimiters, rewrap_prefix)
12114                    } else {
12115                        (None, None)
12116                    };
12117                    (indent, comment_prefix, rewrap_prefix)
12118                };
12119
12120            let mut ranges = Vec::new();
12121            let from_empty_selection = selection.is_empty();
12122
12123            let mut current_range_start = first_row;
12124            let mut prev_row = first_row;
12125            let (
12126                mut current_range_indent,
12127                mut current_range_comment_delimiters,
12128                mut current_range_rewrap_prefix,
12129            ) = indent_and_prefix_for_row(first_row);
12130
12131            for row in non_blank_rows_iter.skip(1) {
12132                let has_paragraph_break = row > prev_row + 1;
12133
12134                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12135                    indent_and_prefix_for_row(row);
12136
12137                let has_indent_change = row_indent != current_range_indent;
12138                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12139
12140                let has_boundary_change = has_comment_change
12141                    || row_rewrap_prefix.is_some()
12142                    || (has_indent_change && current_range_comment_delimiters.is_some());
12143
12144                if has_paragraph_break || has_boundary_change {
12145                    ranges.push((
12146                        language_settings.clone(),
12147                        Point::new(current_range_start, 0)
12148                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12149                        current_range_indent,
12150                        current_range_comment_delimiters.clone(),
12151                        current_range_rewrap_prefix.clone(),
12152                        from_empty_selection,
12153                    ));
12154                    current_range_start = row;
12155                    current_range_indent = row_indent;
12156                    current_range_comment_delimiters = row_comment_delimiters;
12157                    current_range_rewrap_prefix = row_rewrap_prefix;
12158                }
12159                prev_row = row;
12160            }
12161
12162            ranges.push((
12163                language_settings.clone(),
12164                Point::new(current_range_start, 0)
12165                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12166                current_range_indent,
12167                current_range_comment_delimiters,
12168                current_range_rewrap_prefix,
12169                from_empty_selection,
12170            ));
12171
12172            ranges
12173        });
12174
12175        let mut edits = Vec::new();
12176        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12177
12178        for (
12179            language_settings,
12180            wrap_range,
12181            mut indent_size,
12182            comment_prefix,
12183            rewrap_prefix,
12184            from_empty_selection,
12185        ) in wrap_ranges
12186        {
12187            let mut start_row = wrap_range.start.row;
12188            let mut end_row = wrap_range.end.row;
12189
12190            // Skip selections that overlap with a range that has already been rewrapped.
12191            let selection_range = start_row..end_row;
12192            if rewrapped_row_ranges
12193                .iter()
12194                .any(|range| range.overlaps(&selection_range))
12195            {
12196                continue;
12197            }
12198
12199            let tab_size = language_settings.tab_size;
12200
12201            let (line_prefix, inside_comment) = match &comment_prefix {
12202                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12203                    (Some(prefix.as_str()), true)
12204                }
12205                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12206                    (Some(prefix.as_ref()), true)
12207                }
12208                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12209                    start: _,
12210                    end: _,
12211                    prefix,
12212                    tab_size,
12213                })) => {
12214                    indent_size.len += tab_size;
12215                    (Some(prefix.as_ref()), true)
12216                }
12217                None => (None, false),
12218            };
12219            let indent_prefix = indent_size.chars().collect::<String>();
12220            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12221
12222            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12223                RewrapBehavior::InComments => inside_comment,
12224                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12225                RewrapBehavior::Anywhere => true,
12226            };
12227
12228            let should_rewrap = options.override_language_settings
12229                || allow_rewrap_based_on_language
12230                || self.hard_wrap.is_some();
12231            if !should_rewrap {
12232                continue;
12233            }
12234
12235            if from_empty_selection {
12236                'expand_upwards: while start_row > 0 {
12237                    let prev_row = start_row - 1;
12238                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12239                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12240                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12241                    {
12242                        start_row = prev_row;
12243                    } else {
12244                        break 'expand_upwards;
12245                    }
12246                }
12247
12248                'expand_downwards: while end_row < buffer.max_point().row {
12249                    let next_row = end_row + 1;
12250                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12251                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12252                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12253                    {
12254                        end_row = next_row;
12255                    } else {
12256                        break 'expand_downwards;
12257                    }
12258                }
12259            }
12260
12261            let start = Point::new(start_row, 0);
12262            let start_offset = start.to_offset(&buffer);
12263            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12264            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12265            let mut first_line_delimiter = None;
12266            let mut last_line_delimiter = None;
12267            let Some(lines_without_prefixes) = selection_text
12268                .lines()
12269                .enumerate()
12270                .map(|(ix, line)| {
12271                    let line_trimmed = line.trim_start();
12272                    if rewrap_prefix.is_some() && ix > 0 {
12273                        Ok(line_trimmed)
12274                    } else if let Some(
12275                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12276                            start,
12277                            prefix,
12278                            end,
12279                            tab_size,
12280                        })
12281                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12282                            start,
12283                            prefix,
12284                            end,
12285                            tab_size,
12286                        }),
12287                    ) = &comment_prefix
12288                    {
12289                        let line_trimmed = line_trimmed
12290                            .strip_prefix(start.as_ref())
12291                            .map(|s| {
12292                                let mut indent_size = indent_size;
12293                                indent_size.len -= tab_size;
12294                                let indent_prefix: String = indent_size.chars().collect();
12295                                first_line_delimiter = Some((indent_prefix, start));
12296                                s.trim_start()
12297                            })
12298                            .unwrap_or(line_trimmed);
12299                        let line_trimmed = line_trimmed
12300                            .strip_suffix(end.as_ref())
12301                            .map(|s| {
12302                                last_line_delimiter = Some(end);
12303                                s.trim_end()
12304                            })
12305                            .unwrap_or(line_trimmed);
12306                        let line_trimmed = line_trimmed
12307                            .strip_prefix(prefix.as_ref())
12308                            .unwrap_or(line_trimmed);
12309                        Ok(line_trimmed)
12310                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12311                        line_trimmed.strip_prefix(prefix).with_context(|| {
12312                            format!("line did not start with prefix {prefix:?}: {line:?}")
12313                        })
12314                    } else {
12315                        line_trimmed
12316                            .strip_prefix(&line_prefix.trim_start())
12317                            .with_context(|| {
12318                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12319                            })
12320                    }
12321                })
12322                .collect::<Result<Vec<_>, _>>()
12323                .log_err()
12324            else {
12325                continue;
12326            };
12327
12328            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12329                buffer
12330                    .language_settings_at(Point::new(start_row, 0), cx)
12331                    .preferred_line_length as usize
12332            });
12333
12334            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12335                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12336            } else {
12337                line_prefix.clone()
12338            };
12339
12340            let wrapped_text = {
12341                let mut wrapped_text = wrap_with_prefix(
12342                    line_prefix,
12343                    subsequent_lines_prefix,
12344                    lines_without_prefixes.join("\n"),
12345                    wrap_column,
12346                    tab_size,
12347                    options.preserve_existing_whitespace,
12348                );
12349
12350                if let Some((indent, delimiter)) = first_line_delimiter {
12351                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12352                }
12353                if let Some(last_line) = last_line_delimiter {
12354                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12355                }
12356
12357                wrapped_text
12358            };
12359
12360            // TODO: should always use char-based diff while still supporting cursor behavior that
12361            // matches vim.
12362            let mut diff_options = DiffOptions::default();
12363            if options.override_language_settings {
12364                diff_options.max_word_diff_len = 0;
12365                diff_options.max_word_diff_line_count = 0;
12366            } else {
12367                diff_options.max_word_diff_len = usize::MAX;
12368                diff_options.max_word_diff_line_count = usize::MAX;
12369            }
12370
12371            for (old_range, new_text) in
12372                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12373            {
12374                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12375                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12376                edits.push((edit_start..edit_end, new_text));
12377            }
12378
12379            rewrapped_row_ranges.push(start_row..=end_row);
12380        }
12381
12382        self.buffer
12383            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12384    }
12385
12386    pub fn cut_common(
12387        &mut self,
12388        cut_no_selection_line: bool,
12389        window: &mut Window,
12390        cx: &mut Context<Self>,
12391    ) -> ClipboardItem {
12392        let mut text = String::new();
12393        let buffer = self.buffer.read(cx).snapshot(cx);
12394        let mut selections = self.selections.all::<Point>(cx);
12395        let mut clipboard_selections = Vec::with_capacity(selections.len());
12396        {
12397            let max_point = buffer.max_point();
12398            let mut is_first = true;
12399            for selection in &mut selections {
12400                let is_entire_line =
12401                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12402                if is_entire_line {
12403                    selection.start = Point::new(selection.start.row, 0);
12404                    if !selection.is_empty() && selection.end.column == 0 {
12405                        selection.end = cmp::min(max_point, selection.end);
12406                    } else {
12407                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12408                    }
12409                    selection.goal = SelectionGoal::None;
12410                }
12411                if is_first {
12412                    is_first = false;
12413                } else {
12414                    text += "\n";
12415                }
12416                let mut len = 0;
12417                for chunk in buffer.text_for_range(selection.start..selection.end) {
12418                    text.push_str(chunk);
12419                    len += chunk.len();
12420                }
12421                clipboard_selections.push(ClipboardSelection {
12422                    len,
12423                    is_entire_line,
12424                    first_line_indent: buffer
12425                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12426                        .len,
12427                });
12428            }
12429        }
12430
12431        self.transact(window, cx, |this, window, cx| {
12432            this.change_selections(Default::default(), window, cx, |s| {
12433                s.select(selections);
12434            });
12435            this.insert("", window, cx);
12436        });
12437        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12438    }
12439
12440    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12441        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12442        let item = self.cut_common(true, window, cx);
12443        cx.write_to_clipboard(item);
12444    }
12445
12446    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12447        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12448        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12449            s.move_with(|snapshot, sel| {
12450                if sel.is_empty() {
12451                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12452                }
12453                if sel.is_empty() {
12454                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12455                }
12456            });
12457        });
12458        let item = self.cut_common(false, window, cx);
12459        cx.set_global(KillRing(item))
12460    }
12461
12462    pub fn kill_ring_yank(
12463        &mut self,
12464        _: &KillRingYank,
12465        window: &mut Window,
12466        cx: &mut Context<Self>,
12467    ) {
12468        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12469        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12470            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12471                (kill_ring.text().to_string(), kill_ring.metadata_json())
12472            } else {
12473                return;
12474            }
12475        } else {
12476            return;
12477        };
12478        self.do_paste(&text, metadata, false, window, cx);
12479    }
12480
12481    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12482        self.do_copy(true, cx);
12483    }
12484
12485    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12486        self.do_copy(false, cx);
12487    }
12488
12489    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12490        let selections = self.selections.all::<Point>(cx);
12491        let buffer = self.buffer.read(cx).read(cx);
12492        let mut text = String::new();
12493
12494        let mut clipboard_selections = Vec::with_capacity(selections.len());
12495        {
12496            let max_point = buffer.max_point();
12497            let mut is_first = true;
12498            for selection in &selections {
12499                let mut start = selection.start;
12500                let mut end = selection.end;
12501                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12502                if is_entire_line {
12503                    start = Point::new(start.row, 0);
12504                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12505                }
12506
12507                let mut trimmed_selections = Vec::new();
12508                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12509                    let row = MultiBufferRow(start.row);
12510                    let first_indent = buffer.indent_size_for_line(row);
12511                    if first_indent.len == 0 || start.column > first_indent.len {
12512                        trimmed_selections.push(start..end);
12513                    } else {
12514                        trimmed_selections.push(
12515                            Point::new(row.0, first_indent.len)
12516                                ..Point::new(row.0, buffer.line_len(row)),
12517                        );
12518                        for row in start.row + 1..=end.row {
12519                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12520                            if row == end.row {
12521                                line_len = end.column;
12522                            }
12523                            if line_len == 0 {
12524                                trimmed_selections
12525                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12526                                continue;
12527                            }
12528                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12529                            if row_indent_size.len >= first_indent.len {
12530                                trimmed_selections.push(
12531                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12532                                );
12533                            } else {
12534                                trimmed_selections.clear();
12535                                trimmed_selections.push(start..end);
12536                                break;
12537                            }
12538                        }
12539                    }
12540                } else {
12541                    trimmed_selections.push(start..end);
12542                }
12543
12544                for trimmed_range in trimmed_selections {
12545                    if is_first {
12546                        is_first = false;
12547                    } else {
12548                        text += "\n";
12549                    }
12550                    let mut len = 0;
12551                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12552                        text.push_str(chunk);
12553                        len += chunk.len();
12554                    }
12555                    clipboard_selections.push(ClipboardSelection {
12556                        len,
12557                        is_entire_line,
12558                        first_line_indent: buffer
12559                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12560                            .len,
12561                    });
12562                }
12563            }
12564        }
12565
12566        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12567            text,
12568            clipboard_selections,
12569        ));
12570    }
12571
12572    pub fn do_paste(
12573        &mut self,
12574        text: &String,
12575        clipboard_selections: Option<Vec<ClipboardSelection>>,
12576        handle_entire_lines: bool,
12577        window: &mut Window,
12578        cx: &mut Context<Self>,
12579    ) {
12580        if self.read_only(cx) {
12581            return;
12582        }
12583
12584        let clipboard_text = Cow::Borrowed(text.as_str());
12585
12586        self.transact(window, cx, |this, window, cx| {
12587            let had_active_edit_prediction = this.has_active_edit_prediction();
12588            let old_selections = this.selections.all::<usize>(cx);
12589            let cursor_offset = this.selections.last::<usize>(cx).head();
12590
12591            if let Some(mut clipboard_selections) = clipboard_selections {
12592                let all_selections_were_entire_line =
12593                    clipboard_selections.iter().all(|s| s.is_entire_line);
12594                let first_selection_indent_column =
12595                    clipboard_selections.first().map(|s| s.first_line_indent);
12596                if clipboard_selections.len() != old_selections.len() {
12597                    clipboard_selections.drain(..);
12598                }
12599                let mut auto_indent_on_paste = true;
12600
12601                this.buffer.update(cx, |buffer, cx| {
12602                    let snapshot = buffer.read(cx);
12603                    auto_indent_on_paste = snapshot
12604                        .language_settings_at(cursor_offset, cx)
12605                        .auto_indent_on_paste;
12606
12607                    let mut start_offset = 0;
12608                    let mut edits = Vec::new();
12609                    let mut original_indent_columns = Vec::new();
12610                    for (ix, selection) in old_selections.iter().enumerate() {
12611                        let to_insert;
12612                        let entire_line;
12613                        let original_indent_column;
12614                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12615                            let end_offset = start_offset + clipboard_selection.len;
12616                            to_insert = &clipboard_text[start_offset..end_offset];
12617                            entire_line = clipboard_selection.is_entire_line;
12618                            start_offset = end_offset + 1;
12619                            original_indent_column = Some(clipboard_selection.first_line_indent);
12620                        } else {
12621                            to_insert = &*clipboard_text;
12622                            entire_line = all_selections_were_entire_line;
12623                            original_indent_column = first_selection_indent_column
12624                        }
12625
12626                        let (range, to_insert) =
12627                            if selection.is_empty() && handle_entire_lines && entire_line {
12628                                // If the corresponding selection was empty when this slice of the
12629                                // clipboard text was written, then the entire line containing the
12630                                // selection was copied. If this selection is also currently empty,
12631                                // then paste the line before the current line of the buffer.
12632                                let column = selection.start.to_point(&snapshot).column as usize;
12633                                let line_start = selection.start - column;
12634                                (line_start..line_start, Cow::Borrowed(to_insert))
12635                            } else {
12636                                let language = snapshot.language_at(selection.head());
12637                                let range = selection.range();
12638                                if let Some(language) = language
12639                                    && language.name() == "Markdown".into()
12640                                {
12641                                    edit_for_markdown_paste(
12642                                        &snapshot,
12643                                        range,
12644                                        to_insert,
12645                                        url::Url::parse(to_insert).ok(),
12646                                    )
12647                                } else {
12648                                    (range, Cow::Borrowed(to_insert))
12649                                }
12650                            };
12651
12652                        edits.push((range, to_insert));
12653                        original_indent_columns.push(original_indent_column);
12654                    }
12655                    drop(snapshot);
12656
12657                    buffer.edit(
12658                        edits,
12659                        if auto_indent_on_paste {
12660                            Some(AutoindentMode::Block {
12661                                original_indent_columns,
12662                            })
12663                        } else {
12664                            None
12665                        },
12666                        cx,
12667                    );
12668                });
12669
12670                let selections = this.selections.all::<usize>(cx);
12671                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12672            } else {
12673                let url = url::Url::parse(&clipboard_text).ok();
12674
12675                let auto_indent_mode = if !clipboard_text.is_empty() {
12676                    Some(AutoindentMode::Block {
12677                        original_indent_columns: Vec::new(),
12678                    })
12679                } else {
12680                    None
12681                };
12682
12683                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12684                    let snapshot = buffer.snapshot(cx);
12685
12686                    let anchors = old_selections
12687                        .iter()
12688                        .map(|s| {
12689                            let anchor = snapshot.anchor_after(s.head());
12690                            s.map(|_| anchor)
12691                        })
12692                        .collect::<Vec<_>>();
12693
12694                    let mut edits = Vec::new();
12695
12696                    for selection in old_selections.iter() {
12697                        let language = snapshot.language_at(selection.head());
12698                        let range = selection.range();
12699
12700                        let (edit_range, edit_text) = if let Some(language) = language
12701                            && language.name() == "Markdown".into()
12702                        {
12703                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12704                        } else {
12705                            (range, clipboard_text.clone())
12706                        };
12707
12708                        edits.push((edit_range, edit_text));
12709                    }
12710
12711                    drop(snapshot);
12712                    buffer.edit(edits, auto_indent_mode, cx);
12713
12714                    anchors
12715                });
12716
12717                this.change_selections(Default::default(), window, cx, |s| {
12718                    s.select_anchors(selection_anchors);
12719                });
12720            }
12721
12722            let trigger_in_words =
12723                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12724
12725            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12726        });
12727    }
12728
12729    pub fn diff_clipboard_with_selection(
12730        &mut self,
12731        _: &DiffClipboardWithSelection,
12732        window: &mut Window,
12733        cx: &mut Context<Self>,
12734    ) {
12735        let selections = self.selections.all::<usize>(cx);
12736
12737        if selections.is_empty() {
12738            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12739            return;
12740        };
12741
12742        let clipboard_text = match cx.read_from_clipboard() {
12743            Some(item) => match item.entries().first() {
12744                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12745                _ => None,
12746            },
12747            None => None,
12748        };
12749
12750        let Some(clipboard_text) = clipboard_text else {
12751            log::warn!("Clipboard doesn't contain text.");
12752            return;
12753        };
12754
12755        window.dispatch_action(
12756            Box::new(DiffClipboardWithSelectionData {
12757                clipboard_text,
12758                editor: cx.entity(),
12759            }),
12760            cx,
12761        );
12762    }
12763
12764    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12765        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12766        if let Some(item) = cx.read_from_clipboard() {
12767            let entries = item.entries();
12768
12769            match entries.first() {
12770                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12771                // of all the pasted entries.
12772                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12773                    .do_paste(
12774                        clipboard_string.text(),
12775                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12776                        true,
12777                        window,
12778                        cx,
12779                    ),
12780                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12781            }
12782        }
12783    }
12784
12785    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12786        if self.read_only(cx) {
12787            return;
12788        }
12789
12790        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12791
12792        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12793            if let Some((selections, _)) =
12794                self.selection_history.transaction(transaction_id).cloned()
12795            {
12796                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12797                    s.select_anchors(selections.to_vec());
12798                });
12799            } else {
12800                log::error!(
12801                    "No entry in selection_history found for undo. \
12802                     This may correspond to a bug where undo does not update the selection. \
12803                     If this is occurring, please add details to \
12804                     https://github.com/zed-industries/zed/issues/22692"
12805                );
12806            }
12807            self.request_autoscroll(Autoscroll::fit(), cx);
12808            self.unmark_text(window, cx);
12809            self.refresh_edit_prediction(true, false, window, cx);
12810            cx.emit(EditorEvent::Edited { transaction_id });
12811            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12812        }
12813    }
12814
12815    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12816        if self.read_only(cx) {
12817            return;
12818        }
12819
12820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12821
12822        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12823            if let Some((_, Some(selections))) =
12824                self.selection_history.transaction(transaction_id).cloned()
12825            {
12826                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12827                    s.select_anchors(selections.to_vec());
12828                });
12829            } else {
12830                log::error!(
12831                    "No entry in selection_history found for redo. \
12832                     This may correspond to a bug where undo does not update the selection. \
12833                     If this is occurring, please add details to \
12834                     https://github.com/zed-industries/zed/issues/22692"
12835                );
12836            }
12837            self.request_autoscroll(Autoscroll::fit(), cx);
12838            self.unmark_text(window, cx);
12839            self.refresh_edit_prediction(true, false, window, cx);
12840            cx.emit(EditorEvent::Edited { transaction_id });
12841        }
12842    }
12843
12844    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12845        self.buffer
12846            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12847    }
12848
12849    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12850        self.buffer
12851            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12852    }
12853
12854    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12855        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12856        self.change_selections(Default::default(), window, cx, |s| {
12857            s.move_with(|map, selection| {
12858                let cursor = if selection.is_empty() {
12859                    movement::left(map, selection.start)
12860                } else {
12861                    selection.start
12862                };
12863                selection.collapse_to(cursor, SelectionGoal::None);
12864            });
12865        })
12866    }
12867
12868    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12869        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12870        self.change_selections(Default::default(), window, cx, |s| {
12871            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12872        })
12873    }
12874
12875    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12876        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12877        self.change_selections(Default::default(), window, cx, |s| {
12878            s.move_with(|map, selection| {
12879                let cursor = if selection.is_empty() {
12880                    movement::right(map, selection.end)
12881                } else {
12882                    selection.end
12883                };
12884                selection.collapse_to(cursor, SelectionGoal::None)
12885            });
12886        })
12887    }
12888
12889    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12890        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12891        self.change_selections(Default::default(), window, cx, |s| {
12892            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12893        });
12894    }
12895
12896    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12897        if self.take_rename(true, window, cx).is_some() {
12898            return;
12899        }
12900
12901        if self.mode.is_single_line() {
12902            cx.propagate();
12903            return;
12904        }
12905
12906        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12907
12908        let text_layout_details = &self.text_layout_details(window);
12909        let selection_count = self.selections.count();
12910        let first_selection = self.selections.first_anchor();
12911
12912        self.change_selections(Default::default(), window, cx, |s| {
12913            s.move_with(|map, selection| {
12914                if !selection.is_empty() {
12915                    selection.goal = SelectionGoal::None;
12916                }
12917                let (cursor, goal) = movement::up(
12918                    map,
12919                    selection.start,
12920                    selection.goal,
12921                    false,
12922                    text_layout_details,
12923                );
12924                selection.collapse_to(cursor, goal);
12925            });
12926        });
12927
12928        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12929        {
12930            cx.propagate();
12931        }
12932    }
12933
12934    pub fn move_up_by_lines(
12935        &mut self,
12936        action: &MoveUpByLines,
12937        window: &mut Window,
12938        cx: &mut Context<Self>,
12939    ) {
12940        if self.take_rename(true, window, cx).is_some() {
12941            return;
12942        }
12943
12944        if self.mode.is_single_line() {
12945            cx.propagate();
12946            return;
12947        }
12948
12949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12950
12951        let text_layout_details = &self.text_layout_details(window);
12952
12953        self.change_selections(Default::default(), window, cx, |s| {
12954            s.move_with(|map, selection| {
12955                if !selection.is_empty() {
12956                    selection.goal = SelectionGoal::None;
12957                }
12958                let (cursor, goal) = movement::up_by_rows(
12959                    map,
12960                    selection.start,
12961                    action.lines,
12962                    selection.goal,
12963                    false,
12964                    text_layout_details,
12965                );
12966                selection.collapse_to(cursor, goal);
12967            });
12968        })
12969    }
12970
12971    pub fn move_down_by_lines(
12972        &mut self,
12973        action: &MoveDownByLines,
12974        window: &mut Window,
12975        cx: &mut Context<Self>,
12976    ) {
12977        if self.take_rename(true, window, cx).is_some() {
12978            return;
12979        }
12980
12981        if self.mode.is_single_line() {
12982            cx.propagate();
12983            return;
12984        }
12985
12986        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12987
12988        let text_layout_details = &self.text_layout_details(window);
12989
12990        self.change_selections(Default::default(), window, cx, |s| {
12991            s.move_with(|map, selection| {
12992                if !selection.is_empty() {
12993                    selection.goal = SelectionGoal::None;
12994                }
12995                let (cursor, goal) = movement::down_by_rows(
12996                    map,
12997                    selection.start,
12998                    action.lines,
12999                    selection.goal,
13000                    false,
13001                    text_layout_details,
13002                );
13003                selection.collapse_to(cursor, goal);
13004            });
13005        })
13006    }
13007
13008    pub fn select_down_by_lines(
13009        &mut self,
13010        action: &SelectDownByLines,
13011        window: &mut Window,
13012        cx: &mut Context<Self>,
13013    ) {
13014        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13015        let text_layout_details = &self.text_layout_details(window);
13016        self.change_selections(Default::default(), window, cx, |s| {
13017            s.move_heads_with(|map, head, goal| {
13018                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13019            })
13020        })
13021    }
13022
13023    pub fn select_up_by_lines(
13024        &mut self,
13025        action: &SelectUpByLines,
13026        window: &mut Window,
13027        cx: &mut Context<Self>,
13028    ) {
13029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13030        let text_layout_details = &self.text_layout_details(window);
13031        self.change_selections(Default::default(), window, cx, |s| {
13032            s.move_heads_with(|map, head, goal| {
13033                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13034            })
13035        })
13036    }
13037
13038    pub fn select_page_up(
13039        &mut self,
13040        _: &SelectPageUp,
13041        window: &mut Window,
13042        cx: &mut Context<Self>,
13043    ) {
13044        let Some(row_count) = self.visible_row_count() else {
13045            return;
13046        };
13047
13048        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13049
13050        let text_layout_details = &self.text_layout_details(window);
13051
13052        self.change_selections(Default::default(), window, cx, |s| {
13053            s.move_heads_with(|map, head, goal| {
13054                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13055            })
13056        })
13057    }
13058
13059    pub fn move_page_up(
13060        &mut self,
13061        action: &MovePageUp,
13062        window: &mut Window,
13063        cx: &mut Context<Self>,
13064    ) {
13065        if self.take_rename(true, window, cx).is_some() {
13066            return;
13067        }
13068
13069        if self
13070            .context_menu
13071            .borrow_mut()
13072            .as_mut()
13073            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13074            .unwrap_or(false)
13075        {
13076            return;
13077        }
13078
13079        if matches!(self.mode, EditorMode::SingleLine) {
13080            cx.propagate();
13081            return;
13082        }
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 effects = if action.center_cursor {
13091            SelectionEffects::scroll(Autoscroll::center())
13092        } else {
13093            SelectionEffects::default()
13094        };
13095
13096        let text_layout_details = &self.text_layout_details(window);
13097
13098        self.change_selections(effects, window, cx, |s| {
13099            s.move_with(|map, selection| {
13100                if !selection.is_empty() {
13101                    selection.goal = SelectionGoal::None;
13102                }
13103                let (cursor, goal) = movement::up_by_rows(
13104                    map,
13105                    selection.end,
13106                    row_count,
13107                    selection.goal,
13108                    false,
13109                    text_layout_details,
13110                );
13111                selection.collapse_to(cursor, goal);
13112            });
13113        });
13114    }
13115
13116    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13117        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13118        let text_layout_details = &self.text_layout_details(window);
13119        self.change_selections(Default::default(), window, cx, |s| {
13120            s.move_heads_with(|map, head, goal| {
13121                movement::up(map, head, goal, false, text_layout_details)
13122            })
13123        })
13124    }
13125
13126    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13127        self.take_rename(true, window, cx);
13128
13129        if self.mode.is_single_line() {
13130            cx.propagate();
13131            return;
13132        }
13133
13134        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13135
13136        let text_layout_details = &self.text_layout_details(window);
13137        let selection_count = self.selections.count();
13138        let first_selection = self.selections.first_anchor();
13139
13140        self.change_selections(Default::default(), window, cx, |s| {
13141            s.move_with(|map, selection| {
13142                if !selection.is_empty() {
13143                    selection.goal = SelectionGoal::None;
13144                }
13145                let (cursor, goal) = movement::down(
13146                    map,
13147                    selection.end,
13148                    selection.goal,
13149                    false,
13150                    text_layout_details,
13151                );
13152                selection.collapse_to(cursor, goal);
13153            });
13154        });
13155
13156        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13157        {
13158            cx.propagate();
13159        }
13160    }
13161
13162    pub fn select_page_down(
13163        &mut self,
13164        _: &SelectPageDown,
13165        window: &mut Window,
13166        cx: &mut Context<Self>,
13167    ) {
13168        let Some(row_count) = self.visible_row_count() else {
13169            return;
13170        };
13171
13172        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13173
13174        let text_layout_details = &self.text_layout_details(window);
13175
13176        self.change_selections(Default::default(), window, cx, |s| {
13177            s.move_heads_with(|map, head, goal| {
13178                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13179            })
13180        })
13181    }
13182
13183    pub fn move_page_down(
13184        &mut self,
13185        action: &MovePageDown,
13186        window: &mut Window,
13187        cx: &mut Context<Self>,
13188    ) {
13189        if self.take_rename(true, window, cx).is_some() {
13190            return;
13191        }
13192
13193        if self
13194            .context_menu
13195            .borrow_mut()
13196            .as_mut()
13197            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13198            .unwrap_or(false)
13199        {
13200            return;
13201        }
13202
13203        if matches!(self.mode, EditorMode::SingleLine) {
13204            cx.propagate();
13205            return;
13206        }
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 effects = if action.center_cursor {
13215            SelectionEffects::scroll(Autoscroll::center())
13216        } else {
13217            SelectionEffects::default()
13218        };
13219
13220        let text_layout_details = &self.text_layout_details(window);
13221        self.change_selections(effects, window, cx, |s| {
13222            s.move_with(|map, selection| {
13223                if !selection.is_empty() {
13224                    selection.goal = SelectionGoal::None;
13225                }
13226                let (cursor, goal) = movement::down_by_rows(
13227                    map,
13228                    selection.end,
13229                    row_count,
13230                    selection.goal,
13231                    false,
13232                    text_layout_details,
13233                );
13234                selection.collapse_to(cursor, goal);
13235            });
13236        });
13237    }
13238
13239    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13240        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13241        let text_layout_details = &self.text_layout_details(window);
13242        self.change_selections(Default::default(), window, cx, |s| {
13243            s.move_heads_with(|map, head, goal| {
13244                movement::down(map, head, goal, false, text_layout_details)
13245            })
13246        });
13247    }
13248
13249    pub fn context_menu_first(
13250        &mut self,
13251        _: &ContextMenuFirst,
13252        window: &mut Window,
13253        cx: &mut Context<Self>,
13254    ) {
13255        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13256            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13257        }
13258    }
13259
13260    pub fn context_menu_prev(
13261        &mut self,
13262        _: &ContextMenuPrevious,
13263        window: &mut Window,
13264        cx: &mut Context<Self>,
13265    ) {
13266        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13267            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13268        }
13269    }
13270
13271    pub fn context_menu_next(
13272        &mut self,
13273        _: &ContextMenuNext,
13274        window: &mut Window,
13275        cx: &mut Context<Self>,
13276    ) {
13277        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13278            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13279        }
13280    }
13281
13282    pub fn context_menu_last(
13283        &mut self,
13284        _: &ContextMenuLast,
13285        window: &mut Window,
13286        cx: &mut Context<Self>,
13287    ) {
13288        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13289            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13290        }
13291    }
13292
13293    pub fn signature_help_prev(
13294        &mut self,
13295        _: &SignatureHelpPrevious,
13296        _: &mut Window,
13297        cx: &mut Context<Self>,
13298    ) {
13299        if let Some(popover) = self.signature_help_state.popover_mut() {
13300            if popover.current_signature == 0 {
13301                popover.current_signature = popover.signatures.len() - 1;
13302            } else {
13303                popover.current_signature -= 1;
13304            }
13305            cx.notify();
13306        }
13307    }
13308
13309    pub fn signature_help_next(
13310        &mut self,
13311        _: &SignatureHelpNext,
13312        _: &mut Window,
13313        cx: &mut Context<Self>,
13314    ) {
13315        if let Some(popover) = self.signature_help_state.popover_mut() {
13316            if popover.current_signature + 1 == popover.signatures.len() {
13317                popover.current_signature = 0;
13318            } else {
13319                popover.current_signature += 1;
13320            }
13321            cx.notify();
13322        }
13323    }
13324
13325    pub fn move_to_previous_word_start(
13326        &mut self,
13327        _: &MoveToPreviousWordStart,
13328        window: &mut Window,
13329        cx: &mut Context<Self>,
13330    ) {
13331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13332        self.change_selections(Default::default(), window, cx, |s| {
13333            s.move_cursors_with(|map, head, _| {
13334                (
13335                    movement::previous_word_start(map, head),
13336                    SelectionGoal::None,
13337                )
13338            });
13339        })
13340    }
13341
13342    pub fn move_to_previous_subword_start(
13343        &mut self,
13344        _: &MoveToPreviousSubwordStart,
13345        window: &mut Window,
13346        cx: &mut Context<Self>,
13347    ) {
13348        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13349        self.change_selections(Default::default(), window, cx, |s| {
13350            s.move_cursors_with(|map, head, _| {
13351                (
13352                    movement::previous_subword_start(map, head),
13353                    SelectionGoal::None,
13354                )
13355            });
13356        })
13357    }
13358
13359    pub fn select_to_previous_word_start(
13360        &mut self,
13361        _: &SelectToPreviousWordStart,
13362        window: &mut Window,
13363        cx: &mut Context<Self>,
13364    ) {
13365        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13366        self.change_selections(Default::default(), window, cx, |s| {
13367            s.move_heads_with(|map, head, _| {
13368                (
13369                    movement::previous_word_start(map, head),
13370                    SelectionGoal::None,
13371                )
13372            });
13373        })
13374    }
13375
13376    pub fn select_to_previous_subword_start(
13377        &mut self,
13378        _: &SelectToPreviousSubwordStart,
13379        window: &mut Window,
13380        cx: &mut Context<Self>,
13381    ) {
13382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13383        self.change_selections(Default::default(), window, cx, |s| {
13384            s.move_heads_with(|map, head, _| {
13385                (
13386                    movement::previous_subword_start(map, head),
13387                    SelectionGoal::None,
13388                )
13389            });
13390        })
13391    }
13392
13393    pub fn delete_to_previous_word_start(
13394        &mut self,
13395        action: &DeleteToPreviousWordStart,
13396        window: &mut Window,
13397        cx: &mut Context<Self>,
13398    ) {
13399        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13400        self.transact(window, cx, |this, window, cx| {
13401            this.select_autoclose_pair(window, cx);
13402            this.change_selections(Default::default(), window, cx, |s| {
13403                s.move_with(|map, selection| {
13404                    if selection.is_empty() {
13405                        let mut cursor = if action.ignore_newlines {
13406                            movement::previous_word_start(map, selection.head())
13407                        } else {
13408                            movement::previous_word_start_or_newline(map, selection.head())
13409                        };
13410                        cursor = movement::adjust_greedy_deletion(
13411                            map,
13412                            selection.head(),
13413                            cursor,
13414                            action.ignore_brackets,
13415                        );
13416                        selection.set_head(cursor, SelectionGoal::None);
13417                    }
13418                });
13419            });
13420            this.insert("", window, cx);
13421        });
13422    }
13423
13424    pub fn delete_to_previous_subword_start(
13425        &mut self,
13426        _: &DeleteToPreviousSubwordStart,
13427        window: &mut Window,
13428        cx: &mut Context<Self>,
13429    ) {
13430        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13431        self.transact(window, cx, |this, window, cx| {
13432            this.select_autoclose_pair(window, cx);
13433            this.change_selections(Default::default(), window, cx, |s| {
13434                s.move_with(|map, selection| {
13435                    if selection.is_empty() {
13436                        let mut cursor = movement::previous_subword_start(map, selection.head());
13437                        cursor =
13438                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13439                        selection.set_head(cursor, SelectionGoal::None);
13440                    }
13441                });
13442            });
13443            this.insert("", window, cx);
13444        });
13445    }
13446
13447    pub fn move_to_next_word_end(
13448        &mut self,
13449        _: &MoveToNextWordEnd,
13450        window: &mut Window,
13451        cx: &mut Context<Self>,
13452    ) {
13453        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13454        self.change_selections(Default::default(), window, cx, |s| {
13455            s.move_cursors_with(|map, head, _| {
13456                (movement::next_word_end(map, head), SelectionGoal::None)
13457            });
13458        })
13459    }
13460
13461    pub fn move_to_next_subword_end(
13462        &mut self,
13463        _: &MoveToNextSubwordEnd,
13464        window: &mut Window,
13465        cx: &mut Context<Self>,
13466    ) {
13467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13468        self.change_selections(Default::default(), window, cx, |s| {
13469            s.move_cursors_with(|map, head, _| {
13470                (movement::next_subword_end(map, head), SelectionGoal::None)
13471            });
13472        })
13473    }
13474
13475    pub fn select_to_next_word_end(
13476        &mut self,
13477        _: &SelectToNextWordEnd,
13478        window: &mut Window,
13479        cx: &mut Context<Self>,
13480    ) {
13481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13482        self.change_selections(Default::default(), window, cx, |s| {
13483            s.move_heads_with(|map, head, _| {
13484                (movement::next_word_end(map, head), SelectionGoal::None)
13485            });
13486        })
13487    }
13488
13489    pub fn select_to_next_subword_end(
13490        &mut self,
13491        _: &SelectToNextSubwordEnd,
13492        window: &mut Window,
13493        cx: &mut Context<Self>,
13494    ) {
13495        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13496        self.change_selections(Default::default(), window, cx, |s| {
13497            s.move_heads_with(|map, head, _| {
13498                (movement::next_subword_end(map, head), SelectionGoal::None)
13499            });
13500        })
13501    }
13502
13503    pub fn delete_to_next_word_end(
13504        &mut self,
13505        action: &DeleteToNextWordEnd,
13506        window: &mut Window,
13507        cx: &mut Context<Self>,
13508    ) {
13509        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13510        self.transact(window, cx, |this, window, cx| {
13511            this.change_selections(Default::default(), window, cx, |s| {
13512                s.move_with(|map, selection| {
13513                    if selection.is_empty() {
13514                        let mut cursor = if action.ignore_newlines {
13515                            movement::next_word_end(map, selection.head())
13516                        } else {
13517                            movement::next_word_end_or_newline(map, selection.head())
13518                        };
13519                        cursor = movement::adjust_greedy_deletion(
13520                            map,
13521                            selection.head(),
13522                            cursor,
13523                            action.ignore_brackets,
13524                        );
13525                        selection.set_head(cursor, SelectionGoal::None);
13526                    }
13527                });
13528            });
13529            this.insert("", window, cx);
13530        });
13531    }
13532
13533    pub fn delete_to_next_subword_end(
13534        &mut self,
13535        _: &DeleteToNextSubwordEnd,
13536        window: &mut Window,
13537        cx: &mut Context<Self>,
13538    ) {
13539        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13540        self.transact(window, cx, |this, window, cx| {
13541            this.change_selections(Default::default(), window, cx, |s| {
13542                s.move_with(|map, selection| {
13543                    if selection.is_empty() {
13544                        let mut cursor = movement::next_subword_end(map, selection.head());
13545                        cursor =
13546                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13547                        selection.set_head(cursor, SelectionGoal::None);
13548                    }
13549                });
13550            });
13551            this.insert("", window, cx);
13552        });
13553    }
13554
13555    pub fn move_to_beginning_of_line(
13556        &mut self,
13557        action: &MoveToBeginningOfLine,
13558        window: &mut Window,
13559        cx: &mut Context<Self>,
13560    ) {
13561        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13562        self.change_selections(Default::default(), window, cx, |s| {
13563            s.move_cursors_with(|map, head, _| {
13564                (
13565                    movement::indented_line_beginning(
13566                        map,
13567                        head,
13568                        action.stop_at_soft_wraps,
13569                        action.stop_at_indent,
13570                    ),
13571                    SelectionGoal::None,
13572                )
13573            });
13574        })
13575    }
13576
13577    pub fn select_to_beginning_of_line(
13578        &mut self,
13579        action: &SelectToBeginningOfLine,
13580        window: &mut Window,
13581        cx: &mut Context<Self>,
13582    ) {
13583        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13584        self.change_selections(Default::default(), window, cx, |s| {
13585            s.move_heads_with(|map, head, _| {
13586                (
13587                    movement::indented_line_beginning(
13588                        map,
13589                        head,
13590                        action.stop_at_soft_wraps,
13591                        action.stop_at_indent,
13592                    ),
13593                    SelectionGoal::None,
13594                )
13595            });
13596        });
13597    }
13598
13599    pub fn delete_to_beginning_of_line(
13600        &mut self,
13601        action: &DeleteToBeginningOfLine,
13602        window: &mut Window,
13603        cx: &mut Context<Self>,
13604    ) {
13605        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13606        self.transact(window, cx, |this, window, cx| {
13607            this.change_selections(Default::default(), window, cx, |s| {
13608                s.move_with(|_, selection| {
13609                    selection.reversed = true;
13610                });
13611            });
13612
13613            this.select_to_beginning_of_line(
13614                &SelectToBeginningOfLine {
13615                    stop_at_soft_wraps: false,
13616                    stop_at_indent: action.stop_at_indent,
13617                },
13618                window,
13619                cx,
13620            );
13621            this.backspace(&Backspace, window, cx);
13622        });
13623    }
13624
13625    pub fn move_to_end_of_line(
13626        &mut self,
13627        action: &MoveToEndOfLine,
13628        window: &mut Window,
13629        cx: &mut Context<Self>,
13630    ) {
13631        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13632        self.change_selections(Default::default(), window, cx, |s| {
13633            s.move_cursors_with(|map, head, _| {
13634                (
13635                    movement::line_end(map, head, action.stop_at_soft_wraps),
13636                    SelectionGoal::None,
13637                )
13638            });
13639        })
13640    }
13641
13642    pub fn select_to_end_of_line(
13643        &mut self,
13644        action: &SelectToEndOfLine,
13645        window: &mut Window,
13646        cx: &mut Context<Self>,
13647    ) {
13648        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13649        self.change_selections(Default::default(), window, cx, |s| {
13650            s.move_heads_with(|map, head, _| {
13651                (
13652                    movement::line_end(map, head, action.stop_at_soft_wraps),
13653                    SelectionGoal::None,
13654                )
13655            });
13656        })
13657    }
13658
13659    pub fn delete_to_end_of_line(
13660        &mut self,
13661        _: &DeleteToEndOfLine,
13662        window: &mut Window,
13663        cx: &mut Context<Self>,
13664    ) {
13665        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13666        self.transact(window, cx, |this, window, cx| {
13667            this.select_to_end_of_line(
13668                &SelectToEndOfLine {
13669                    stop_at_soft_wraps: false,
13670                },
13671                window,
13672                cx,
13673            );
13674            this.delete(&Delete, window, cx);
13675        });
13676    }
13677
13678    pub fn cut_to_end_of_line(
13679        &mut self,
13680        action: &CutToEndOfLine,
13681        window: &mut Window,
13682        cx: &mut Context<Self>,
13683    ) {
13684        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13685        self.transact(window, cx, |this, window, cx| {
13686            this.select_to_end_of_line(
13687                &SelectToEndOfLine {
13688                    stop_at_soft_wraps: false,
13689                },
13690                window,
13691                cx,
13692            );
13693            if !action.stop_at_newlines {
13694                this.change_selections(Default::default(), window, cx, |s| {
13695                    s.move_with(|_, sel| {
13696                        if sel.is_empty() {
13697                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13698                        }
13699                    });
13700                });
13701            }
13702            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13703            let item = this.cut_common(false, window, cx);
13704            cx.write_to_clipboard(item);
13705        });
13706    }
13707
13708    pub fn move_to_start_of_paragraph(
13709        &mut self,
13710        _: &MoveToStartOfParagraph,
13711        window: &mut Window,
13712        cx: &mut Context<Self>,
13713    ) {
13714        if matches!(self.mode, EditorMode::SingleLine) {
13715            cx.propagate();
13716            return;
13717        }
13718        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13719        self.change_selections(Default::default(), window, cx, |s| {
13720            s.move_with(|map, selection| {
13721                selection.collapse_to(
13722                    movement::start_of_paragraph(map, selection.head(), 1),
13723                    SelectionGoal::None,
13724                )
13725            });
13726        })
13727    }
13728
13729    pub fn move_to_end_of_paragraph(
13730        &mut self,
13731        _: &MoveToEndOfParagraph,
13732        window: &mut Window,
13733        cx: &mut Context<Self>,
13734    ) {
13735        if matches!(self.mode, EditorMode::SingleLine) {
13736            cx.propagate();
13737            return;
13738        }
13739        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13740        self.change_selections(Default::default(), window, cx, |s| {
13741            s.move_with(|map, selection| {
13742                selection.collapse_to(
13743                    movement::end_of_paragraph(map, selection.head(), 1),
13744                    SelectionGoal::None,
13745                )
13746            });
13747        })
13748    }
13749
13750    pub fn select_to_start_of_paragraph(
13751        &mut self,
13752        _: &SelectToStartOfParagraph,
13753        window: &mut Window,
13754        cx: &mut Context<Self>,
13755    ) {
13756        if matches!(self.mode, EditorMode::SingleLine) {
13757            cx.propagate();
13758            return;
13759        }
13760        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13761        self.change_selections(Default::default(), window, cx, |s| {
13762            s.move_heads_with(|map, head, _| {
13763                (
13764                    movement::start_of_paragraph(map, head, 1),
13765                    SelectionGoal::None,
13766                )
13767            });
13768        })
13769    }
13770
13771    pub fn select_to_end_of_paragraph(
13772        &mut self,
13773        _: &SelectToEndOfParagraph,
13774        window: &mut Window,
13775        cx: &mut Context<Self>,
13776    ) {
13777        if matches!(self.mode, EditorMode::SingleLine) {
13778            cx.propagate();
13779            return;
13780        }
13781        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13782        self.change_selections(Default::default(), window, cx, |s| {
13783            s.move_heads_with(|map, head, _| {
13784                (
13785                    movement::end_of_paragraph(map, head, 1),
13786                    SelectionGoal::None,
13787                )
13788            });
13789        })
13790    }
13791
13792    pub fn move_to_start_of_excerpt(
13793        &mut self,
13794        _: &MoveToStartOfExcerpt,
13795        window: &mut Window,
13796        cx: &mut Context<Self>,
13797    ) {
13798        if matches!(self.mode, EditorMode::SingleLine) {
13799            cx.propagate();
13800            return;
13801        }
13802        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13803        self.change_selections(Default::default(), window, cx, |s| {
13804            s.move_with(|map, selection| {
13805                selection.collapse_to(
13806                    movement::start_of_excerpt(
13807                        map,
13808                        selection.head(),
13809                        workspace::searchable::Direction::Prev,
13810                    ),
13811                    SelectionGoal::None,
13812                )
13813            });
13814        })
13815    }
13816
13817    pub fn move_to_start_of_next_excerpt(
13818        &mut self,
13819        _: &MoveToStartOfNextExcerpt,
13820        window: &mut Window,
13821        cx: &mut Context<Self>,
13822    ) {
13823        if matches!(self.mode, EditorMode::SingleLine) {
13824            cx.propagate();
13825            return;
13826        }
13827
13828        self.change_selections(Default::default(), window, cx, |s| {
13829            s.move_with(|map, selection| {
13830                selection.collapse_to(
13831                    movement::start_of_excerpt(
13832                        map,
13833                        selection.head(),
13834                        workspace::searchable::Direction::Next,
13835                    ),
13836                    SelectionGoal::None,
13837                )
13838            });
13839        })
13840    }
13841
13842    pub fn move_to_end_of_excerpt(
13843        &mut self,
13844        _: &MoveToEndOfExcerpt,
13845        window: &mut Window,
13846        cx: &mut Context<Self>,
13847    ) {
13848        if matches!(self.mode, EditorMode::SingleLine) {
13849            cx.propagate();
13850            return;
13851        }
13852        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13853        self.change_selections(Default::default(), window, cx, |s| {
13854            s.move_with(|map, selection| {
13855                selection.collapse_to(
13856                    movement::end_of_excerpt(
13857                        map,
13858                        selection.head(),
13859                        workspace::searchable::Direction::Next,
13860                    ),
13861                    SelectionGoal::None,
13862                )
13863            });
13864        })
13865    }
13866
13867    pub fn move_to_end_of_previous_excerpt(
13868        &mut self,
13869        _: &MoveToEndOfPreviousExcerpt,
13870        window: &mut Window,
13871        cx: &mut Context<Self>,
13872    ) {
13873        if matches!(self.mode, EditorMode::SingleLine) {
13874            cx.propagate();
13875            return;
13876        }
13877        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13878        self.change_selections(Default::default(), window, cx, |s| {
13879            s.move_with(|map, selection| {
13880                selection.collapse_to(
13881                    movement::end_of_excerpt(
13882                        map,
13883                        selection.head(),
13884                        workspace::searchable::Direction::Prev,
13885                    ),
13886                    SelectionGoal::None,
13887                )
13888            });
13889        })
13890    }
13891
13892    pub fn select_to_start_of_excerpt(
13893        &mut self,
13894        _: &SelectToStartOfExcerpt,
13895        window: &mut Window,
13896        cx: &mut Context<Self>,
13897    ) {
13898        if matches!(self.mode, EditorMode::SingleLine) {
13899            cx.propagate();
13900            return;
13901        }
13902        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13903        self.change_selections(Default::default(), window, cx, |s| {
13904            s.move_heads_with(|map, head, _| {
13905                (
13906                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13907                    SelectionGoal::None,
13908                )
13909            });
13910        })
13911    }
13912
13913    pub fn select_to_start_of_next_excerpt(
13914        &mut self,
13915        _: &SelectToStartOfNextExcerpt,
13916        window: &mut Window,
13917        cx: &mut Context<Self>,
13918    ) {
13919        if matches!(self.mode, EditorMode::SingleLine) {
13920            cx.propagate();
13921            return;
13922        }
13923        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13924        self.change_selections(Default::default(), window, cx, |s| {
13925            s.move_heads_with(|map, head, _| {
13926                (
13927                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13928                    SelectionGoal::None,
13929                )
13930            });
13931        })
13932    }
13933
13934    pub fn select_to_end_of_excerpt(
13935        &mut self,
13936        _: &SelectToEndOfExcerpt,
13937        window: &mut Window,
13938        cx: &mut Context<Self>,
13939    ) {
13940        if matches!(self.mode, EditorMode::SingleLine) {
13941            cx.propagate();
13942            return;
13943        }
13944        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13945        self.change_selections(Default::default(), window, cx, |s| {
13946            s.move_heads_with(|map, head, _| {
13947                (
13948                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13949                    SelectionGoal::None,
13950                )
13951            });
13952        })
13953    }
13954
13955    pub fn select_to_end_of_previous_excerpt(
13956        &mut self,
13957        _: &SelectToEndOfPreviousExcerpt,
13958        window: &mut Window,
13959        cx: &mut Context<Self>,
13960    ) {
13961        if matches!(self.mode, EditorMode::SingleLine) {
13962            cx.propagate();
13963            return;
13964        }
13965        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13966        self.change_selections(Default::default(), window, cx, |s| {
13967            s.move_heads_with(|map, head, _| {
13968                (
13969                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13970                    SelectionGoal::None,
13971                )
13972            });
13973        })
13974    }
13975
13976    pub fn move_to_beginning(
13977        &mut self,
13978        _: &MoveToBeginning,
13979        window: &mut Window,
13980        cx: &mut Context<Self>,
13981    ) {
13982        if matches!(self.mode, EditorMode::SingleLine) {
13983            cx.propagate();
13984            return;
13985        }
13986        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13987        self.change_selections(Default::default(), window, cx, |s| {
13988            s.select_ranges(vec![0..0]);
13989        });
13990    }
13991
13992    pub fn select_to_beginning(
13993        &mut self,
13994        _: &SelectToBeginning,
13995        window: &mut Window,
13996        cx: &mut Context<Self>,
13997    ) {
13998        let mut selection = self.selections.last::<Point>(cx);
13999        selection.set_head(Point::zero(), SelectionGoal::None);
14000        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14001        self.change_selections(Default::default(), window, cx, |s| {
14002            s.select(vec![selection]);
14003        });
14004    }
14005
14006    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14007        if matches!(self.mode, EditorMode::SingleLine) {
14008            cx.propagate();
14009            return;
14010        }
14011        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14012        let cursor = self.buffer.read(cx).read(cx).len();
14013        self.change_selections(Default::default(), window, cx, |s| {
14014            s.select_ranges(vec![cursor..cursor])
14015        });
14016    }
14017
14018    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14019        self.nav_history = nav_history;
14020    }
14021
14022    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14023        self.nav_history.as_ref()
14024    }
14025
14026    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14027        self.push_to_nav_history(
14028            self.selections.newest_anchor().head(),
14029            None,
14030            false,
14031            true,
14032            cx,
14033        );
14034    }
14035
14036    fn push_to_nav_history(
14037        &mut self,
14038        cursor_anchor: Anchor,
14039        new_position: Option<Point>,
14040        is_deactivate: bool,
14041        always: bool,
14042        cx: &mut Context<Self>,
14043    ) {
14044        if let Some(nav_history) = self.nav_history.as_mut() {
14045            let buffer = self.buffer.read(cx).read(cx);
14046            let cursor_position = cursor_anchor.to_point(&buffer);
14047            let scroll_state = self.scroll_manager.anchor();
14048            let scroll_top_row = scroll_state.top_row(&buffer);
14049            drop(buffer);
14050
14051            if let Some(new_position) = new_position {
14052                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14053                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14054                    return;
14055                }
14056            }
14057
14058            nav_history.push(
14059                Some(NavigationData {
14060                    cursor_anchor,
14061                    cursor_position,
14062                    scroll_anchor: scroll_state,
14063                    scroll_top_row,
14064                }),
14065                cx,
14066            );
14067            cx.emit(EditorEvent::PushedToNavHistory {
14068                anchor: cursor_anchor,
14069                is_deactivate,
14070            })
14071        }
14072    }
14073
14074    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14075        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14076        let buffer = self.buffer.read(cx).snapshot(cx);
14077        let mut selection = self.selections.first::<usize>(cx);
14078        selection.set_head(buffer.len(), SelectionGoal::None);
14079        self.change_selections(Default::default(), window, cx, |s| {
14080            s.select(vec![selection]);
14081        });
14082    }
14083
14084    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14085        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14086        let end = self.buffer.read(cx).read(cx).len();
14087        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14088            s.select_ranges(vec![0..end]);
14089        });
14090    }
14091
14092    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14093        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14094        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14095        let mut selections = self.selections.all::<Point>(cx);
14096        let max_point = display_map.buffer_snapshot.max_point();
14097        for selection in &mut selections {
14098            let rows = selection.spanned_rows(true, &display_map);
14099            selection.start = Point::new(rows.start.0, 0);
14100            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14101            selection.reversed = false;
14102        }
14103        self.change_selections(Default::default(), window, cx, |s| {
14104            s.select(selections);
14105        });
14106    }
14107
14108    pub fn split_selection_into_lines(
14109        &mut self,
14110        action: &SplitSelectionIntoLines,
14111        window: &mut Window,
14112        cx: &mut Context<Self>,
14113    ) {
14114        let selections = self
14115            .selections
14116            .all::<Point>(cx)
14117            .into_iter()
14118            .map(|selection| selection.start..selection.end)
14119            .collect::<Vec<_>>();
14120        self.unfold_ranges(&selections, true, true, cx);
14121
14122        let mut new_selection_ranges = Vec::new();
14123        {
14124            let buffer = self.buffer.read(cx).read(cx);
14125            for selection in selections {
14126                for row in selection.start.row..selection.end.row {
14127                    let line_start = Point::new(row, 0);
14128                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14129
14130                    if action.keep_selections {
14131                        // Keep the selection range for each line
14132                        let selection_start = if row == selection.start.row {
14133                            selection.start
14134                        } else {
14135                            line_start
14136                        };
14137                        new_selection_ranges.push(selection_start..line_end);
14138                    } else {
14139                        // Collapse to cursor at end of line
14140                        new_selection_ranges.push(line_end..line_end);
14141                    }
14142                }
14143
14144                let is_multiline_selection = selection.start.row != selection.end.row;
14145                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14146                // so this action feels more ergonomic when paired with other selection operations
14147                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14148                if !should_skip_last {
14149                    if action.keep_selections {
14150                        if is_multiline_selection {
14151                            let line_start = Point::new(selection.end.row, 0);
14152                            new_selection_ranges.push(line_start..selection.end);
14153                        } else {
14154                            new_selection_ranges.push(selection.start..selection.end);
14155                        }
14156                    } else {
14157                        new_selection_ranges.push(selection.end..selection.end);
14158                    }
14159                }
14160            }
14161        }
14162        self.change_selections(Default::default(), window, cx, |s| {
14163            s.select_ranges(new_selection_ranges);
14164        });
14165    }
14166
14167    pub fn add_selection_above(
14168        &mut self,
14169        _: &AddSelectionAbove,
14170        window: &mut Window,
14171        cx: &mut Context<Self>,
14172    ) {
14173        self.add_selection(true, window, cx);
14174    }
14175
14176    pub fn add_selection_below(
14177        &mut self,
14178        _: &AddSelectionBelow,
14179        window: &mut Window,
14180        cx: &mut Context<Self>,
14181    ) {
14182        self.add_selection(false, window, cx);
14183    }
14184
14185    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14186        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14187
14188        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14189        let all_selections = self.selections.all::<Point>(cx);
14190        let text_layout_details = self.text_layout_details(window);
14191
14192        let (mut columnar_selections, new_selections_to_columnarize) = {
14193            if let Some(state) = self.add_selections_state.as_ref() {
14194                let columnar_selection_ids: HashSet<_> = state
14195                    .groups
14196                    .iter()
14197                    .flat_map(|group| group.stack.iter())
14198                    .copied()
14199                    .collect();
14200
14201                all_selections
14202                    .into_iter()
14203                    .partition(|s| columnar_selection_ids.contains(&s.id))
14204            } else {
14205                (Vec::new(), all_selections)
14206            }
14207        };
14208
14209        let mut state = self
14210            .add_selections_state
14211            .take()
14212            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14213
14214        for selection in new_selections_to_columnarize {
14215            let range = selection.display_range(&display_map).sorted();
14216            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14217            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14218            let positions = start_x.min(end_x)..start_x.max(end_x);
14219            let mut stack = Vec::new();
14220            for row in range.start.row().0..=range.end.row().0 {
14221                if let Some(selection) = self.selections.build_columnar_selection(
14222                    &display_map,
14223                    DisplayRow(row),
14224                    &positions,
14225                    selection.reversed,
14226                    &text_layout_details,
14227                ) {
14228                    stack.push(selection.id);
14229                    columnar_selections.push(selection);
14230                }
14231            }
14232            if !stack.is_empty() {
14233                if above {
14234                    stack.reverse();
14235                }
14236                state.groups.push(AddSelectionsGroup { above, stack });
14237            }
14238        }
14239
14240        let mut final_selections = Vec::new();
14241        let end_row = if above {
14242            DisplayRow(0)
14243        } else {
14244            display_map.max_point().row()
14245        };
14246
14247        let mut last_added_item_per_group = HashMap::default();
14248        for group in state.groups.iter_mut() {
14249            if let Some(last_id) = group.stack.last() {
14250                last_added_item_per_group.insert(*last_id, group);
14251            }
14252        }
14253
14254        for selection in columnar_selections {
14255            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14256                if above == group.above {
14257                    let range = selection.display_range(&display_map).sorted();
14258                    debug_assert_eq!(range.start.row(), range.end.row());
14259                    let mut row = range.start.row();
14260                    let positions =
14261                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14262                            Pixels::from(start)..Pixels::from(end)
14263                        } else {
14264                            let start_x =
14265                                display_map.x_for_display_point(range.start, &text_layout_details);
14266                            let end_x =
14267                                display_map.x_for_display_point(range.end, &text_layout_details);
14268                            start_x.min(end_x)..start_x.max(end_x)
14269                        };
14270
14271                    let mut maybe_new_selection = None;
14272                    while row != end_row {
14273                        if above {
14274                            row.0 -= 1;
14275                        } else {
14276                            row.0 += 1;
14277                        }
14278                        if let Some(new_selection) = self.selections.build_columnar_selection(
14279                            &display_map,
14280                            row,
14281                            &positions,
14282                            selection.reversed,
14283                            &text_layout_details,
14284                        ) {
14285                            maybe_new_selection = Some(new_selection);
14286                            break;
14287                        }
14288                    }
14289
14290                    if let Some(new_selection) = maybe_new_selection {
14291                        group.stack.push(new_selection.id);
14292                        if above {
14293                            final_selections.push(new_selection);
14294                            final_selections.push(selection);
14295                        } else {
14296                            final_selections.push(selection);
14297                            final_selections.push(new_selection);
14298                        }
14299                    } else {
14300                        final_selections.push(selection);
14301                    }
14302                } else {
14303                    group.stack.pop();
14304                }
14305            } else {
14306                final_selections.push(selection);
14307            }
14308        }
14309
14310        self.change_selections(Default::default(), window, cx, |s| {
14311            s.select(final_selections);
14312        });
14313
14314        let final_selection_ids: HashSet<_> = self
14315            .selections
14316            .all::<Point>(cx)
14317            .iter()
14318            .map(|s| s.id)
14319            .collect();
14320        state.groups.retain_mut(|group| {
14321            // selections might get merged above so we remove invalid items from stacks
14322            group.stack.retain(|id| final_selection_ids.contains(id));
14323
14324            // single selection in stack can be treated as initial state
14325            group.stack.len() > 1
14326        });
14327
14328        if !state.groups.is_empty() {
14329            self.add_selections_state = Some(state);
14330        }
14331    }
14332
14333    fn select_match_ranges(
14334        &mut self,
14335        range: Range<usize>,
14336        reversed: bool,
14337        replace_newest: bool,
14338        auto_scroll: Option<Autoscroll>,
14339        window: &mut Window,
14340        cx: &mut Context<Editor>,
14341    ) {
14342        self.unfold_ranges(
14343            std::slice::from_ref(&range),
14344            false,
14345            auto_scroll.is_some(),
14346            cx,
14347        );
14348        let effects = if let Some(scroll) = auto_scroll {
14349            SelectionEffects::scroll(scroll)
14350        } else {
14351            SelectionEffects::no_scroll()
14352        };
14353        self.change_selections(effects, window, cx, |s| {
14354            if replace_newest {
14355                s.delete(s.newest_anchor().id);
14356            }
14357            if reversed {
14358                s.insert_range(range.end..range.start);
14359            } else {
14360                s.insert_range(range);
14361            }
14362        });
14363    }
14364
14365    pub fn select_next_match_internal(
14366        &mut self,
14367        display_map: &DisplaySnapshot,
14368        replace_newest: bool,
14369        autoscroll: Option<Autoscroll>,
14370        window: &mut Window,
14371        cx: &mut Context<Self>,
14372    ) -> Result<()> {
14373        let buffer = &display_map.buffer_snapshot;
14374        let mut selections = self.selections.all::<usize>(cx);
14375        if let Some(mut select_next_state) = self.select_next_state.take() {
14376            let query = &select_next_state.query;
14377            if !select_next_state.done {
14378                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14379                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14380                let mut next_selected_range = None;
14381
14382                let bytes_after_last_selection =
14383                    buffer.bytes_in_range(last_selection.end..buffer.len());
14384                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14385                let query_matches = query
14386                    .stream_find_iter(bytes_after_last_selection)
14387                    .map(|result| (last_selection.end, result))
14388                    .chain(
14389                        query
14390                            .stream_find_iter(bytes_before_first_selection)
14391                            .map(|result| (0, result)),
14392                    );
14393
14394                for (start_offset, query_match) in query_matches {
14395                    let query_match = query_match.unwrap(); // can only fail due to I/O
14396                    let offset_range =
14397                        start_offset + query_match.start()..start_offset + query_match.end();
14398
14399                    if !select_next_state.wordwise
14400                        || (!buffer.is_inside_word(offset_range.start, None)
14401                            && !buffer.is_inside_word(offset_range.end, None))
14402                    {
14403                        // TODO: This is n^2, because we might check all the selections
14404                        if !selections
14405                            .iter()
14406                            .any(|selection| selection.range().overlaps(&offset_range))
14407                        {
14408                            next_selected_range = Some(offset_range);
14409                            break;
14410                        }
14411                    }
14412                }
14413
14414                if let Some(next_selected_range) = next_selected_range {
14415                    self.select_match_ranges(
14416                        next_selected_range,
14417                        last_selection.reversed,
14418                        replace_newest,
14419                        autoscroll,
14420                        window,
14421                        cx,
14422                    );
14423                } else {
14424                    select_next_state.done = true;
14425                }
14426            }
14427
14428            self.select_next_state = Some(select_next_state);
14429        } else {
14430            let mut only_carets = true;
14431            let mut same_text_selected = true;
14432            let mut selected_text = None;
14433
14434            let mut selections_iter = selections.iter().peekable();
14435            while let Some(selection) = selections_iter.next() {
14436                if selection.start != selection.end {
14437                    only_carets = false;
14438                }
14439
14440                if same_text_selected {
14441                    if selected_text.is_none() {
14442                        selected_text =
14443                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14444                    }
14445
14446                    if let Some(next_selection) = selections_iter.peek() {
14447                        if next_selection.range().len() == selection.range().len() {
14448                            let next_selected_text = buffer
14449                                .text_for_range(next_selection.range())
14450                                .collect::<String>();
14451                            if Some(next_selected_text) != selected_text {
14452                                same_text_selected = false;
14453                                selected_text = None;
14454                            }
14455                        } else {
14456                            same_text_selected = false;
14457                            selected_text = None;
14458                        }
14459                    }
14460                }
14461            }
14462
14463            if only_carets {
14464                for selection in &mut selections {
14465                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14466                    selection.start = word_range.start;
14467                    selection.end = word_range.end;
14468                    selection.goal = SelectionGoal::None;
14469                    selection.reversed = false;
14470                    self.select_match_ranges(
14471                        selection.start..selection.end,
14472                        selection.reversed,
14473                        replace_newest,
14474                        autoscroll,
14475                        window,
14476                        cx,
14477                    );
14478                }
14479
14480                if selections.len() == 1 {
14481                    let selection = selections
14482                        .last()
14483                        .expect("ensured that there's only one selection");
14484                    let query = buffer
14485                        .text_for_range(selection.start..selection.end)
14486                        .collect::<String>();
14487                    let is_empty = query.is_empty();
14488                    let select_state = SelectNextState {
14489                        query: AhoCorasick::new(&[query])?,
14490                        wordwise: true,
14491                        done: is_empty,
14492                    };
14493                    self.select_next_state = Some(select_state);
14494                } else {
14495                    self.select_next_state = None;
14496                }
14497            } else if let Some(selected_text) = selected_text {
14498                self.select_next_state = Some(SelectNextState {
14499                    query: AhoCorasick::new(&[selected_text])?,
14500                    wordwise: false,
14501                    done: false,
14502                });
14503                self.select_next_match_internal(
14504                    display_map,
14505                    replace_newest,
14506                    autoscroll,
14507                    window,
14508                    cx,
14509                )?;
14510            }
14511        }
14512        Ok(())
14513    }
14514
14515    pub fn select_all_matches(
14516        &mut self,
14517        _action: &SelectAllMatches,
14518        window: &mut Window,
14519        cx: &mut Context<Self>,
14520    ) -> Result<()> {
14521        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14522
14523        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14524
14525        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14526        let Some(select_next_state) = self.select_next_state.as_mut() else {
14527            return Ok(());
14528        };
14529        if select_next_state.done {
14530            return Ok(());
14531        }
14532
14533        let mut new_selections = Vec::new();
14534
14535        let reversed = self.selections.oldest::<usize>(cx).reversed;
14536        let buffer = &display_map.buffer_snapshot;
14537        let query_matches = select_next_state
14538            .query
14539            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14540
14541        for query_match in query_matches.into_iter() {
14542            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14543            let offset_range = if reversed {
14544                query_match.end()..query_match.start()
14545            } else {
14546                query_match.start()..query_match.end()
14547            };
14548
14549            if !select_next_state.wordwise
14550                || (!buffer.is_inside_word(offset_range.start, None)
14551                    && !buffer.is_inside_word(offset_range.end, None))
14552            {
14553                new_selections.push(offset_range.start..offset_range.end);
14554            }
14555        }
14556
14557        select_next_state.done = true;
14558
14559        if new_selections.is_empty() {
14560            log::error!("bug: new_selections is empty in select_all_matches");
14561            return Ok(());
14562        }
14563
14564        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14565        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14566            selections.select_ranges(new_selections)
14567        });
14568
14569        Ok(())
14570    }
14571
14572    pub fn select_next(
14573        &mut self,
14574        action: &SelectNext,
14575        window: &mut Window,
14576        cx: &mut Context<Self>,
14577    ) -> Result<()> {
14578        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14579        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14580        self.select_next_match_internal(
14581            &display_map,
14582            action.replace_newest,
14583            Some(Autoscroll::newest()),
14584            window,
14585            cx,
14586        )?;
14587        Ok(())
14588    }
14589
14590    pub fn select_previous(
14591        &mut self,
14592        action: &SelectPrevious,
14593        window: &mut Window,
14594        cx: &mut Context<Self>,
14595    ) -> Result<()> {
14596        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14597        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14598        let buffer = &display_map.buffer_snapshot;
14599        let mut selections = self.selections.all::<usize>(cx);
14600        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14601            let query = &select_prev_state.query;
14602            if !select_prev_state.done {
14603                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14604                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14605                let mut next_selected_range = None;
14606                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14607                let bytes_before_last_selection =
14608                    buffer.reversed_bytes_in_range(0..last_selection.start);
14609                let bytes_after_first_selection =
14610                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14611                let query_matches = query
14612                    .stream_find_iter(bytes_before_last_selection)
14613                    .map(|result| (last_selection.start, result))
14614                    .chain(
14615                        query
14616                            .stream_find_iter(bytes_after_first_selection)
14617                            .map(|result| (buffer.len(), result)),
14618                    );
14619                for (end_offset, query_match) in query_matches {
14620                    let query_match = query_match.unwrap(); // can only fail due to I/O
14621                    let offset_range =
14622                        end_offset - query_match.end()..end_offset - query_match.start();
14623
14624                    if !select_prev_state.wordwise
14625                        || (!buffer.is_inside_word(offset_range.start, None)
14626                            && !buffer.is_inside_word(offset_range.end, None))
14627                    {
14628                        next_selected_range = Some(offset_range);
14629                        break;
14630                    }
14631                }
14632
14633                if let Some(next_selected_range) = next_selected_range {
14634                    self.select_match_ranges(
14635                        next_selected_range,
14636                        last_selection.reversed,
14637                        action.replace_newest,
14638                        Some(Autoscroll::newest()),
14639                        window,
14640                        cx,
14641                    );
14642                } else {
14643                    select_prev_state.done = true;
14644                }
14645            }
14646
14647            self.select_prev_state = Some(select_prev_state);
14648        } else {
14649            let mut only_carets = true;
14650            let mut same_text_selected = true;
14651            let mut selected_text = None;
14652
14653            let mut selections_iter = selections.iter().peekable();
14654            while let Some(selection) = selections_iter.next() {
14655                if selection.start != selection.end {
14656                    only_carets = false;
14657                }
14658
14659                if same_text_selected {
14660                    if selected_text.is_none() {
14661                        selected_text =
14662                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14663                    }
14664
14665                    if let Some(next_selection) = selections_iter.peek() {
14666                        if next_selection.range().len() == selection.range().len() {
14667                            let next_selected_text = buffer
14668                                .text_for_range(next_selection.range())
14669                                .collect::<String>();
14670                            if Some(next_selected_text) != selected_text {
14671                                same_text_selected = false;
14672                                selected_text = None;
14673                            }
14674                        } else {
14675                            same_text_selected = false;
14676                            selected_text = None;
14677                        }
14678                    }
14679                }
14680            }
14681
14682            if only_carets {
14683                for selection in &mut selections {
14684                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14685                    selection.start = word_range.start;
14686                    selection.end = word_range.end;
14687                    selection.goal = SelectionGoal::None;
14688                    selection.reversed = false;
14689                    self.select_match_ranges(
14690                        selection.start..selection.end,
14691                        selection.reversed,
14692                        action.replace_newest,
14693                        Some(Autoscroll::newest()),
14694                        window,
14695                        cx,
14696                    );
14697                }
14698                if selections.len() == 1 {
14699                    let selection = selections
14700                        .last()
14701                        .expect("ensured that there's only one selection");
14702                    let query = buffer
14703                        .text_for_range(selection.start..selection.end)
14704                        .collect::<String>();
14705                    let is_empty = query.is_empty();
14706                    let select_state = SelectNextState {
14707                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14708                        wordwise: true,
14709                        done: is_empty,
14710                    };
14711                    self.select_prev_state = Some(select_state);
14712                } else {
14713                    self.select_prev_state = None;
14714                }
14715            } else if let Some(selected_text) = selected_text {
14716                self.select_prev_state = Some(SelectNextState {
14717                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14718                    wordwise: false,
14719                    done: false,
14720                });
14721                self.select_previous(action, window, cx)?;
14722            }
14723        }
14724        Ok(())
14725    }
14726
14727    pub fn find_next_match(
14728        &mut self,
14729        _: &FindNextMatch,
14730        window: &mut Window,
14731        cx: &mut Context<Self>,
14732    ) -> Result<()> {
14733        let selections = self.selections.disjoint_anchors_arc();
14734        match selections.first() {
14735            Some(first) if selections.len() >= 2 => {
14736                self.change_selections(Default::default(), window, cx, |s| {
14737                    s.select_ranges([first.range()]);
14738                });
14739            }
14740            _ => self.select_next(
14741                &SelectNext {
14742                    replace_newest: true,
14743                },
14744                window,
14745                cx,
14746            )?,
14747        }
14748        Ok(())
14749    }
14750
14751    pub fn find_previous_match(
14752        &mut self,
14753        _: &FindPreviousMatch,
14754        window: &mut Window,
14755        cx: &mut Context<Self>,
14756    ) -> Result<()> {
14757        let selections = self.selections.disjoint_anchors_arc();
14758        match selections.last() {
14759            Some(last) if selections.len() >= 2 => {
14760                self.change_selections(Default::default(), window, cx, |s| {
14761                    s.select_ranges([last.range()]);
14762                });
14763            }
14764            _ => self.select_previous(
14765                &SelectPrevious {
14766                    replace_newest: true,
14767                },
14768                window,
14769                cx,
14770            )?,
14771        }
14772        Ok(())
14773    }
14774
14775    pub fn toggle_comments(
14776        &mut self,
14777        action: &ToggleComments,
14778        window: &mut Window,
14779        cx: &mut Context<Self>,
14780    ) {
14781        if self.read_only(cx) {
14782            return;
14783        }
14784        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14785        let text_layout_details = &self.text_layout_details(window);
14786        self.transact(window, cx, |this, window, cx| {
14787            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14788            let mut edits = Vec::new();
14789            let mut selection_edit_ranges = Vec::new();
14790            let mut last_toggled_row = None;
14791            let snapshot = this.buffer.read(cx).read(cx);
14792            let empty_str: Arc<str> = Arc::default();
14793            let mut suffixes_inserted = Vec::new();
14794            let ignore_indent = action.ignore_indent;
14795
14796            fn comment_prefix_range(
14797                snapshot: &MultiBufferSnapshot,
14798                row: MultiBufferRow,
14799                comment_prefix: &str,
14800                comment_prefix_whitespace: &str,
14801                ignore_indent: bool,
14802            ) -> Range<Point> {
14803                let indent_size = if ignore_indent {
14804                    0
14805                } else {
14806                    snapshot.indent_size_for_line(row).len
14807                };
14808
14809                let start = Point::new(row.0, indent_size);
14810
14811                let mut line_bytes = snapshot
14812                    .bytes_in_range(start..snapshot.max_point())
14813                    .flatten()
14814                    .copied();
14815
14816                // If this line currently begins with the line comment prefix, then record
14817                // the range containing the prefix.
14818                if line_bytes
14819                    .by_ref()
14820                    .take(comment_prefix.len())
14821                    .eq(comment_prefix.bytes())
14822                {
14823                    // Include any whitespace that matches the comment prefix.
14824                    let matching_whitespace_len = line_bytes
14825                        .zip(comment_prefix_whitespace.bytes())
14826                        .take_while(|(a, b)| a == b)
14827                        .count() as u32;
14828                    let end = Point::new(
14829                        start.row,
14830                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14831                    );
14832                    start..end
14833                } else {
14834                    start..start
14835                }
14836            }
14837
14838            fn comment_suffix_range(
14839                snapshot: &MultiBufferSnapshot,
14840                row: MultiBufferRow,
14841                comment_suffix: &str,
14842                comment_suffix_has_leading_space: bool,
14843            ) -> Range<Point> {
14844                let end = Point::new(row.0, snapshot.line_len(row));
14845                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14846
14847                let mut line_end_bytes = snapshot
14848                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14849                    .flatten()
14850                    .copied();
14851
14852                let leading_space_len = if suffix_start_column > 0
14853                    && line_end_bytes.next() == Some(b' ')
14854                    && comment_suffix_has_leading_space
14855                {
14856                    1
14857                } else {
14858                    0
14859                };
14860
14861                // If this line currently begins with the line comment prefix, then record
14862                // the range containing the prefix.
14863                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14864                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14865                    start..end
14866                } else {
14867                    end..end
14868                }
14869            }
14870
14871            // TODO: Handle selections that cross excerpts
14872            for selection in &mut selections {
14873                let start_column = snapshot
14874                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14875                    .len;
14876                let language = if let Some(language) =
14877                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14878                {
14879                    language
14880                } else {
14881                    continue;
14882                };
14883
14884                selection_edit_ranges.clear();
14885
14886                // If multiple selections contain a given row, avoid processing that
14887                // row more than once.
14888                let mut start_row = MultiBufferRow(selection.start.row);
14889                if last_toggled_row == Some(start_row) {
14890                    start_row = start_row.next_row();
14891                }
14892                let end_row =
14893                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14894                        MultiBufferRow(selection.end.row - 1)
14895                    } else {
14896                        MultiBufferRow(selection.end.row)
14897                    };
14898                last_toggled_row = Some(end_row);
14899
14900                if start_row > end_row {
14901                    continue;
14902                }
14903
14904                // If the language has line comments, toggle those.
14905                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14906
14907                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14908                if ignore_indent {
14909                    full_comment_prefixes = full_comment_prefixes
14910                        .into_iter()
14911                        .map(|s| Arc::from(s.trim_end()))
14912                        .collect();
14913                }
14914
14915                if !full_comment_prefixes.is_empty() {
14916                    let first_prefix = full_comment_prefixes
14917                        .first()
14918                        .expect("prefixes is non-empty");
14919                    let prefix_trimmed_lengths = full_comment_prefixes
14920                        .iter()
14921                        .map(|p| p.trim_end_matches(' ').len())
14922                        .collect::<SmallVec<[usize; 4]>>();
14923
14924                    let mut all_selection_lines_are_comments = true;
14925
14926                    for row in start_row.0..=end_row.0 {
14927                        let row = MultiBufferRow(row);
14928                        if start_row < end_row && snapshot.is_line_blank(row) {
14929                            continue;
14930                        }
14931
14932                        let prefix_range = full_comment_prefixes
14933                            .iter()
14934                            .zip(prefix_trimmed_lengths.iter().copied())
14935                            .map(|(prefix, trimmed_prefix_len)| {
14936                                comment_prefix_range(
14937                                    snapshot.deref(),
14938                                    row,
14939                                    &prefix[..trimmed_prefix_len],
14940                                    &prefix[trimmed_prefix_len..],
14941                                    ignore_indent,
14942                                )
14943                            })
14944                            .max_by_key(|range| range.end.column - range.start.column)
14945                            .expect("prefixes is non-empty");
14946
14947                        if prefix_range.is_empty() {
14948                            all_selection_lines_are_comments = false;
14949                        }
14950
14951                        selection_edit_ranges.push(prefix_range);
14952                    }
14953
14954                    if all_selection_lines_are_comments {
14955                        edits.extend(
14956                            selection_edit_ranges
14957                                .iter()
14958                                .cloned()
14959                                .map(|range| (range, empty_str.clone())),
14960                        );
14961                    } else {
14962                        let min_column = selection_edit_ranges
14963                            .iter()
14964                            .map(|range| range.start.column)
14965                            .min()
14966                            .unwrap_or(0);
14967                        edits.extend(selection_edit_ranges.iter().map(|range| {
14968                            let position = Point::new(range.start.row, min_column);
14969                            (position..position, first_prefix.clone())
14970                        }));
14971                    }
14972                } else if let Some(BlockCommentConfig {
14973                    start: full_comment_prefix,
14974                    end: comment_suffix,
14975                    ..
14976                }) = language.block_comment()
14977                {
14978                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14979                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14980                    let prefix_range = comment_prefix_range(
14981                        snapshot.deref(),
14982                        start_row,
14983                        comment_prefix,
14984                        comment_prefix_whitespace,
14985                        ignore_indent,
14986                    );
14987                    let suffix_range = comment_suffix_range(
14988                        snapshot.deref(),
14989                        end_row,
14990                        comment_suffix.trim_start_matches(' '),
14991                        comment_suffix.starts_with(' '),
14992                    );
14993
14994                    if prefix_range.is_empty() || suffix_range.is_empty() {
14995                        edits.push((
14996                            prefix_range.start..prefix_range.start,
14997                            full_comment_prefix.clone(),
14998                        ));
14999                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15000                        suffixes_inserted.push((end_row, comment_suffix.len()));
15001                    } else {
15002                        edits.push((prefix_range, empty_str.clone()));
15003                        edits.push((suffix_range, empty_str.clone()));
15004                    }
15005                } else {
15006                    continue;
15007                }
15008            }
15009
15010            drop(snapshot);
15011            this.buffer.update(cx, |buffer, cx| {
15012                buffer.edit(edits, None, cx);
15013            });
15014
15015            // Adjust selections so that they end before any comment suffixes that
15016            // were inserted.
15017            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15018            let mut selections = this.selections.all::<Point>(cx);
15019            let snapshot = this.buffer.read(cx).read(cx);
15020            for selection in &mut selections {
15021                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15022                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15023                        Ordering::Less => {
15024                            suffixes_inserted.next();
15025                            continue;
15026                        }
15027                        Ordering::Greater => break,
15028                        Ordering::Equal => {
15029                            if selection.end.column == snapshot.line_len(row) {
15030                                if selection.is_empty() {
15031                                    selection.start.column -= suffix_len as u32;
15032                                }
15033                                selection.end.column -= suffix_len as u32;
15034                            }
15035                            break;
15036                        }
15037                    }
15038                }
15039            }
15040
15041            drop(snapshot);
15042            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15043
15044            let selections = this.selections.all::<Point>(cx);
15045            let selections_on_single_row = selections.windows(2).all(|selections| {
15046                selections[0].start.row == selections[1].start.row
15047                    && selections[0].end.row == selections[1].end.row
15048                    && selections[0].start.row == selections[0].end.row
15049            });
15050            let selections_selecting = selections
15051                .iter()
15052                .any(|selection| selection.start != selection.end);
15053            let advance_downwards = action.advance_downwards
15054                && selections_on_single_row
15055                && !selections_selecting
15056                && !matches!(this.mode, EditorMode::SingleLine);
15057
15058            if advance_downwards {
15059                let snapshot = this.buffer.read(cx).snapshot(cx);
15060
15061                this.change_selections(Default::default(), window, cx, |s| {
15062                    s.move_cursors_with(|display_snapshot, display_point, _| {
15063                        let mut point = display_point.to_point(display_snapshot);
15064                        point.row += 1;
15065                        point = snapshot.clip_point(point, Bias::Left);
15066                        let display_point = point.to_display_point(display_snapshot);
15067                        let goal = SelectionGoal::HorizontalPosition(
15068                            display_snapshot
15069                                .x_for_display_point(display_point, text_layout_details)
15070                                .into(),
15071                        );
15072                        (display_point, goal)
15073                    })
15074                });
15075            }
15076        });
15077    }
15078
15079    pub fn select_enclosing_symbol(
15080        &mut self,
15081        _: &SelectEnclosingSymbol,
15082        window: &mut Window,
15083        cx: &mut Context<Self>,
15084    ) {
15085        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15086
15087        let buffer = self.buffer.read(cx).snapshot(cx);
15088        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15089
15090        fn update_selection(
15091            selection: &Selection<usize>,
15092            buffer_snap: &MultiBufferSnapshot,
15093        ) -> Option<Selection<usize>> {
15094            let cursor = selection.head();
15095            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15096            for symbol in symbols.iter().rev() {
15097                let start = symbol.range.start.to_offset(buffer_snap);
15098                let end = symbol.range.end.to_offset(buffer_snap);
15099                let new_range = start..end;
15100                if start < selection.start || end > selection.end {
15101                    return Some(Selection {
15102                        id: selection.id,
15103                        start: new_range.start,
15104                        end: new_range.end,
15105                        goal: SelectionGoal::None,
15106                        reversed: selection.reversed,
15107                    });
15108                }
15109            }
15110            None
15111        }
15112
15113        let mut selected_larger_symbol = false;
15114        let new_selections = old_selections
15115            .iter()
15116            .map(|selection| match update_selection(selection, &buffer) {
15117                Some(new_selection) => {
15118                    if new_selection.range() != selection.range() {
15119                        selected_larger_symbol = true;
15120                    }
15121                    new_selection
15122                }
15123                None => selection.clone(),
15124            })
15125            .collect::<Vec<_>>();
15126
15127        if selected_larger_symbol {
15128            self.change_selections(Default::default(), window, cx, |s| {
15129                s.select(new_selections);
15130            });
15131        }
15132    }
15133
15134    pub fn select_larger_syntax_node(
15135        &mut self,
15136        _: &SelectLargerSyntaxNode,
15137        window: &mut Window,
15138        cx: &mut Context<Self>,
15139    ) {
15140        let Some(visible_row_count) = self.visible_row_count() else {
15141            return;
15142        };
15143        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15144        if old_selections.is_empty() {
15145            return;
15146        }
15147
15148        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15149
15150        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15151        let buffer = self.buffer.read(cx).snapshot(cx);
15152
15153        let mut selected_larger_node = false;
15154        let mut new_selections = old_selections
15155            .iter()
15156            .map(|selection| {
15157                let old_range = selection.start..selection.end;
15158
15159                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15160                    // manually select word at selection
15161                    if ["string_content", "inline"].contains(&node.kind()) {
15162                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15163                        // ignore if word is already selected
15164                        if !word_range.is_empty() && old_range != word_range {
15165                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15166                            // only select word if start and end point belongs to same word
15167                            if word_range == last_word_range {
15168                                selected_larger_node = true;
15169                                return Selection {
15170                                    id: selection.id,
15171                                    start: word_range.start,
15172                                    end: word_range.end,
15173                                    goal: SelectionGoal::None,
15174                                    reversed: selection.reversed,
15175                                };
15176                            }
15177                        }
15178                    }
15179                }
15180
15181                let mut new_range = old_range.clone();
15182                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15183                    new_range = range;
15184                    if !node.is_named() {
15185                        continue;
15186                    }
15187                    if !display_map.intersects_fold(new_range.start)
15188                        && !display_map.intersects_fold(new_range.end)
15189                    {
15190                        break;
15191                    }
15192                }
15193
15194                selected_larger_node |= new_range != old_range;
15195                Selection {
15196                    id: selection.id,
15197                    start: new_range.start,
15198                    end: new_range.end,
15199                    goal: SelectionGoal::None,
15200                    reversed: selection.reversed,
15201                }
15202            })
15203            .collect::<Vec<_>>();
15204
15205        if !selected_larger_node {
15206            return; // don't put this call in the history
15207        }
15208
15209        // scroll based on transformation done to the last selection created by the user
15210        let (last_old, last_new) = old_selections
15211            .last()
15212            .zip(new_selections.last().cloned())
15213            .expect("old_selections isn't empty");
15214
15215        // revert selection
15216        let is_selection_reversed = {
15217            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15218            new_selections.last_mut().expect("checked above").reversed =
15219                should_newest_selection_be_reversed;
15220            should_newest_selection_be_reversed
15221        };
15222
15223        if selected_larger_node {
15224            self.select_syntax_node_history.disable_clearing = true;
15225            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15226                s.select(new_selections.clone());
15227            });
15228            self.select_syntax_node_history.disable_clearing = false;
15229        }
15230
15231        let start_row = last_new.start.to_display_point(&display_map).row().0;
15232        let end_row = last_new.end.to_display_point(&display_map).row().0;
15233        let selection_height = end_row - start_row + 1;
15234        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15235
15236        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15237        let scroll_behavior = if fits_on_the_screen {
15238            self.request_autoscroll(Autoscroll::fit(), cx);
15239            SelectSyntaxNodeScrollBehavior::FitSelection
15240        } else if is_selection_reversed {
15241            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15242            SelectSyntaxNodeScrollBehavior::CursorTop
15243        } else {
15244            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15245            SelectSyntaxNodeScrollBehavior::CursorBottom
15246        };
15247
15248        self.select_syntax_node_history.push((
15249            old_selections,
15250            scroll_behavior,
15251            is_selection_reversed,
15252        ));
15253    }
15254
15255    pub fn select_smaller_syntax_node(
15256        &mut self,
15257        _: &SelectSmallerSyntaxNode,
15258        window: &mut Window,
15259        cx: &mut Context<Self>,
15260    ) {
15261        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15262
15263        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15264            self.select_syntax_node_history.pop()
15265        {
15266            if let Some(selection) = selections.last_mut() {
15267                selection.reversed = is_selection_reversed;
15268            }
15269
15270            self.select_syntax_node_history.disable_clearing = true;
15271            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15272                s.select(selections.to_vec());
15273            });
15274            self.select_syntax_node_history.disable_clearing = false;
15275
15276            match scroll_behavior {
15277                SelectSyntaxNodeScrollBehavior::CursorTop => {
15278                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15279                }
15280                SelectSyntaxNodeScrollBehavior::FitSelection => {
15281                    self.request_autoscroll(Autoscroll::fit(), cx);
15282                }
15283                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15284                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15285                }
15286            }
15287        }
15288    }
15289
15290    pub fn unwrap_syntax_node(
15291        &mut self,
15292        _: &UnwrapSyntaxNode,
15293        window: &mut Window,
15294        cx: &mut Context<Self>,
15295    ) {
15296        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15297
15298        let buffer = self.buffer.read(cx).snapshot(cx);
15299        let selections = self
15300            .selections
15301            .all::<usize>(cx)
15302            .into_iter()
15303            // subtracting the offset requires sorting
15304            .sorted_by_key(|i| i.start);
15305
15306        let full_edits = selections
15307            .into_iter()
15308            .filter_map(|selection| {
15309                let child = if selection.is_empty()
15310                    && let Some((_, ancestor_range)) =
15311                        buffer.syntax_ancestor(selection.start..selection.end)
15312                {
15313                    ancestor_range
15314                } else {
15315                    selection.range()
15316                };
15317
15318                let mut parent = child.clone();
15319                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15320                    parent = ancestor_range;
15321                    if parent.start < child.start || parent.end > child.end {
15322                        break;
15323                    }
15324                }
15325
15326                if parent == child {
15327                    return None;
15328                }
15329                let text = buffer.text_for_range(child).collect::<String>();
15330                Some((selection.id, parent, text))
15331            })
15332            .collect::<Vec<_>>();
15333        if full_edits.is_empty() {
15334            return;
15335        }
15336
15337        self.transact(window, cx, |this, window, cx| {
15338            this.buffer.update(cx, |buffer, cx| {
15339                buffer.edit(
15340                    full_edits
15341                        .iter()
15342                        .map(|(_, p, t)| (p.clone(), t.clone()))
15343                        .collect::<Vec<_>>(),
15344                    None,
15345                    cx,
15346                );
15347            });
15348            this.change_selections(Default::default(), window, cx, |s| {
15349                let mut offset = 0;
15350                let mut selections = vec![];
15351                for (id, parent, text) in full_edits {
15352                    let start = parent.start - offset;
15353                    offset += parent.len() - text.len();
15354                    selections.push(Selection {
15355                        id,
15356                        start,
15357                        end: start + text.len(),
15358                        reversed: false,
15359                        goal: Default::default(),
15360                    });
15361                }
15362                s.select(selections);
15363            });
15364        });
15365    }
15366
15367    pub fn select_next_syntax_node(
15368        &mut self,
15369        _: &SelectNextSyntaxNode,
15370        window: &mut Window,
15371        cx: &mut Context<Self>,
15372    ) {
15373        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15374        if old_selections.is_empty() {
15375            return;
15376        }
15377
15378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15379
15380        let buffer = self.buffer.read(cx).snapshot(cx);
15381        let mut selected_sibling = false;
15382
15383        let new_selections = old_selections
15384            .iter()
15385            .map(|selection| {
15386                let old_range = selection.start..selection.end;
15387
15388                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15389                    let new_range = node.byte_range();
15390                    selected_sibling = true;
15391                    Selection {
15392                        id: selection.id,
15393                        start: new_range.start,
15394                        end: new_range.end,
15395                        goal: SelectionGoal::None,
15396                        reversed: selection.reversed,
15397                    }
15398                } else {
15399                    selection.clone()
15400                }
15401            })
15402            .collect::<Vec<_>>();
15403
15404        if selected_sibling {
15405            self.change_selections(
15406                SelectionEffects::scroll(Autoscroll::fit()),
15407                window,
15408                cx,
15409                |s| {
15410                    s.select(new_selections);
15411                },
15412            );
15413        }
15414    }
15415
15416    pub fn select_prev_syntax_node(
15417        &mut self,
15418        _: &SelectPreviousSyntaxNode,
15419        window: &mut Window,
15420        cx: &mut Context<Self>,
15421    ) {
15422        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15423        if old_selections.is_empty() {
15424            return;
15425        }
15426
15427        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15428
15429        let buffer = self.buffer.read(cx).snapshot(cx);
15430        let mut selected_sibling = false;
15431
15432        let new_selections = old_selections
15433            .iter()
15434            .map(|selection| {
15435                let old_range = selection.start..selection.end;
15436
15437                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15438                    let new_range = node.byte_range();
15439                    selected_sibling = true;
15440                    Selection {
15441                        id: selection.id,
15442                        start: new_range.start,
15443                        end: new_range.end,
15444                        goal: SelectionGoal::None,
15445                        reversed: selection.reversed,
15446                    }
15447                } else {
15448                    selection.clone()
15449                }
15450            })
15451            .collect::<Vec<_>>();
15452
15453        if selected_sibling {
15454            self.change_selections(
15455                SelectionEffects::scroll(Autoscroll::fit()),
15456                window,
15457                cx,
15458                |s| {
15459                    s.select(new_selections);
15460                },
15461            );
15462        }
15463    }
15464
15465    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15466        if !EditorSettings::get_global(cx).gutter.runnables {
15467            self.clear_tasks();
15468            return Task::ready(());
15469        }
15470        let project = self.project().map(Entity::downgrade);
15471        let task_sources = self.lsp_task_sources(cx);
15472        let multi_buffer = self.buffer.downgrade();
15473        cx.spawn_in(window, async move |editor, cx| {
15474            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15475            let Some(project) = project.and_then(|p| p.upgrade()) else {
15476                return;
15477            };
15478            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15479                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15480            }) else {
15481                return;
15482            };
15483
15484            let hide_runnables = project
15485                .update(cx, |project, _| project.is_via_collab())
15486                .unwrap_or(true);
15487            if hide_runnables {
15488                return;
15489            }
15490            let new_rows =
15491                cx.background_spawn({
15492                    let snapshot = display_snapshot.clone();
15493                    async move {
15494                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15495                    }
15496                })
15497                    .await;
15498            let Ok(lsp_tasks) =
15499                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15500            else {
15501                return;
15502            };
15503            let lsp_tasks = lsp_tasks.await;
15504
15505            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15506                lsp_tasks
15507                    .into_iter()
15508                    .flat_map(|(kind, tasks)| {
15509                        tasks.into_iter().filter_map(move |(location, task)| {
15510                            Some((kind.clone(), location?, task))
15511                        })
15512                    })
15513                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15514                        let buffer = location.target.buffer;
15515                        let buffer_snapshot = buffer.read(cx).snapshot();
15516                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15517                            |(excerpt_id, snapshot, _)| {
15518                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15519                                    display_snapshot
15520                                        .buffer_snapshot
15521                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15522                                } else {
15523                                    None
15524                                }
15525                            },
15526                        );
15527                        if let Some(offset) = offset {
15528                            let task_buffer_range =
15529                                location.target.range.to_point(&buffer_snapshot);
15530                            let context_buffer_range =
15531                                task_buffer_range.to_offset(&buffer_snapshot);
15532                            let context_range = BufferOffset(context_buffer_range.start)
15533                                ..BufferOffset(context_buffer_range.end);
15534
15535                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15536                                .or_insert_with(|| RunnableTasks {
15537                                    templates: Vec::new(),
15538                                    offset,
15539                                    column: task_buffer_range.start.column,
15540                                    extra_variables: HashMap::default(),
15541                                    context_range,
15542                                })
15543                                .templates
15544                                .push((kind, task.original_task().clone()));
15545                        }
15546
15547                        acc
15548                    })
15549            }) else {
15550                return;
15551            };
15552
15553            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15554                buffer.language_settings(cx).tasks.prefer_lsp
15555            }) else {
15556                return;
15557            };
15558
15559            let rows = Self::runnable_rows(
15560                project,
15561                display_snapshot,
15562                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15563                new_rows,
15564                cx.clone(),
15565            )
15566            .await;
15567            editor
15568                .update(cx, |editor, _| {
15569                    editor.clear_tasks();
15570                    for (key, mut value) in rows {
15571                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15572                            value.templates.extend(lsp_tasks.templates);
15573                        }
15574
15575                        editor.insert_tasks(key, value);
15576                    }
15577                    for (key, value) in lsp_tasks_by_rows {
15578                        editor.insert_tasks(key, value);
15579                    }
15580                })
15581                .ok();
15582        })
15583    }
15584    fn fetch_runnable_ranges(
15585        snapshot: &DisplaySnapshot,
15586        range: Range<Anchor>,
15587    ) -> Vec<language::RunnableRange> {
15588        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15589    }
15590
15591    fn runnable_rows(
15592        project: Entity<Project>,
15593        snapshot: DisplaySnapshot,
15594        prefer_lsp: bool,
15595        runnable_ranges: Vec<RunnableRange>,
15596        cx: AsyncWindowContext,
15597    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15598        cx.spawn(async move |cx| {
15599            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15600            for mut runnable in runnable_ranges {
15601                let Some(tasks) = cx
15602                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15603                    .ok()
15604                else {
15605                    continue;
15606                };
15607                let mut tasks = tasks.await;
15608
15609                if prefer_lsp {
15610                    tasks.retain(|(task_kind, _)| {
15611                        !matches!(task_kind, TaskSourceKind::Language { .. })
15612                    });
15613                }
15614                if tasks.is_empty() {
15615                    continue;
15616                }
15617
15618                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15619                let Some(row) = snapshot
15620                    .buffer_snapshot
15621                    .buffer_line_for_row(MultiBufferRow(point.row))
15622                    .map(|(_, range)| range.start.row)
15623                else {
15624                    continue;
15625                };
15626
15627                let context_range =
15628                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15629                runnable_rows.push((
15630                    (runnable.buffer_id, row),
15631                    RunnableTasks {
15632                        templates: tasks,
15633                        offset: snapshot
15634                            .buffer_snapshot
15635                            .anchor_before(runnable.run_range.start),
15636                        context_range,
15637                        column: point.column,
15638                        extra_variables: runnable.extra_captures,
15639                    },
15640                ));
15641            }
15642            runnable_rows
15643        })
15644    }
15645
15646    fn templates_with_tags(
15647        project: &Entity<Project>,
15648        runnable: &mut Runnable,
15649        cx: &mut App,
15650    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15651        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15652            let (worktree_id, file) = project
15653                .buffer_for_id(runnable.buffer, cx)
15654                .and_then(|buffer| buffer.read(cx).file())
15655                .map(|file| (file.worktree_id(cx), file.clone()))
15656                .unzip();
15657
15658            (
15659                project.task_store().read(cx).task_inventory().cloned(),
15660                worktree_id,
15661                file,
15662            )
15663        });
15664
15665        let tags = mem::take(&mut runnable.tags);
15666        let language = runnable.language.clone();
15667        cx.spawn(async move |cx| {
15668            let mut templates_with_tags = Vec::new();
15669            if let Some(inventory) = inventory {
15670                for RunnableTag(tag) in tags {
15671                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15672                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15673                    }) else {
15674                        return templates_with_tags;
15675                    };
15676                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15677                        move |(_, template)| {
15678                            template.tags.iter().any(|source_tag| source_tag == &tag)
15679                        },
15680                    ));
15681                }
15682            }
15683            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15684
15685            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15686                // Strongest source wins; if we have worktree tag binding, prefer that to
15687                // global and language bindings;
15688                // if we have a global binding, prefer that to language binding.
15689                let first_mismatch = templates_with_tags
15690                    .iter()
15691                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15692                if let Some(index) = first_mismatch {
15693                    templates_with_tags.truncate(index);
15694                }
15695            }
15696
15697            templates_with_tags
15698        })
15699    }
15700
15701    pub fn move_to_enclosing_bracket(
15702        &mut self,
15703        _: &MoveToEnclosingBracket,
15704        window: &mut Window,
15705        cx: &mut Context<Self>,
15706    ) {
15707        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15708        self.change_selections(Default::default(), window, cx, |s| {
15709            s.move_offsets_with(|snapshot, selection| {
15710                let Some(enclosing_bracket_ranges) =
15711                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15712                else {
15713                    return;
15714                };
15715
15716                let mut best_length = usize::MAX;
15717                let mut best_inside = false;
15718                let mut best_in_bracket_range = false;
15719                let mut best_destination = None;
15720                for (open, close) in enclosing_bracket_ranges {
15721                    let close = close.to_inclusive();
15722                    let length = close.end() - open.start;
15723                    let inside = selection.start >= open.end && selection.end <= *close.start();
15724                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15725                        || close.contains(&selection.head());
15726
15727                    // If best is next to a bracket and current isn't, skip
15728                    if !in_bracket_range && best_in_bracket_range {
15729                        continue;
15730                    }
15731
15732                    // Prefer smaller lengths unless best is inside and current isn't
15733                    if length > best_length && (best_inside || !inside) {
15734                        continue;
15735                    }
15736
15737                    best_length = length;
15738                    best_inside = inside;
15739                    best_in_bracket_range = in_bracket_range;
15740                    best_destination = Some(
15741                        if close.contains(&selection.start) && close.contains(&selection.end) {
15742                            if inside { open.end } else { open.start }
15743                        } else if inside {
15744                            *close.start()
15745                        } else {
15746                            *close.end()
15747                        },
15748                    );
15749                }
15750
15751                if let Some(destination) = best_destination {
15752                    selection.collapse_to(destination, SelectionGoal::None);
15753                }
15754            })
15755        });
15756    }
15757
15758    pub fn undo_selection(
15759        &mut self,
15760        _: &UndoSelection,
15761        window: &mut Window,
15762        cx: &mut Context<Self>,
15763    ) {
15764        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15765        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15766            self.selection_history.mode = SelectionHistoryMode::Undoing;
15767            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15768                this.end_selection(window, cx);
15769                this.change_selections(
15770                    SelectionEffects::scroll(Autoscroll::newest()),
15771                    window,
15772                    cx,
15773                    |s| s.select_anchors(entry.selections.to_vec()),
15774                );
15775            });
15776            self.selection_history.mode = SelectionHistoryMode::Normal;
15777
15778            self.select_next_state = entry.select_next_state;
15779            self.select_prev_state = entry.select_prev_state;
15780            self.add_selections_state = entry.add_selections_state;
15781        }
15782    }
15783
15784    pub fn redo_selection(
15785        &mut self,
15786        _: &RedoSelection,
15787        window: &mut Window,
15788        cx: &mut Context<Self>,
15789    ) {
15790        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15791        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15792            self.selection_history.mode = SelectionHistoryMode::Redoing;
15793            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15794                this.end_selection(window, cx);
15795                this.change_selections(
15796                    SelectionEffects::scroll(Autoscroll::newest()),
15797                    window,
15798                    cx,
15799                    |s| s.select_anchors(entry.selections.to_vec()),
15800                );
15801            });
15802            self.selection_history.mode = SelectionHistoryMode::Normal;
15803
15804            self.select_next_state = entry.select_next_state;
15805            self.select_prev_state = entry.select_prev_state;
15806            self.add_selections_state = entry.add_selections_state;
15807        }
15808    }
15809
15810    pub fn expand_excerpts(
15811        &mut self,
15812        action: &ExpandExcerpts,
15813        _: &mut Window,
15814        cx: &mut Context<Self>,
15815    ) {
15816        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15817    }
15818
15819    pub fn expand_excerpts_down(
15820        &mut self,
15821        action: &ExpandExcerptsDown,
15822        _: &mut Window,
15823        cx: &mut Context<Self>,
15824    ) {
15825        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15826    }
15827
15828    pub fn expand_excerpts_up(
15829        &mut self,
15830        action: &ExpandExcerptsUp,
15831        _: &mut Window,
15832        cx: &mut Context<Self>,
15833    ) {
15834        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15835    }
15836
15837    pub fn expand_excerpts_for_direction(
15838        &mut self,
15839        lines: u32,
15840        direction: ExpandExcerptDirection,
15841
15842        cx: &mut Context<Self>,
15843    ) {
15844        let selections = self.selections.disjoint_anchors_arc();
15845
15846        let lines = if lines == 0 {
15847            EditorSettings::get_global(cx).expand_excerpt_lines
15848        } else {
15849            lines
15850        };
15851
15852        self.buffer.update(cx, |buffer, cx| {
15853            let snapshot = buffer.snapshot(cx);
15854            let mut excerpt_ids = selections
15855                .iter()
15856                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15857                .collect::<Vec<_>>();
15858            excerpt_ids.sort();
15859            excerpt_ids.dedup();
15860            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15861        })
15862    }
15863
15864    pub fn expand_excerpt(
15865        &mut self,
15866        excerpt: ExcerptId,
15867        direction: ExpandExcerptDirection,
15868        window: &mut Window,
15869        cx: &mut Context<Self>,
15870    ) {
15871        let current_scroll_position = self.scroll_position(cx);
15872        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15873        let mut should_scroll_up = false;
15874
15875        if direction == ExpandExcerptDirection::Down {
15876            let multi_buffer = self.buffer.read(cx);
15877            let snapshot = multi_buffer.snapshot(cx);
15878            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15879                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15880                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15881            {
15882                let buffer_snapshot = buffer.read(cx).snapshot();
15883                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15884                let last_row = buffer_snapshot.max_point().row;
15885                let lines_below = last_row.saturating_sub(excerpt_end_row);
15886                should_scroll_up = lines_below >= lines_to_expand;
15887            }
15888        }
15889
15890        self.buffer.update(cx, |buffer, cx| {
15891            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15892        });
15893
15894        if should_scroll_up {
15895            let new_scroll_position =
15896                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15897            self.set_scroll_position(new_scroll_position, window, cx);
15898        }
15899    }
15900
15901    pub fn go_to_singleton_buffer_point(
15902        &mut self,
15903        point: Point,
15904        window: &mut Window,
15905        cx: &mut Context<Self>,
15906    ) {
15907        self.go_to_singleton_buffer_range(point..point, window, cx);
15908    }
15909
15910    pub fn go_to_singleton_buffer_range(
15911        &mut self,
15912        range: Range<Point>,
15913        window: &mut Window,
15914        cx: &mut Context<Self>,
15915    ) {
15916        let multibuffer = self.buffer().read(cx);
15917        let Some(buffer) = multibuffer.as_singleton() else {
15918            return;
15919        };
15920        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15921            return;
15922        };
15923        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15924            return;
15925        };
15926        self.change_selections(
15927            SelectionEffects::default().nav_history(true),
15928            window,
15929            cx,
15930            |s| s.select_anchor_ranges([start..end]),
15931        );
15932    }
15933
15934    pub fn go_to_diagnostic(
15935        &mut self,
15936        action: &GoToDiagnostic,
15937        window: &mut Window,
15938        cx: &mut Context<Self>,
15939    ) {
15940        if !self.diagnostics_enabled() {
15941            return;
15942        }
15943        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15944        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15945    }
15946
15947    pub fn go_to_prev_diagnostic(
15948        &mut self,
15949        action: &GoToPreviousDiagnostic,
15950        window: &mut Window,
15951        cx: &mut Context<Self>,
15952    ) {
15953        if !self.diagnostics_enabled() {
15954            return;
15955        }
15956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15957        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15958    }
15959
15960    pub fn go_to_diagnostic_impl(
15961        &mut self,
15962        direction: Direction,
15963        severity: GoToDiagnosticSeverityFilter,
15964        window: &mut Window,
15965        cx: &mut Context<Self>,
15966    ) {
15967        let buffer = self.buffer.read(cx).snapshot(cx);
15968        let selection = self.selections.newest::<usize>(cx);
15969
15970        let mut active_group_id = None;
15971        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15972            && active_group.active_range.start.to_offset(&buffer) == selection.start
15973        {
15974            active_group_id = Some(active_group.group_id);
15975        }
15976
15977        fn filtered<'a>(
15978            snapshot: EditorSnapshot,
15979            severity: GoToDiagnosticSeverityFilter,
15980            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
15981        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
15982            diagnostics
15983                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15984                .filter(|entry| entry.range.start != entry.range.end)
15985                .filter(|entry| !entry.diagnostic.is_unnecessary)
15986                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15987        }
15988
15989        let snapshot = self.snapshot(window, cx);
15990        let before = filtered(
15991            snapshot.clone(),
15992            severity,
15993            buffer
15994                .diagnostics_in_range(0..selection.start)
15995                .filter(|entry| entry.range.start <= selection.start),
15996        );
15997        let after = filtered(
15998            snapshot,
15999            severity,
16000            buffer
16001                .diagnostics_in_range(selection.start..buffer.len())
16002                .filter(|entry| entry.range.start >= selection.start),
16003        );
16004
16005        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16006        if direction == Direction::Prev {
16007            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16008            {
16009                for diagnostic in prev_diagnostics.into_iter().rev() {
16010                    if diagnostic.range.start != selection.start
16011                        || active_group_id
16012                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16013                    {
16014                        found = Some(diagnostic);
16015                        break 'outer;
16016                    }
16017                }
16018            }
16019        } else {
16020            for diagnostic in after.chain(before) {
16021                if diagnostic.range.start != selection.start
16022                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16023                {
16024                    found = Some(diagnostic);
16025                    break;
16026                }
16027            }
16028        }
16029        let Some(next_diagnostic) = found else {
16030            return;
16031        };
16032
16033        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16034        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16035            return;
16036        };
16037        self.change_selections(Default::default(), window, cx, |s| {
16038            s.select_ranges(vec![
16039                next_diagnostic.range.start..next_diagnostic.range.start,
16040            ])
16041        });
16042        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16043        self.refresh_edit_prediction(false, true, window, cx);
16044    }
16045
16046    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16047        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16048        let snapshot = self.snapshot(window, cx);
16049        let selection = self.selections.newest::<Point>(cx);
16050        self.go_to_hunk_before_or_after_position(
16051            &snapshot,
16052            selection.head(),
16053            Direction::Next,
16054            window,
16055            cx,
16056        );
16057    }
16058
16059    pub fn go_to_hunk_before_or_after_position(
16060        &mut self,
16061        snapshot: &EditorSnapshot,
16062        position: Point,
16063        direction: Direction,
16064        window: &mut Window,
16065        cx: &mut Context<Editor>,
16066    ) {
16067        let row = if direction == Direction::Next {
16068            self.hunk_after_position(snapshot, position)
16069                .map(|hunk| hunk.row_range.start)
16070        } else {
16071            self.hunk_before_position(snapshot, position)
16072        };
16073
16074        if let Some(row) = row {
16075            let destination = Point::new(row.0, 0);
16076            let autoscroll = Autoscroll::center();
16077
16078            self.unfold_ranges(&[destination..destination], false, false, cx);
16079            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16080                s.select_ranges([destination..destination]);
16081            });
16082        }
16083    }
16084
16085    fn hunk_after_position(
16086        &mut self,
16087        snapshot: &EditorSnapshot,
16088        position: Point,
16089    ) -> Option<MultiBufferDiffHunk> {
16090        snapshot
16091            .buffer_snapshot
16092            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16093            .find(|hunk| hunk.row_range.start.0 > position.row)
16094            .or_else(|| {
16095                snapshot
16096                    .buffer_snapshot
16097                    .diff_hunks_in_range(Point::zero()..position)
16098                    .find(|hunk| hunk.row_range.end.0 < position.row)
16099            })
16100    }
16101
16102    fn go_to_prev_hunk(
16103        &mut self,
16104        _: &GoToPreviousHunk,
16105        window: &mut Window,
16106        cx: &mut Context<Self>,
16107    ) {
16108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16109        let snapshot = self.snapshot(window, cx);
16110        let selection = self.selections.newest::<Point>(cx);
16111        self.go_to_hunk_before_or_after_position(
16112            &snapshot,
16113            selection.head(),
16114            Direction::Prev,
16115            window,
16116            cx,
16117        );
16118    }
16119
16120    fn hunk_before_position(
16121        &mut self,
16122        snapshot: &EditorSnapshot,
16123        position: Point,
16124    ) -> Option<MultiBufferRow> {
16125        snapshot
16126            .buffer_snapshot
16127            .diff_hunk_before(position)
16128            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
16129    }
16130
16131    fn go_to_next_change(
16132        &mut self,
16133        _: &GoToNextChange,
16134        window: &mut Window,
16135        cx: &mut Context<Self>,
16136    ) {
16137        if let Some(selections) = self
16138            .change_list
16139            .next_change(1, Direction::Next)
16140            .map(|s| s.to_vec())
16141        {
16142            self.change_selections(Default::default(), window, cx, |s| {
16143                let map = s.display_map();
16144                s.select_display_ranges(selections.iter().map(|a| {
16145                    let point = a.to_display_point(&map);
16146                    point..point
16147                }))
16148            })
16149        }
16150    }
16151
16152    fn go_to_previous_change(
16153        &mut self,
16154        _: &GoToPreviousChange,
16155        window: &mut Window,
16156        cx: &mut Context<Self>,
16157    ) {
16158        if let Some(selections) = self
16159            .change_list
16160            .next_change(1, Direction::Prev)
16161            .map(|s| s.to_vec())
16162        {
16163            self.change_selections(Default::default(), window, cx, |s| {
16164                let map = s.display_map();
16165                s.select_display_ranges(selections.iter().map(|a| {
16166                    let point = a.to_display_point(&map);
16167                    point..point
16168                }))
16169            })
16170        }
16171    }
16172
16173    pub fn go_to_next_document_highlight(
16174        &mut self,
16175        _: &GoToNextDocumentHighlight,
16176        window: &mut Window,
16177        cx: &mut Context<Self>,
16178    ) {
16179        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16180    }
16181
16182    pub fn go_to_prev_document_highlight(
16183        &mut self,
16184        _: &GoToPreviousDocumentHighlight,
16185        window: &mut Window,
16186        cx: &mut Context<Self>,
16187    ) {
16188        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16189    }
16190
16191    pub fn go_to_document_highlight_before_or_after_position(
16192        &mut self,
16193        direction: Direction,
16194        window: &mut Window,
16195        cx: &mut Context<Editor>,
16196    ) {
16197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16198        let snapshot = self.snapshot(window, cx);
16199        let buffer = &snapshot.buffer_snapshot;
16200        let position = self.selections.newest::<Point>(cx).head();
16201        let anchor_position = buffer.anchor_after(position);
16202
16203        // Get all document highlights (both read and write)
16204        let mut all_highlights = Vec::new();
16205
16206        if let Some((_, read_highlights)) = self
16207            .background_highlights
16208            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16209        {
16210            all_highlights.extend(read_highlights.iter());
16211        }
16212
16213        if let Some((_, write_highlights)) = self
16214            .background_highlights
16215            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16216        {
16217            all_highlights.extend(write_highlights.iter());
16218        }
16219
16220        if all_highlights.is_empty() {
16221            return;
16222        }
16223
16224        // Sort highlights by position
16225        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16226
16227        let target_highlight = match direction {
16228            Direction::Next => {
16229                // Find the first highlight after the current position
16230                all_highlights
16231                    .iter()
16232                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16233            }
16234            Direction::Prev => {
16235                // Find the last highlight before the current position
16236                all_highlights
16237                    .iter()
16238                    .rev()
16239                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16240            }
16241        };
16242
16243        if let Some(highlight) = target_highlight {
16244            let destination = highlight.start.to_point(buffer);
16245            let autoscroll = Autoscroll::center();
16246
16247            self.unfold_ranges(&[destination..destination], false, false, cx);
16248            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16249                s.select_ranges([destination..destination]);
16250            });
16251        }
16252    }
16253
16254    fn go_to_line<T: 'static>(
16255        &mut self,
16256        position: Anchor,
16257        highlight_color: Option<Hsla>,
16258        window: &mut Window,
16259        cx: &mut Context<Self>,
16260    ) {
16261        let snapshot = self.snapshot(window, cx).display_snapshot;
16262        let position = position.to_point(&snapshot.buffer_snapshot);
16263        let start = snapshot
16264            .buffer_snapshot
16265            .clip_point(Point::new(position.row, 0), Bias::Left);
16266        let end = start + Point::new(1, 0);
16267        let start = snapshot.buffer_snapshot.anchor_before(start);
16268        let end = snapshot.buffer_snapshot.anchor_before(end);
16269
16270        self.highlight_rows::<T>(
16271            start..end,
16272            highlight_color
16273                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16274            Default::default(),
16275            cx,
16276        );
16277
16278        if self.buffer.read(cx).is_singleton() {
16279            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16280        }
16281    }
16282
16283    pub fn go_to_definition(
16284        &mut self,
16285        _: &GoToDefinition,
16286        window: &mut Window,
16287        cx: &mut Context<Self>,
16288    ) -> Task<Result<Navigated>> {
16289        let definition =
16290            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16291        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16292        cx.spawn_in(window, async move |editor, cx| {
16293            if definition.await? == Navigated::Yes {
16294                return Ok(Navigated::Yes);
16295            }
16296            match fallback_strategy {
16297                GoToDefinitionFallback::None => Ok(Navigated::No),
16298                GoToDefinitionFallback::FindAllReferences => {
16299                    match editor.update_in(cx, |editor, window, cx| {
16300                        editor.find_all_references(&FindAllReferences, window, cx)
16301                    })? {
16302                        Some(references) => references.await,
16303                        None => Ok(Navigated::No),
16304                    }
16305                }
16306            }
16307        })
16308    }
16309
16310    pub fn go_to_declaration(
16311        &mut self,
16312        _: &GoToDeclaration,
16313        window: &mut Window,
16314        cx: &mut Context<Self>,
16315    ) -> Task<Result<Navigated>> {
16316        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16317    }
16318
16319    pub fn go_to_declaration_split(
16320        &mut self,
16321        _: &GoToDeclaration,
16322        window: &mut Window,
16323        cx: &mut Context<Self>,
16324    ) -> Task<Result<Navigated>> {
16325        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16326    }
16327
16328    pub fn go_to_implementation(
16329        &mut self,
16330        _: &GoToImplementation,
16331        window: &mut Window,
16332        cx: &mut Context<Self>,
16333    ) -> Task<Result<Navigated>> {
16334        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16335    }
16336
16337    pub fn go_to_implementation_split(
16338        &mut self,
16339        _: &GoToImplementationSplit,
16340        window: &mut Window,
16341        cx: &mut Context<Self>,
16342    ) -> Task<Result<Navigated>> {
16343        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16344    }
16345
16346    pub fn go_to_type_definition(
16347        &mut self,
16348        _: &GoToTypeDefinition,
16349        window: &mut Window,
16350        cx: &mut Context<Self>,
16351    ) -> Task<Result<Navigated>> {
16352        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16353    }
16354
16355    pub fn go_to_definition_split(
16356        &mut self,
16357        _: &GoToDefinitionSplit,
16358        window: &mut Window,
16359        cx: &mut Context<Self>,
16360    ) -> Task<Result<Navigated>> {
16361        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16362    }
16363
16364    pub fn go_to_type_definition_split(
16365        &mut self,
16366        _: &GoToTypeDefinitionSplit,
16367        window: &mut Window,
16368        cx: &mut Context<Self>,
16369    ) -> Task<Result<Navigated>> {
16370        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16371    }
16372
16373    fn go_to_definition_of_kind(
16374        &mut self,
16375        kind: GotoDefinitionKind,
16376        split: bool,
16377        window: &mut Window,
16378        cx: &mut Context<Self>,
16379    ) -> Task<Result<Navigated>> {
16380        let Some(provider) = self.semantics_provider.clone() else {
16381            return Task::ready(Ok(Navigated::No));
16382        };
16383        let head = self.selections.newest::<usize>(cx).head();
16384        let buffer = self.buffer.read(cx);
16385        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16386            return Task::ready(Ok(Navigated::No));
16387        };
16388        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16389            return Task::ready(Ok(Navigated::No));
16390        };
16391
16392        cx.spawn_in(window, async move |editor, cx| {
16393            let Some(definitions) = definitions.await? else {
16394                return Ok(Navigated::No);
16395            };
16396            let navigated = editor
16397                .update_in(cx, |editor, window, cx| {
16398                    editor.navigate_to_hover_links(
16399                        Some(kind),
16400                        definitions
16401                            .into_iter()
16402                            .filter(|location| {
16403                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16404                            })
16405                            .map(HoverLink::Text)
16406                            .collect::<Vec<_>>(),
16407                        split,
16408                        window,
16409                        cx,
16410                    )
16411                })?
16412                .await?;
16413            anyhow::Ok(navigated)
16414        })
16415    }
16416
16417    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16418        let selection = self.selections.newest_anchor();
16419        let head = selection.head();
16420        let tail = selection.tail();
16421
16422        let Some((buffer, start_position)) =
16423            self.buffer.read(cx).text_anchor_for_position(head, cx)
16424        else {
16425            return;
16426        };
16427
16428        let end_position = if head != tail {
16429            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16430                return;
16431            };
16432            Some(pos)
16433        } else {
16434            None
16435        };
16436
16437        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16438            let url = if let Some(end_pos) = end_position {
16439                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16440            } else {
16441                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16442            };
16443
16444            if let Some(url) = url {
16445                cx.update(|window, cx| {
16446                    if parse_zed_link(&url, cx).is_some() {
16447                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16448                    } else {
16449                        cx.open_url(&url);
16450                    }
16451                })?;
16452            }
16453
16454            anyhow::Ok(())
16455        });
16456
16457        url_finder.detach();
16458    }
16459
16460    pub fn open_selected_filename(
16461        &mut self,
16462        _: &OpenSelectedFilename,
16463        window: &mut Window,
16464        cx: &mut Context<Self>,
16465    ) {
16466        let Some(workspace) = self.workspace() else {
16467            return;
16468        };
16469
16470        let position = self.selections.newest_anchor().head();
16471
16472        let Some((buffer, buffer_position)) =
16473            self.buffer.read(cx).text_anchor_for_position(position, cx)
16474        else {
16475            return;
16476        };
16477
16478        let project = self.project.clone();
16479
16480        cx.spawn_in(window, async move |_, cx| {
16481            let result = find_file(&buffer, project, buffer_position, cx).await;
16482
16483            if let Some((_, path)) = result {
16484                workspace
16485                    .update_in(cx, |workspace, window, cx| {
16486                        workspace.open_resolved_path(path, window, cx)
16487                    })?
16488                    .await?;
16489            }
16490            anyhow::Ok(())
16491        })
16492        .detach();
16493    }
16494
16495    pub(crate) fn navigate_to_hover_links(
16496        &mut self,
16497        kind: Option<GotoDefinitionKind>,
16498        definitions: Vec<HoverLink>,
16499        split: bool,
16500        window: &mut Window,
16501        cx: &mut Context<Editor>,
16502    ) -> Task<Result<Navigated>> {
16503        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16504        let mut first_url_or_file = None;
16505        let definitions: Vec<_> = definitions
16506            .into_iter()
16507            .filter_map(|def| match def {
16508                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16509                HoverLink::InlayHint(lsp_location, server_id) => {
16510                    let computation =
16511                        self.compute_target_location(lsp_location, server_id, window, cx);
16512                    Some(cx.background_spawn(computation))
16513                }
16514                HoverLink::Url(url) => {
16515                    first_url_or_file = Some(Either::Left(url));
16516                    None
16517                }
16518                HoverLink::File(path) => {
16519                    first_url_or_file = Some(Either::Right(path));
16520                    None
16521                }
16522            })
16523            .collect();
16524
16525        let workspace = self.workspace();
16526
16527        cx.spawn_in(window, async move |editor, cx| {
16528            let locations: Vec<Location> = future::join_all(definitions)
16529                .await
16530                .into_iter()
16531                .filter_map(|location| location.transpose())
16532                .collect::<Result<_>>()
16533                .context("location tasks")?;
16534            let mut locations = cx.update(|_, cx| {
16535                locations
16536                    .into_iter()
16537                    .map(|location| {
16538                        let buffer = location.buffer.read(cx);
16539                        (location.buffer, location.range.to_point(buffer))
16540                    })
16541                    .into_group_map()
16542            })?;
16543            let mut num_locations = 0;
16544            for ranges in locations.values_mut() {
16545                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16546                ranges.dedup();
16547                num_locations += ranges.len();
16548            }
16549
16550            if num_locations > 1 {
16551                let Some(workspace) = workspace else {
16552                    return Ok(Navigated::No);
16553                };
16554
16555                let tab_kind = match kind {
16556                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16557                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16558                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16559                    Some(GotoDefinitionKind::Type) => "Types",
16560                };
16561                let title = editor
16562                    .update_in(cx, |_, _, cx| {
16563                        let target = locations
16564                            .iter()
16565                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16566                            .map(|(buffer, location)| {
16567                                buffer
16568                                    .read(cx)
16569                                    .text_for_range(location.clone())
16570                                    .collect::<String>()
16571                            })
16572                            .filter(|text| !text.contains('\n'))
16573                            .unique()
16574                            .take(3)
16575                            .join(", ");
16576                        if target.is_empty() {
16577                            tab_kind.to_owned()
16578                        } else {
16579                            format!("{tab_kind} for {target}")
16580                        }
16581                    })
16582                    .context("buffer title")?;
16583
16584                let opened = workspace
16585                    .update_in(cx, |workspace, window, cx| {
16586                        Self::open_locations_in_multibuffer(
16587                            workspace,
16588                            locations,
16589                            title,
16590                            split,
16591                            MultibufferSelectionMode::First,
16592                            window,
16593                            cx,
16594                        )
16595                    })
16596                    .is_ok();
16597
16598                anyhow::Ok(Navigated::from_bool(opened))
16599            } else if num_locations == 0 {
16600                // If there is one url or file, open it directly
16601                match first_url_or_file {
16602                    Some(Either::Left(url)) => {
16603                        cx.update(|_, cx| cx.open_url(&url))?;
16604                        Ok(Navigated::Yes)
16605                    }
16606                    Some(Either::Right(path)) => {
16607                        let Some(workspace) = workspace else {
16608                            return Ok(Navigated::No);
16609                        };
16610
16611                        workspace
16612                            .update_in(cx, |workspace, window, cx| {
16613                                workspace.open_resolved_path(path, window, cx)
16614                            })?
16615                            .await?;
16616                        Ok(Navigated::Yes)
16617                    }
16618                    None => Ok(Navigated::No),
16619                }
16620            } else {
16621                let Some(workspace) = workspace else {
16622                    return Ok(Navigated::No);
16623                };
16624
16625                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16626                let target_range = target_ranges.first().unwrap().clone();
16627
16628                editor.update_in(cx, |editor, window, cx| {
16629                    let range = target_range.to_point(target_buffer.read(cx));
16630                    let range = editor.range_for_match(&range);
16631                    let range = collapse_multiline_range(range);
16632
16633                    if !split
16634                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16635                    {
16636                        editor.go_to_singleton_buffer_range(range, window, cx);
16637                    } else {
16638                        let pane = workspace.read(cx).active_pane().clone();
16639                        window.defer(cx, move |window, cx| {
16640                            let target_editor: Entity<Self> =
16641                                workspace.update(cx, |workspace, cx| {
16642                                    let pane = if split {
16643                                        workspace.adjacent_pane(window, cx)
16644                                    } else {
16645                                        workspace.active_pane().clone()
16646                                    };
16647
16648                                    workspace.open_project_item(
16649                                        pane,
16650                                        target_buffer.clone(),
16651                                        true,
16652                                        true,
16653                                        window,
16654                                        cx,
16655                                    )
16656                                });
16657                            target_editor.update(cx, |target_editor, cx| {
16658                                // When selecting a definition in a different buffer, disable the nav history
16659                                // to avoid creating a history entry at the previous cursor location.
16660                                pane.update(cx, |pane, _| pane.disable_history());
16661                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16662                                pane.update(cx, |pane, _| pane.enable_history());
16663                            });
16664                        });
16665                    }
16666                    Navigated::Yes
16667                })
16668            }
16669        })
16670    }
16671
16672    fn compute_target_location(
16673        &self,
16674        lsp_location: lsp::Location,
16675        server_id: LanguageServerId,
16676        window: &mut Window,
16677        cx: &mut Context<Self>,
16678    ) -> Task<anyhow::Result<Option<Location>>> {
16679        let Some(project) = self.project.clone() else {
16680            return Task::ready(Ok(None));
16681        };
16682
16683        cx.spawn_in(window, async move |editor, cx| {
16684            let location_task = editor.update(cx, |_, cx| {
16685                project.update(cx, |project, cx| {
16686                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16687                })
16688            })?;
16689            let location = Some({
16690                let target_buffer_handle = location_task.await.context("open local buffer")?;
16691                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16692                    let target_start = target_buffer
16693                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16694                    let target_end = target_buffer
16695                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16696                    target_buffer.anchor_after(target_start)
16697                        ..target_buffer.anchor_before(target_end)
16698                })?;
16699                Location {
16700                    buffer: target_buffer_handle,
16701                    range,
16702                }
16703            });
16704            Ok(location)
16705        })
16706    }
16707
16708    pub fn find_all_references(
16709        &mut self,
16710        _: &FindAllReferences,
16711        window: &mut Window,
16712        cx: &mut Context<Self>,
16713    ) -> Option<Task<Result<Navigated>>> {
16714        let selection = self.selections.newest::<usize>(cx);
16715        let multi_buffer = self.buffer.read(cx);
16716        let head = selection.head();
16717
16718        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16719        let head_anchor = multi_buffer_snapshot.anchor_at(
16720            head,
16721            if head < selection.tail() {
16722                Bias::Right
16723            } else {
16724                Bias::Left
16725            },
16726        );
16727
16728        match self
16729            .find_all_references_task_sources
16730            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16731        {
16732            Ok(_) => {
16733                log::info!(
16734                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16735                );
16736                return None;
16737            }
16738            Err(i) => {
16739                self.find_all_references_task_sources.insert(i, head_anchor);
16740            }
16741        }
16742
16743        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16744        let workspace = self.workspace()?;
16745        let project = workspace.read(cx).project().clone();
16746        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16747        Some(cx.spawn_in(window, async move |editor, cx| {
16748            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16749                if let Ok(i) = editor
16750                    .find_all_references_task_sources
16751                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16752                {
16753                    editor.find_all_references_task_sources.remove(i);
16754                }
16755            });
16756
16757            let Some(locations) = references.await? else {
16758                return anyhow::Ok(Navigated::No);
16759            };
16760            let mut locations = cx.update(|_, cx| {
16761                locations
16762                    .into_iter()
16763                    .map(|location| {
16764                        let buffer = location.buffer.read(cx);
16765                        (location.buffer, location.range.to_point(buffer))
16766                    })
16767                    .into_group_map()
16768            })?;
16769            if locations.is_empty() {
16770                return anyhow::Ok(Navigated::No);
16771            }
16772            for ranges in locations.values_mut() {
16773                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16774                ranges.dedup();
16775            }
16776
16777            workspace.update_in(cx, |workspace, window, cx| {
16778                let target = locations
16779                    .iter()
16780                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16781                    .map(|(buffer, location)| {
16782                        buffer
16783                            .read(cx)
16784                            .text_for_range(location.clone())
16785                            .collect::<String>()
16786                    })
16787                    .filter(|text| !text.contains('\n'))
16788                    .unique()
16789                    .take(3)
16790                    .join(", ");
16791                let title = if target.is_empty() {
16792                    "References".to_owned()
16793                } else {
16794                    format!("References to {target}")
16795                };
16796                Self::open_locations_in_multibuffer(
16797                    workspace,
16798                    locations,
16799                    title,
16800                    false,
16801                    MultibufferSelectionMode::First,
16802                    window,
16803                    cx,
16804                );
16805                Navigated::Yes
16806            })
16807        }))
16808    }
16809
16810    /// Opens a multibuffer with the given project locations in it
16811    pub fn open_locations_in_multibuffer(
16812        workspace: &mut Workspace,
16813        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16814        title: String,
16815        split: bool,
16816        multibuffer_selection_mode: MultibufferSelectionMode,
16817        window: &mut Window,
16818        cx: &mut Context<Workspace>,
16819    ) {
16820        if locations.is_empty() {
16821            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16822            return;
16823        }
16824
16825        let capability = workspace.project().read(cx).capability();
16826        let mut ranges = <Vec<Range<Anchor>>>::new();
16827
16828        // a key to find existing multibuffer editors with the same set of locations
16829        // to prevent us from opening more and more multibuffer tabs for searches and the like
16830        let mut key = (title.clone(), vec![]);
16831        let excerpt_buffer = cx.new(|cx| {
16832            let key = &mut key.1;
16833            let mut multibuffer = MultiBuffer::new(capability);
16834            for (buffer, mut ranges_for_buffer) in locations {
16835                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16836                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16837                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16838                    PathKey::for_buffer(&buffer, cx),
16839                    buffer.clone(),
16840                    ranges_for_buffer,
16841                    multibuffer_context_lines(cx),
16842                    cx,
16843                );
16844                ranges.extend(new_ranges)
16845            }
16846
16847            multibuffer.with_title(title)
16848        });
16849        let existing = workspace.active_pane().update(cx, |pane, cx| {
16850            pane.items()
16851                .filter_map(|item| item.downcast::<Editor>())
16852                .find(|editor| {
16853                    editor
16854                        .read(cx)
16855                        .lookup_key
16856                        .as_ref()
16857                        .and_then(|it| {
16858                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16859                        })
16860                        .is_some_and(|it| *it == key)
16861                })
16862        });
16863        let editor = existing.unwrap_or_else(|| {
16864            cx.new(|cx| {
16865                let mut editor = Editor::for_multibuffer(
16866                    excerpt_buffer,
16867                    Some(workspace.project().clone()),
16868                    window,
16869                    cx,
16870                );
16871                editor.lookup_key = Some(Box::new(key));
16872                editor
16873            })
16874        });
16875        editor.update(cx, |editor, cx| {
16876            match multibuffer_selection_mode {
16877                MultibufferSelectionMode::First => {
16878                    if let Some(first_range) = ranges.first() {
16879                        editor.change_selections(
16880                            SelectionEffects::no_scroll(),
16881                            window,
16882                            cx,
16883                            |selections| {
16884                                selections.clear_disjoint();
16885                                selections
16886                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16887                            },
16888                        );
16889                    }
16890                    editor.highlight_background::<Self>(
16891                        &ranges,
16892                        |theme| theme.colors().editor_highlighted_line_background,
16893                        cx,
16894                    );
16895                }
16896                MultibufferSelectionMode::All => {
16897                    editor.change_selections(
16898                        SelectionEffects::no_scroll(),
16899                        window,
16900                        cx,
16901                        |selections| {
16902                            selections.clear_disjoint();
16903                            selections.select_anchor_ranges(ranges);
16904                        },
16905                    );
16906                }
16907            }
16908            editor.register_buffers_with_language_servers(cx);
16909        });
16910
16911        let item = Box::new(editor);
16912        let item_id = item.item_id();
16913
16914        if split {
16915            let pane = workspace.adjacent_pane(window, cx);
16916            workspace.add_item(pane, item, None, true, true, window, cx);
16917        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16918            let (preview_item_id, preview_item_idx) =
16919                workspace.active_pane().read_with(cx, |pane, _| {
16920                    (pane.preview_item_id(), pane.preview_item_idx())
16921                });
16922
16923            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16924
16925            if let Some(preview_item_id) = preview_item_id {
16926                workspace.active_pane().update(cx, |pane, cx| {
16927                    pane.remove_item(preview_item_id, false, false, window, cx);
16928                });
16929            }
16930        } else {
16931            workspace.add_item_to_active_pane(item, None, true, window, cx);
16932        }
16933        workspace.active_pane().update(cx, |pane, cx| {
16934            pane.set_preview_item_id(Some(item_id), cx);
16935        });
16936    }
16937
16938    pub fn rename(
16939        &mut self,
16940        _: &Rename,
16941        window: &mut Window,
16942        cx: &mut Context<Self>,
16943    ) -> Option<Task<Result<()>>> {
16944        use language::ToOffset as _;
16945
16946        let provider = self.semantics_provider.clone()?;
16947        let selection = self.selections.newest_anchor().clone();
16948        let (cursor_buffer, cursor_buffer_position) = self
16949            .buffer
16950            .read(cx)
16951            .text_anchor_for_position(selection.head(), cx)?;
16952        let (tail_buffer, cursor_buffer_position_end) = self
16953            .buffer
16954            .read(cx)
16955            .text_anchor_for_position(selection.tail(), cx)?;
16956        if tail_buffer != cursor_buffer {
16957            return None;
16958        }
16959
16960        let snapshot = cursor_buffer.read(cx).snapshot();
16961        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16962        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16963        let prepare_rename = provider
16964            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16965            .unwrap_or_else(|| Task::ready(Ok(None)));
16966        drop(snapshot);
16967
16968        Some(cx.spawn_in(window, async move |this, cx| {
16969            let rename_range = if let Some(range) = prepare_rename.await? {
16970                Some(range)
16971            } else {
16972                this.update(cx, |this, cx| {
16973                    let buffer = this.buffer.read(cx).snapshot(cx);
16974                    let mut buffer_highlights = this
16975                        .document_highlights_for_position(selection.head(), &buffer)
16976                        .filter(|highlight| {
16977                            highlight.start.excerpt_id == selection.head().excerpt_id
16978                                && highlight.end.excerpt_id == selection.head().excerpt_id
16979                        });
16980                    buffer_highlights
16981                        .next()
16982                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16983                })?
16984            };
16985            if let Some(rename_range) = rename_range {
16986                this.update_in(cx, |this, window, cx| {
16987                    let snapshot = cursor_buffer.read(cx).snapshot();
16988                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16989                    let cursor_offset_in_rename_range =
16990                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16991                    let cursor_offset_in_rename_range_end =
16992                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16993
16994                    this.take_rename(false, window, cx);
16995                    let buffer = this.buffer.read(cx).read(cx);
16996                    let cursor_offset = selection.head().to_offset(&buffer);
16997                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16998                    let rename_end = rename_start + rename_buffer_range.len();
16999                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17000                    let mut old_highlight_id = None;
17001                    let old_name: Arc<str> = buffer
17002                        .chunks(rename_start..rename_end, true)
17003                        .map(|chunk| {
17004                            if old_highlight_id.is_none() {
17005                                old_highlight_id = chunk.syntax_highlight_id;
17006                            }
17007                            chunk.text
17008                        })
17009                        .collect::<String>()
17010                        .into();
17011
17012                    drop(buffer);
17013
17014                    // Position the selection in the rename editor so that it matches the current selection.
17015                    this.show_local_selections = false;
17016                    let rename_editor = cx.new(|cx| {
17017                        let mut editor = Editor::single_line(window, cx);
17018                        editor.buffer.update(cx, |buffer, cx| {
17019                            buffer.edit([(0..0, old_name.clone())], None, cx)
17020                        });
17021                        let rename_selection_range = match cursor_offset_in_rename_range
17022                            .cmp(&cursor_offset_in_rename_range_end)
17023                        {
17024                            Ordering::Equal => {
17025                                editor.select_all(&SelectAll, window, cx);
17026                                return editor;
17027                            }
17028                            Ordering::Less => {
17029                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17030                            }
17031                            Ordering::Greater => {
17032                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17033                            }
17034                        };
17035                        if rename_selection_range.end > old_name.len() {
17036                            editor.select_all(&SelectAll, window, cx);
17037                        } else {
17038                            editor.change_selections(Default::default(), window, cx, |s| {
17039                                s.select_ranges([rename_selection_range]);
17040                            });
17041                        }
17042                        editor
17043                    });
17044                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17045                        if e == &EditorEvent::Focused {
17046                            cx.emit(EditorEvent::FocusedIn)
17047                        }
17048                    })
17049                    .detach();
17050
17051                    let write_highlights =
17052                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17053                    let read_highlights =
17054                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17055                    let ranges = write_highlights
17056                        .iter()
17057                        .flat_map(|(_, ranges)| ranges.iter())
17058                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17059                        .cloned()
17060                        .collect();
17061
17062                    this.highlight_text::<Rename>(
17063                        ranges,
17064                        HighlightStyle {
17065                            fade_out: Some(0.6),
17066                            ..Default::default()
17067                        },
17068                        cx,
17069                    );
17070                    let rename_focus_handle = rename_editor.focus_handle(cx);
17071                    window.focus(&rename_focus_handle);
17072                    let block_id = this.insert_blocks(
17073                        [BlockProperties {
17074                            style: BlockStyle::Flex,
17075                            placement: BlockPlacement::Below(range.start),
17076                            height: Some(1),
17077                            render: Arc::new({
17078                                let rename_editor = rename_editor.clone();
17079                                move |cx: &mut BlockContext| {
17080                                    let mut text_style = cx.editor_style.text.clone();
17081                                    if let Some(highlight_style) = old_highlight_id
17082                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17083                                    {
17084                                        text_style = text_style.highlight(highlight_style);
17085                                    }
17086                                    div()
17087                                        .block_mouse_except_scroll()
17088                                        .pl(cx.anchor_x)
17089                                        .child(EditorElement::new(
17090                                            &rename_editor,
17091                                            EditorStyle {
17092                                                background: cx.theme().system().transparent,
17093                                                local_player: cx.editor_style.local_player,
17094                                                text: text_style,
17095                                                scrollbar_width: cx.editor_style.scrollbar_width,
17096                                                syntax: cx.editor_style.syntax.clone(),
17097                                                status: cx.editor_style.status.clone(),
17098                                                inlay_hints_style: HighlightStyle {
17099                                                    font_weight: Some(FontWeight::BOLD),
17100                                                    ..make_inlay_hints_style(cx.app)
17101                                                },
17102                                                edit_prediction_styles: make_suggestion_styles(
17103                                                    cx.app,
17104                                                ),
17105                                                ..EditorStyle::default()
17106                                            },
17107                                        ))
17108                                        .into_any_element()
17109                                }
17110                            }),
17111                            priority: 0,
17112                        }],
17113                        Some(Autoscroll::fit()),
17114                        cx,
17115                    )[0];
17116                    this.pending_rename = Some(RenameState {
17117                        range,
17118                        old_name,
17119                        editor: rename_editor,
17120                        block_id,
17121                    });
17122                })?;
17123            }
17124
17125            Ok(())
17126        }))
17127    }
17128
17129    pub fn confirm_rename(
17130        &mut self,
17131        _: &ConfirmRename,
17132        window: &mut Window,
17133        cx: &mut Context<Self>,
17134    ) -> Option<Task<Result<()>>> {
17135        let rename = self.take_rename(false, window, cx)?;
17136        let workspace = self.workspace()?.downgrade();
17137        let (buffer, start) = self
17138            .buffer
17139            .read(cx)
17140            .text_anchor_for_position(rename.range.start, cx)?;
17141        let (end_buffer, _) = self
17142            .buffer
17143            .read(cx)
17144            .text_anchor_for_position(rename.range.end, cx)?;
17145        if buffer != end_buffer {
17146            return None;
17147        }
17148
17149        let old_name = rename.old_name;
17150        let new_name = rename.editor.read(cx).text(cx);
17151
17152        let rename = self.semantics_provider.as_ref()?.perform_rename(
17153            &buffer,
17154            start,
17155            new_name.clone(),
17156            cx,
17157        )?;
17158
17159        Some(cx.spawn_in(window, async move |editor, cx| {
17160            let project_transaction = rename.await?;
17161            Self::open_project_transaction(
17162                &editor,
17163                workspace,
17164                project_transaction,
17165                format!("Rename: {}{}", old_name, new_name),
17166                cx,
17167            )
17168            .await?;
17169
17170            editor.update(cx, |editor, cx| {
17171                editor.refresh_document_highlights(cx);
17172            })?;
17173            Ok(())
17174        }))
17175    }
17176
17177    fn take_rename(
17178        &mut self,
17179        moving_cursor: bool,
17180        window: &mut Window,
17181        cx: &mut Context<Self>,
17182    ) -> Option<RenameState> {
17183        let rename = self.pending_rename.take()?;
17184        if rename.editor.focus_handle(cx).is_focused(window) {
17185            window.focus(&self.focus_handle);
17186        }
17187
17188        self.remove_blocks(
17189            [rename.block_id].into_iter().collect(),
17190            Some(Autoscroll::fit()),
17191            cx,
17192        );
17193        self.clear_highlights::<Rename>(cx);
17194        self.show_local_selections = true;
17195
17196        if moving_cursor {
17197            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17198                editor.selections.newest::<usize>(cx).head()
17199            });
17200
17201            // Update the selection to match the position of the selection inside
17202            // the rename editor.
17203            let snapshot = self.buffer.read(cx).read(cx);
17204            let rename_range = rename.range.to_offset(&snapshot);
17205            let cursor_in_editor = snapshot
17206                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17207                .min(rename_range.end);
17208            drop(snapshot);
17209
17210            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17211                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17212            });
17213        } else {
17214            self.refresh_document_highlights(cx);
17215        }
17216
17217        Some(rename)
17218    }
17219
17220    pub fn pending_rename(&self) -> Option<&RenameState> {
17221        self.pending_rename.as_ref()
17222    }
17223
17224    fn format(
17225        &mut self,
17226        _: &Format,
17227        window: &mut Window,
17228        cx: &mut Context<Self>,
17229    ) -> Option<Task<Result<()>>> {
17230        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17231
17232        let project = match &self.project {
17233            Some(project) => project.clone(),
17234            None => return None,
17235        };
17236
17237        Some(self.perform_format(
17238            project,
17239            FormatTrigger::Manual,
17240            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17241            window,
17242            cx,
17243        ))
17244    }
17245
17246    fn format_selections(
17247        &mut self,
17248        _: &FormatSelections,
17249        window: &mut Window,
17250        cx: &mut Context<Self>,
17251    ) -> Option<Task<Result<()>>> {
17252        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17253
17254        let project = match &self.project {
17255            Some(project) => project.clone(),
17256            None => return None,
17257        };
17258
17259        let ranges = self
17260            .selections
17261            .all_adjusted(cx)
17262            .into_iter()
17263            .map(|selection| selection.range())
17264            .collect_vec();
17265
17266        Some(self.perform_format(
17267            project,
17268            FormatTrigger::Manual,
17269            FormatTarget::Ranges(ranges),
17270            window,
17271            cx,
17272        ))
17273    }
17274
17275    fn perform_format(
17276        &mut self,
17277        project: Entity<Project>,
17278        trigger: FormatTrigger,
17279        target: FormatTarget,
17280        window: &mut Window,
17281        cx: &mut Context<Self>,
17282    ) -> Task<Result<()>> {
17283        let buffer = self.buffer.clone();
17284        let (buffers, target) = match target {
17285            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17286            FormatTarget::Ranges(selection_ranges) => {
17287                let multi_buffer = buffer.read(cx);
17288                let snapshot = multi_buffer.read(cx);
17289                let mut buffers = HashSet::default();
17290                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17291                    BTreeMap::new();
17292                for selection_range in selection_ranges {
17293                    for (buffer, buffer_range, _) in
17294                        snapshot.range_to_buffer_ranges(selection_range)
17295                    {
17296                        let buffer_id = buffer.remote_id();
17297                        let start = buffer.anchor_before(buffer_range.start);
17298                        let end = buffer.anchor_after(buffer_range.end);
17299                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17300                        buffer_id_to_ranges
17301                            .entry(buffer_id)
17302                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17303                            .or_insert_with(|| vec![start..end]);
17304                    }
17305                }
17306                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17307            }
17308        };
17309
17310        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17311        let selections_prev = transaction_id_prev
17312            .and_then(|transaction_id_prev| {
17313                // default to selections as they were after the last edit, if we have them,
17314                // instead of how they are now.
17315                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17316                // will take you back to where you made the last edit, instead of staying where you scrolled
17317                self.selection_history
17318                    .transaction(transaction_id_prev)
17319                    .map(|t| t.0.clone())
17320            })
17321            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17322
17323        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17324        let format = project.update(cx, |project, cx| {
17325            project.format(buffers, target, true, trigger, cx)
17326        });
17327
17328        cx.spawn_in(window, async move |editor, cx| {
17329            let transaction = futures::select_biased! {
17330                transaction = format.log_err().fuse() => transaction,
17331                () = timeout => {
17332                    log::warn!("timed out waiting for formatting");
17333                    None
17334                }
17335            };
17336
17337            buffer
17338                .update(cx, |buffer, cx| {
17339                    if let Some(transaction) = transaction
17340                        && !buffer.is_singleton()
17341                    {
17342                        buffer.push_transaction(&transaction.0, cx);
17343                    }
17344                    cx.notify();
17345                })
17346                .ok();
17347
17348            if let Some(transaction_id_now) =
17349                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17350            {
17351                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17352                if has_new_transaction {
17353                    _ = editor.update(cx, |editor, _| {
17354                        editor
17355                            .selection_history
17356                            .insert_transaction(transaction_id_now, selections_prev);
17357                    });
17358                }
17359            }
17360
17361            Ok(())
17362        })
17363    }
17364
17365    fn organize_imports(
17366        &mut self,
17367        _: &OrganizeImports,
17368        window: &mut Window,
17369        cx: &mut Context<Self>,
17370    ) -> Option<Task<Result<()>>> {
17371        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17372        let project = match &self.project {
17373            Some(project) => project.clone(),
17374            None => return None,
17375        };
17376        Some(self.perform_code_action_kind(
17377            project,
17378            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17379            window,
17380            cx,
17381        ))
17382    }
17383
17384    fn perform_code_action_kind(
17385        &mut self,
17386        project: Entity<Project>,
17387        kind: CodeActionKind,
17388        window: &mut Window,
17389        cx: &mut Context<Self>,
17390    ) -> Task<Result<()>> {
17391        let buffer = self.buffer.clone();
17392        let buffers = buffer.read(cx).all_buffers();
17393        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17394        let apply_action = project.update(cx, |project, cx| {
17395            project.apply_code_action_kind(buffers, kind, true, cx)
17396        });
17397        cx.spawn_in(window, async move |_, cx| {
17398            let transaction = futures::select_biased! {
17399                () = timeout => {
17400                    log::warn!("timed out waiting for executing code action");
17401                    None
17402                }
17403                transaction = apply_action.log_err().fuse() => transaction,
17404            };
17405            buffer
17406                .update(cx, |buffer, cx| {
17407                    // check if we need this
17408                    if let Some(transaction) = transaction
17409                        && !buffer.is_singleton()
17410                    {
17411                        buffer.push_transaction(&transaction.0, cx);
17412                    }
17413                    cx.notify();
17414                })
17415                .ok();
17416            Ok(())
17417        })
17418    }
17419
17420    pub fn restart_language_server(
17421        &mut self,
17422        _: &RestartLanguageServer,
17423        _: &mut Window,
17424        cx: &mut Context<Self>,
17425    ) {
17426        if let Some(project) = self.project.clone() {
17427            self.buffer.update(cx, |multi_buffer, cx| {
17428                project.update(cx, |project, cx| {
17429                    project.restart_language_servers_for_buffers(
17430                        multi_buffer.all_buffers().into_iter().collect(),
17431                        HashSet::default(),
17432                        cx,
17433                    );
17434                });
17435            })
17436        }
17437    }
17438
17439    pub fn stop_language_server(
17440        &mut self,
17441        _: &StopLanguageServer,
17442        _: &mut Window,
17443        cx: &mut Context<Self>,
17444    ) {
17445        if let Some(project) = self.project.clone() {
17446            self.buffer.update(cx, |multi_buffer, cx| {
17447                project.update(cx, |project, cx| {
17448                    project.stop_language_servers_for_buffers(
17449                        multi_buffer.all_buffers().into_iter().collect(),
17450                        HashSet::default(),
17451                        cx,
17452                    );
17453                    cx.emit(project::Event::RefreshInlayHints);
17454                });
17455            });
17456        }
17457    }
17458
17459    fn cancel_language_server_work(
17460        workspace: &mut Workspace,
17461        _: &actions::CancelLanguageServerWork,
17462        _: &mut Window,
17463        cx: &mut Context<Workspace>,
17464    ) {
17465        let project = workspace.project();
17466        let buffers = workspace
17467            .active_item(cx)
17468            .and_then(|item| item.act_as::<Editor>(cx))
17469            .map_or(HashSet::default(), |editor| {
17470                editor.read(cx).buffer.read(cx).all_buffers()
17471            });
17472        project.update(cx, |project, cx| {
17473            project.cancel_language_server_work_for_buffers(buffers, cx);
17474        });
17475    }
17476
17477    fn show_character_palette(
17478        &mut self,
17479        _: &ShowCharacterPalette,
17480        window: &mut Window,
17481        _: &mut Context<Self>,
17482    ) {
17483        window.show_character_palette();
17484    }
17485
17486    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17487        if !self.diagnostics_enabled() {
17488            return;
17489        }
17490
17491        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17492            let buffer = self.buffer.read(cx).snapshot(cx);
17493            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17494            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17495            let is_valid = buffer
17496                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17497                .any(|entry| {
17498                    entry.diagnostic.is_primary
17499                        && !entry.range.is_empty()
17500                        && entry.range.start == primary_range_start
17501                        && entry.diagnostic.message == active_diagnostics.active_message
17502                });
17503
17504            if !is_valid {
17505                self.dismiss_diagnostics(cx);
17506            }
17507        }
17508    }
17509
17510    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17511        match &self.active_diagnostics {
17512            ActiveDiagnostic::Group(group) => Some(group),
17513            _ => None,
17514        }
17515    }
17516
17517    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17518        if !self.diagnostics_enabled() {
17519            return;
17520        }
17521        self.dismiss_diagnostics(cx);
17522        self.active_diagnostics = ActiveDiagnostic::All;
17523    }
17524
17525    fn activate_diagnostics(
17526        &mut self,
17527        buffer_id: BufferId,
17528        diagnostic: DiagnosticEntryRef<'_, usize>,
17529        window: &mut Window,
17530        cx: &mut Context<Self>,
17531    ) {
17532        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17533            return;
17534        }
17535        self.dismiss_diagnostics(cx);
17536        let snapshot = self.snapshot(window, cx);
17537        let buffer = self.buffer.read(cx).snapshot(cx);
17538        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17539            return;
17540        };
17541
17542        let diagnostic_group = buffer
17543            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17544            .collect::<Vec<_>>();
17545
17546        let blocks =
17547            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17548
17549        let blocks = self.display_map.update(cx, |display_map, cx| {
17550            display_map.insert_blocks(blocks, cx).into_iter().collect()
17551        });
17552        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17553            active_range: buffer.anchor_before(diagnostic.range.start)
17554                ..buffer.anchor_after(diagnostic.range.end),
17555            active_message: diagnostic.diagnostic.message.clone(),
17556            group_id: diagnostic.diagnostic.group_id,
17557            blocks,
17558        });
17559        cx.notify();
17560    }
17561
17562    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17563        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17564            return;
17565        };
17566
17567        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17568        if let ActiveDiagnostic::Group(group) = prev {
17569            self.display_map.update(cx, |display_map, cx| {
17570                display_map.remove_blocks(group.blocks, cx);
17571            });
17572            cx.notify();
17573        }
17574    }
17575
17576    /// Disable inline diagnostics rendering for this editor.
17577    pub fn disable_inline_diagnostics(&mut self) {
17578        self.inline_diagnostics_enabled = false;
17579        self.inline_diagnostics_update = Task::ready(());
17580        self.inline_diagnostics.clear();
17581    }
17582
17583    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17584        self.diagnostics_enabled = false;
17585        self.dismiss_diagnostics(cx);
17586        self.inline_diagnostics_update = Task::ready(());
17587        self.inline_diagnostics.clear();
17588    }
17589
17590    pub fn disable_word_completions(&mut self) {
17591        self.word_completions_enabled = false;
17592    }
17593
17594    pub fn diagnostics_enabled(&self) -> bool {
17595        self.diagnostics_enabled && self.mode.is_full()
17596    }
17597
17598    pub fn inline_diagnostics_enabled(&self) -> bool {
17599        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17600    }
17601
17602    pub fn show_inline_diagnostics(&self) -> bool {
17603        self.show_inline_diagnostics
17604    }
17605
17606    pub fn toggle_inline_diagnostics(
17607        &mut self,
17608        _: &ToggleInlineDiagnostics,
17609        window: &mut Window,
17610        cx: &mut Context<Editor>,
17611    ) {
17612        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17613        self.refresh_inline_diagnostics(false, window, cx);
17614    }
17615
17616    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17617        self.diagnostics_max_severity = severity;
17618        self.display_map.update(cx, |display_map, _| {
17619            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17620        });
17621    }
17622
17623    pub fn toggle_diagnostics(
17624        &mut self,
17625        _: &ToggleDiagnostics,
17626        window: &mut Window,
17627        cx: &mut Context<Editor>,
17628    ) {
17629        if !self.diagnostics_enabled() {
17630            return;
17631        }
17632
17633        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17634            EditorSettings::get_global(cx)
17635                .diagnostics_max_severity
17636                .filter(|severity| severity != &DiagnosticSeverity::Off)
17637                .unwrap_or(DiagnosticSeverity::Hint)
17638        } else {
17639            DiagnosticSeverity::Off
17640        };
17641        self.set_max_diagnostics_severity(new_severity, cx);
17642        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17643            self.active_diagnostics = ActiveDiagnostic::None;
17644            self.inline_diagnostics_update = Task::ready(());
17645            self.inline_diagnostics.clear();
17646        } else {
17647            self.refresh_inline_diagnostics(false, window, cx);
17648        }
17649
17650        cx.notify();
17651    }
17652
17653    pub fn toggle_minimap(
17654        &mut self,
17655        _: &ToggleMinimap,
17656        window: &mut Window,
17657        cx: &mut Context<Editor>,
17658    ) {
17659        if self.supports_minimap(cx) {
17660            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17661        }
17662    }
17663
17664    fn refresh_inline_diagnostics(
17665        &mut self,
17666        debounce: bool,
17667        window: &mut Window,
17668        cx: &mut Context<Self>,
17669    ) {
17670        let max_severity = ProjectSettings::get_global(cx)
17671            .diagnostics
17672            .inline
17673            .max_severity
17674            .unwrap_or(self.diagnostics_max_severity);
17675
17676        if !self.inline_diagnostics_enabled()
17677            || !self.show_inline_diagnostics
17678            || max_severity == DiagnosticSeverity::Off
17679        {
17680            self.inline_diagnostics_update = Task::ready(());
17681            self.inline_diagnostics.clear();
17682            return;
17683        }
17684
17685        let debounce_ms = ProjectSettings::get_global(cx)
17686            .diagnostics
17687            .inline
17688            .update_debounce_ms;
17689        let debounce = if debounce && debounce_ms > 0 {
17690            Some(Duration::from_millis(debounce_ms))
17691        } else {
17692            None
17693        };
17694        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17695            if let Some(debounce) = debounce {
17696                cx.background_executor().timer(debounce).await;
17697            }
17698            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17699                editor
17700                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17701                    .ok()
17702            }) else {
17703                return;
17704            };
17705
17706            let new_inline_diagnostics = cx
17707                .background_spawn(async move {
17708                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17709                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17710                        let message = diagnostic_entry
17711                            .diagnostic
17712                            .message
17713                            .split_once('\n')
17714                            .map(|(line, _)| line)
17715                            .map(SharedString::new)
17716                            .unwrap_or_else(|| {
17717                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17718                            });
17719                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17720                        let (Ok(i) | Err(i)) = inline_diagnostics
17721                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17722                        inline_diagnostics.insert(
17723                            i,
17724                            (
17725                                start_anchor,
17726                                InlineDiagnostic {
17727                                    message,
17728                                    group_id: diagnostic_entry.diagnostic.group_id,
17729                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17730                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17731                                    severity: diagnostic_entry.diagnostic.severity,
17732                                },
17733                            ),
17734                        );
17735                    }
17736                    inline_diagnostics
17737                })
17738                .await;
17739
17740            editor
17741                .update(cx, |editor, cx| {
17742                    editor.inline_diagnostics = new_inline_diagnostics;
17743                    cx.notify();
17744                })
17745                .ok();
17746        });
17747    }
17748
17749    fn pull_diagnostics(
17750        &mut self,
17751        buffer_id: Option<BufferId>,
17752        window: &Window,
17753        cx: &mut Context<Self>,
17754    ) -> Option<()> {
17755        if !self.mode().is_full() {
17756            return None;
17757        }
17758        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17759            .diagnostics
17760            .lsp_pull_diagnostics;
17761        if !pull_diagnostics_settings.enabled {
17762            return None;
17763        }
17764        let project = self.project()?.downgrade();
17765        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17766        let mut buffers = self.buffer.read(cx).all_buffers();
17767        if let Some(buffer_id) = buffer_id {
17768            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17769        }
17770
17771        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17772            cx.background_executor().timer(debounce).await;
17773
17774            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17775                buffers
17776                    .into_iter()
17777                    .filter_map(|buffer| {
17778                        project
17779                            .update(cx, |project, cx| {
17780                                project.lsp_store().update(cx, |lsp_store, cx| {
17781                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17782                                })
17783                            })
17784                            .ok()
17785                    })
17786                    .collect::<FuturesUnordered<_>>()
17787            }) else {
17788                return;
17789            };
17790
17791            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17792                match pull_task {
17793                    Ok(()) => {
17794                        if editor
17795                            .update_in(cx, |editor, window, cx| {
17796                                editor.update_diagnostics_state(window, cx);
17797                            })
17798                            .is_err()
17799                        {
17800                            return;
17801                        }
17802                    }
17803                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17804                }
17805            }
17806        });
17807
17808        Some(())
17809    }
17810
17811    pub fn set_selections_from_remote(
17812        &mut self,
17813        selections: Vec<Selection<Anchor>>,
17814        pending_selection: Option<Selection<Anchor>>,
17815        window: &mut Window,
17816        cx: &mut Context<Self>,
17817    ) {
17818        let old_cursor_position = self.selections.newest_anchor().head();
17819        self.selections.change_with(cx, |s| {
17820            s.select_anchors(selections);
17821            if let Some(pending_selection) = pending_selection {
17822                s.set_pending(pending_selection, SelectMode::Character);
17823            } else {
17824                s.clear_pending();
17825            }
17826        });
17827        self.selections_did_change(
17828            false,
17829            &old_cursor_position,
17830            SelectionEffects::default(),
17831            window,
17832            cx,
17833        );
17834    }
17835
17836    pub fn transact(
17837        &mut self,
17838        window: &mut Window,
17839        cx: &mut Context<Self>,
17840        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17841    ) -> Option<TransactionId> {
17842        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17843            this.start_transaction_at(Instant::now(), window, cx);
17844            update(this, window, cx);
17845            this.end_transaction_at(Instant::now(), cx)
17846        })
17847    }
17848
17849    pub fn start_transaction_at(
17850        &mut self,
17851        now: Instant,
17852        window: &mut Window,
17853        cx: &mut Context<Self>,
17854    ) -> Option<TransactionId> {
17855        self.end_selection(window, cx);
17856        if let Some(tx_id) = self
17857            .buffer
17858            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17859        {
17860            self.selection_history
17861                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17862            cx.emit(EditorEvent::TransactionBegun {
17863                transaction_id: tx_id,
17864            });
17865            Some(tx_id)
17866        } else {
17867            None
17868        }
17869    }
17870
17871    pub fn end_transaction_at(
17872        &mut self,
17873        now: Instant,
17874        cx: &mut Context<Self>,
17875    ) -> Option<TransactionId> {
17876        if let Some(transaction_id) = self
17877            .buffer
17878            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17879        {
17880            if let Some((_, end_selections)) =
17881                self.selection_history.transaction_mut(transaction_id)
17882            {
17883                *end_selections = Some(self.selections.disjoint_anchors_arc());
17884            } else {
17885                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17886            }
17887
17888            cx.emit(EditorEvent::Edited { transaction_id });
17889            Some(transaction_id)
17890        } else {
17891            None
17892        }
17893    }
17894
17895    pub fn modify_transaction_selection_history(
17896        &mut self,
17897        transaction_id: TransactionId,
17898        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17899    ) -> bool {
17900        self.selection_history
17901            .transaction_mut(transaction_id)
17902            .map(modify)
17903            .is_some()
17904    }
17905
17906    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17907        if self.selection_mark_mode {
17908            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17909                s.move_with(|_, sel| {
17910                    sel.collapse_to(sel.head(), SelectionGoal::None);
17911                });
17912            })
17913        }
17914        self.selection_mark_mode = true;
17915        cx.notify();
17916    }
17917
17918    pub fn swap_selection_ends(
17919        &mut self,
17920        _: &actions::SwapSelectionEnds,
17921        window: &mut Window,
17922        cx: &mut Context<Self>,
17923    ) {
17924        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17925            s.move_with(|_, sel| {
17926                if sel.start != sel.end {
17927                    sel.reversed = !sel.reversed
17928                }
17929            });
17930        });
17931        self.request_autoscroll(Autoscroll::newest(), cx);
17932        cx.notify();
17933    }
17934
17935    pub fn toggle_focus(
17936        workspace: &mut Workspace,
17937        _: &actions::ToggleFocus,
17938        window: &mut Window,
17939        cx: &mut Context<Workspace>,
17940    ) {
17941        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17942            return;
17943        };
17944        workspace.activate_item(&item, true, true, window, cx);
17945    }
17946
17947    pub fn toggle_fold(
17948        &mut self,
17949        _: &actions::ToggleFold,
17950        window: &mut Window,
17951        cx: &mut Context<Self>,
17952    ) {
17953        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
17954            let selection = self.selections.newest::<Point>(cx);
17955
17956            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17957            let range = if selection.is_empty() {
17958                let point = selection.head().to_display_point(&display_map);
17959                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17960                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17961                    .to_point(&display_map);
17962                start..end
17963            } else {
17964                selection.range()
17965            };
17966            if display_map.folds_in_range(range).next().is_some() {
17967                self.unfold_lines(&Default::default(), window, cx)
17968            } else {
17969                self.fold(&Default::default(), window, cx)
17970            }
17971        } else {
17972            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17973            let buffer_ids: HashSet<_> = self
17974                .selections
17975                .disjoint_anchor_ranges()
17976                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17977                .collect();
17978
17979            let should_unfold = buffer_ids
17980                .iter()
17981                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17982
17983            for buffer_id in buffer_ids {
17984                if should_unfold {
17985                    self.unfold_buffer(buffer_id, cx);
17986                } else {
17987                    self.fold_buffer(buffer_id, cx);
17988                }
17989            }
17990        }
17991    }
17992
17993    pub fn toggle_fold_recursive(
17994        &mut self,
17995        _: &actions::ToggleFoldRecursive,
17996        window: &mut Window,
17997        cx: &mut Context<Self>,
17998    ) {
17999        let selection = self.selections.newest::<Point>(cx);
18000
18001        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18002        let range = if selection.is_empty() {
18003            let point = selection.head().to_display_point(&display_map);
18004            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18005            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18006                .to_point(&display_map);
18007            start..end
18008        } else {
18009            selection.range()
18010        };
18011        if display_map.folds_in_range(range).next().is_some() {
18012            self.unfold_recursive(&Default::default(), window, cx)
18013        } else {
18014            self.fold_recursive(&Default::default(), window, cx)
18015        }
18016    }
18017
18018    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18019        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18020            let mut to_fold = Vec::new();
18021            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18022            let selections = self.selections.all_adjusted(cx);
18023
18024            for selection in selections {
18025                let range = selection.range().sorted();
18026                let buffer_start_row = range.start.row;
18027
18028                if range.start.row != range.end.row {
18029                    let mut found = false;
18030                    let mut row = range.start.row;
18031                    while row <= range.end.row {
18032                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18033                        {
18034                            found = true;
18035                            row = crease.range().end.row + 1;
18036                            to_fold.push(crease);
18037                        } else {
18038                            row += 1
18039                        }
18040                    }
18041                    if found {
18042                        continue;
18043                    }
18044                }
18045
18046                for row in (0..=range.start.row).rev() {
18047                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18048                        && crease.range().end.row >= buffer_start_row
18049                    {
18050                        to_fold.push(crease);
18051                        if row <= range.start.row {
18052                            break;
18053                        }
18054                    }
18055                }
18056            }
18057
18058            self.fold_creases(to_fold, true, window, cx);
18059        } else {
18060            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18061            let buffer_ids = self
18062                .selections
18063                .disjoint_anchor_ranges()
18064                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18065                .collect::<HashSet<_>>();
18066            for buffer_id in buffer_ids {
18067                self.fold_buffer(buffer_id, cx);
18068            }
18069        }
18070    }
18071
18072    pub fn toggle_fold_all(
18073        &mut self,
18074        _: &actions::ToggleFoldAll,
18075        window: &mut Window,
18076        cx: &mut Context<Self>,
18077    ) {
18078        if self.buffer.read(cx).is_singleton() {
18079            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18080            let has_folds = display_map
18081                .folds_in_range(0..display_map.buffer_snapshot.len())
18082                .next()
18083                .is_some();
18084
18085            if has_folds {
18086                self.unfold_all(&actions::UnfoldAll, window, cx);
18087            } else {
18088                self.fold_all(&actions::FoldAll, window, cx);
18089            }
18090        } else {
18091            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18092            let should_unfold = buffer_ids
18093                .iter()
18094                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18095
18096            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18097                editor
18098                    .update_in(cx, |editor, _, cx| {
18099                        for buffer_id in buffer_ids {
18100                            if should_unfold {
18101                                editor.unfold_buffer(buffer_id, cx);
18102                            } else {
18103                                editor.fold_buffer(buffer_id, cx);
18104                            }
18105                        }
18106                    })
18107                    .ok();
18108            });
18109        }
18110    }
18111
18112    fn fold_at_level(
18113        &mut self,
18114        fold_at: &FoldAtLevel,
18115        window: &mut Window,
18116        cx: &mut Context<Self>,
18117    ) {
18118        if !self.buffer.read(cx).is_singleton() {
18119            return;
18120        }
18121
18122        let fold_at_level = fold_at.0;
18123        let snapshot = self.buffer.read(cx).snapshot(cx);
18124        let mut to_fold = Vec::new();
18125        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18126
18127        let row_ranges_to_keep: Vec<Range<u32>> = self
18128            .selections
18129            .all::<Point>(cx)
18130            .into_iter()
18131            .map(|sel| sel.start.row..sel.end.row)
18132            .collect();
18133
18134        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18135            while start_row < end_row {
18136                match self
18137                    .snapshot(window, cx)
18138                    .crease_for_buffer_row(MultiBufferRow(start_row))
18139                {
18140                    Some(crease) => {
18141                        let nested_start_row = crease.range().start.row + 1;
18142                        let nested_end_row = crease.range().end.row;
18143
18144                        if current_level < fold_at_level {
18145                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18146                        } else if current_level == fold_at_level {
18147                            // Fold iff there is no selection completely contained within the fold region
18148                            if !row_ranges_to_keep.iter().any(|selection| {
18149                                selection.end >= nested_start_row
18150                                    && selection.start <= nested_end_row
18151                            }) {
18152                                to_fold.push(crease);
18153                            }
18154                        }
18155
18156                        start_row = nested_end_row + 1;
18157                    }
18158                    None => start_row += 1,
18159                }
18160            }
18161        }
18162
18163        self.fold_creases(to_fold, true, window, cx);
18164    }
18165
18166    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18167        if self.buffer.read(cx).is_singleton() {
18168            let mut fold_ranges = Vec::new();
18169            let snapshot = self.buffer.read(cx).snapshot(cx);
18170
18171            for row in 0..snapshot.max_row().0 {
18172                if let Some(foldable_range) = self
18173                    .snapshot(window, cx)
18174                    .crease_for_buffer_row(MultiBufferRow(row))
18175                {
18176                    fold_ranges.push(foldable_range);
18177                }
18178            }
18179
18180            self.fold_creases(fold_ranges, true, window, cx);
18181        } else {
18182            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18183                editor
18184                    .update_in(cx, |editor, _, cx| {
18185                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18186                            editor.fold_buffer(buffer_id, cx);
18187                        }
18188                    })
18189                    .ok();
18190            });
18191        }
18192    }
18193
18194    pub fn fold_function_bodies(
18195        &mut self,
18196        _: &actions::FoldFunctionBodies,
18197        window: &mut Window,
18198        cx: &mut Context<Self>,
18199    ) {
18200        let snapshot = self.buffer.read(cx).snapshot(cx);
18201
18202        let ranges = snapshot
18203            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18204            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18205            .collect::<Vec<_>>();
18206
18207        let creases = ranges
18208            .into_iter()
18209            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18210            .collect();
18211
18212        self.fold_creases(creases, true, window, cx);
18213    }
18214
18215    pub fn fold_recursive(
18216        &mut self,
18217        _: &actions::FoldRecursive,
18218        window: &mut Window,
18219        cx: &mut Context<Self>,
18220    ) {
18221        let mut to_fold = Vec::new();
18222        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18223        let selections = self.selections.all_adjusted(cx);
18224
18225        for selection in selections {
18226            let range = selection.range().sorted();
18227            let buffer_start_row = range.start.row;
18228
18229            if range.start.row != range.end.row {
18230                let mut found = false;
18231                for row in range.start.row..=range.end.row {
18232                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18233                        found = true;
18234                        to_fold.push(crease);
18235                    }
18236                }
18237                if found {
18238                    continue;
18239                }
18240            }
18241
18242            for row in (0..=range.start.row).rev() {
18243                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18244                    if crease.range().end.row >= buffer_start_row {
18245                        to_fold.push(crease);
18246                    } else {
18247                        break;
18248                    }
18249                }
18250            }
18251        }
18252
18253        self.fold_creases(to_fold, true, window, cx);
18254    }
18255
18256    pub fn fold_at(
18257        &mut self,
18258        buffer_row: MultiBufferRow,
18259        window: &mut Window,
18260        cx: &mut Context<Self>,
18261    ) {
18262        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18263
18264        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18265            let autoscroll = self
18266                .selections
18267                .all::<Point>(cx)
18268                .iter()
18269                .any(|selection| crease.range().overlaps(&selection.range()));
18270
18271            self.fold_creases(vec![crease], autoscroll, window, cx);
18272        }
18273    }
18274
18275    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18276        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18277            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18278            let buffer = &display_map.buffer_snapshot;
18279            let selections = self.selections.all::<Point>(cx);
18280            let ranges = selections
18281                .iter()
18282                .map(|s| {
18283                    let range = s.display_range(&display_map).sorted();
18284                    let mut start = range.start.to_point(&display_map);
18285                    let mut end = range.end.to_point(&display_map);
18286                    start.column = 0;
18287                    end.column = buffer.line_len(MultiBufferRow(end.row));
18288                    start..end
18289                })
18290                .collect::<Vec<_>>();
18291
18292            self.unfold_ranges(&ranges, true, true, cx);
18293        } else {
18294            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18295            let buffer_ids = self
18296                .selections
18297                .disjoint_anchor_ranges()
18298                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18299                .collect::<HashSet<_>>();
18300            for buffer_id in buffer_ids {
18301                self.unfold_buffer(buffer_id, cx);
18302            }
18303        }
18304    }
18305
18306    pub fn unfold_recursive(
18307        &mut self,
18308        _: &UnfoldRecursive,
18309        _window: &mut Window,
18310        cx: &mut Context<Self>,
18311    ) {
18312        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18313        let selections = self.selections.all::<Point>(cx);
18314        let ranges = selections
18315            .iter()
18316            .map(|s| {
18317                let mut range = s.display_range(&display_map).sorted();
18318                *range.start.column_mut() = 0;
18319                *range.end.column_mut() = display_map.line_len(range.end.row());
18320                let start = range.start.to_point(&display_map);
18321                let end = range.end.to_point(&display_map);
18322                start..end
18323            })
18324            .collect::<Vec<_>>();
18325
18326        self.unfold_ranges(&ranges, true, true, cx);
18327    }
18328
18329    pub fn unfold_at(
18330        &mut self,
18331        buffer_row: MultiBufferRow,
18332        _window: &mut Window,
18333        cx: &mut Context<Self>,
18334    ) {
18335        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18336
18337        let intersection_range = Point::new(buffer_row.0, 0)
18338            ..Point::new(
18339                buffer_row.0,
18340                display_map.buffer_snapshot.line_len(buffer_row),
18341            );
18342
18343        let autoscroll = self
18344            .selections
18345            .all::<Point>(cx)
18346            .iter()
18347            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18348
18349        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18350    }
18351
18352    pub fn unfold_all(
18353        &mut self,
18354        _: &actions::UnfoldAll,
18355        _window: &mut Window,
18356        cx: &mut Context<Self>,
18357    ) {
18358        if self.buffer.read(cx).is_singleton() {
18359            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18360            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18361        } else {
18362            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18363                editor
18364                    .update(cx, |editor, cx| {
18365                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18366                            editor.unfold_buffer(buffer_id, cx);
18367                        }
18368                    })
18369                    .ok();
18370            });
18371        }
18372    }
18373
18374    pub fn fold_selected_ranges(
18375        &mut self,
18376        _: &FoldSelectedRanges,
18377        window: &mut Window,
18378        cx: &mut Context<Self>,
18379    ) {
18380        let selections = self.selections.all_adjusted(cx);
18381        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18382        let ranges = selections
18383            .into_iter()
18384            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18385            .collect::<Vec<_>>();
18386        self.fold_creases(ranges, true, window, cx);
18387    }
18388
18389    pub fn fold_ranges<T: ToOffset + Clone>(
18390        &mut self,
18391        ranges: Vec<Range<T>>,
18392        auto_scroll: bool,
18393        window: &mut Window,
18394        cx: &mut Context<Self>,
18395    ) {
18396        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18397        let ranges = ranges
18398            .into_iter()
18399            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18400            .collect::<Vec<_>>();
18401        self.fold_creases(ranges, auto_scroll, window, cx);
18402    }
18403
18404    pub fn fold_creases<T: ToOffset + Clone>(
18405        &mut self,
18406        creases: Vec<Crease<T>>,
18407        auto_scroll: bool,
18408        _window: &mut Window,
18409        cx: &mut Context<Self>,
18410    ) {
18411        if creases.is_empty() {
18412            return;
18413        }
18414
18415        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18416
18417        if auto_scroll {
18418            self.request_autoscroll(Autoscroll::fit(), cx);
18419        }
18420
18421        cx.notify();
18422
18423        self.scrollbar_marker_state.dirty = true;
18424        self.folds_did_change(cx);
18425    }
18426
18427    /// Removes any folds whose ranges intersect any of the given ranges.
18428    pub fn unfold_ranges<T: ToOffset + Clone>(
18429        &mut self,
18430        ranges: &[Range<T>],
18431        inclusive: bool,
18432        auto_scroll: bool,
18433        cx: &mut Context<Self>,
18434    ) {
18435        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18436            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18437        });
18438        self.folds_did_change(cx);
18439    }
18440
18441    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18442        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18443            return;
18444        }
18445        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18446        self.display_map.update(cx, |display_map, cx| {
18447            display_map.fold_buffers([buffer_id], cx)
18448        });
18449        cx.emit(EditorEvent::BufferFoldToggled {
18450            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18451            folded: true,
18452        });
18453        cx.notify();
18454    }
18455
18456    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18457        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18458            return;
18459        }
18460        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18461        self.display_map.update(cx, |display_map, cx| {
18462            display_map.unfold_buffers([buffer_id], cx);
18463        });
18464        cx.emit(EditorEvent::BufferFoldToggled {
18465            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18466            folded: false,
18467        });
18468        cx.notify();
18469    }
18470
18471    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18472        self.display_map.read(cx).is_buffer_folded(buffer)
18473    }
18474
18475    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18476        self.display_map.read(cx).folded_buffers()
18477    }
18478
18479    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18480        self.display_map.update(cx, |display_map, cx| {
18481            display_map.disable_header_for_buffer(buffer_id, cx);
18482        });
18483        cx.notify();
18484    }
18485
18486    /// Removes any folds with the given ranges.
18487    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18488        &mut self,
18489        ranges: &[Range<T>],
18490        type_id: TypeId,
18491        auto_scroll: bool,
18492        cx: &mut Context<Self>,
18493    ) {
18494        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18495            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18496        });
18497        self.folds_did_change(cx);
18498    }
18499
18500    fn remove_folds_with<T: ToOffset + Clone>(
18501        &mut self,
18502        ranges: &[Range<T>],
18503        auto_scroll: bool,
18504        cx: &mut Context<Self>,
18505        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18506    ) {
18507        if ranges.is_empty() {
18508            return;
18509        }
18510
18511        let mut buffers_affected = HashSet::default();
18512        let multi_buffer = self.buffer().read(cx);
18513        for range in ranges {
18514            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18515                buffers_affected.insert(buffer.read(cx).remote_id());
18516            };
18517        }
18518
18519        self.display_map.update(cx, update);
18520
18521        if auto_scroll {
18522            self.request_autoscroll(Autoscroll::fit(), cx);
18523        }
18524
18525        cx.notify();
18526        self.scrollbar_marker_state.dirty = true;
18527        self.active_indent_guides_state.dirty = true;
18528    }
18529
18530    pub fn update_renderer_widths(
18531        &mut self,
18532        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18533        cx: &mut Context<Self>,
18534    ) -> bool {
18535        self.display_map
18536            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18537    }
18538
18539    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18540        self.display_map.read(cx).fold_placeholder.clone()
18541    }
18542
18543    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18544        self.buffer.update(cx, |buffer, cx| {
18545            buffer.set_all_diff_hunks_expanded(cx);
18546        });
18547    }
18548
18549    pub fn expand_all_diff_hunks(
18550        &mut self,
18551        _: &ExpandAllDiffHunks,
18552        _window: &mut Window,
18553        cx: &mut Context<Self>,
18554    ) {
18555        self.buffer.update(cx, |buffer, cx| {
18556            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18557        });
18558    }
18559
18560    pub fn toggle_selected_diff_hunks(
18561        &mut self,
18562        _: &ToggleSelectedDiffHunks,
18563        _window: &mut Window,
18564        cx: &mut Context<Self>,
18565    ) {
18566        let ranges: Vec<_> = self
18567            .selections
18568            .disjoint_anchors()
18569            .iter()
18570            .map(|s| s.range())
18571            .collect();
18572        self.toggle_diff_hunks_in_ranges(ranges, cx);
18573    }
18574
18575    pub fn diff_hunks_in_ranges<'a>(
18576        &'a self,
18577        ranges: &'a [Range<Anchor>],
18578        buffer: &'a MultiBufferSnapshot,
18579    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18580        ranges.iter().flat_map(move |range| {
18581            let end_excerpt_id = range.end.excerpt_id;
18582            let range = range.to_point(buffer);
18583            let mut peek_end = range.end;
18584            if range.end.row < buffer.max_row().0 {
18585                peek_end = Point::new(range.end.row + 1, 0);
18586            }
18587            buffer
18588                .diff_hunks_in_range(range.start..peek_end)
18589                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18590        })
18591    }
18592
18593    pub fn has_stageable_diff_hunks_in_ranges(
18594        &self,
18595        ranges: &[Range<Anchor>],
18596        snapshot: &MultiBufferSnapshot,
18597    ) -> bool {
18598        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18599        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18600    }
18601
18602    pub fn toggle_staged_selected_diff_hunks(
18603        &mut self,
18604        _: &::git::ToggleStaged,
18605        _: &mut Window,
18606        cx: &mut Context<Self>,
18607    ) {
18608        let snapshot = self.buffer.read(cx).snapshot(cx);
18609        let ranges: Vec<_> = self
18610            .selections
18611            .disjoint_anchors()
18612            .iter()
18613            .map(|s| s.range())
18614            .collect();
18615        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18616        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18617    }
18618
18619    pub fn set_render_diff_hunk_controls(
18620        &mut self,
18621        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18622        cx: &mut Context<Self>,
18623    ) {
18624        self.render_diff_hunk_controls = render_diff_hunk_controls;
18625        cx.notify();
18626    }
18627
18628    pub fn stage_and_next(
18629        &mut self,
18630        _: &::git::StageAndNext,
18631        window: &mut Window,
18632        cx: &mut Context<Self>,
18633    ) {
18634        self.do_stage_or_unstage_and_next(true, window, cx);
18635    }
18636
18637    pub fn unstage_and_next(
18638        &mut self,
18639        _: &::git::UnstageAndNext,
18640        window: &mut Window,
18641        cx: &mut Context<Self>,
18642    ) {
18643        self.do_stage_or_unstage_and_next(false, window, cx);
18644    }
18645
18646    pub fn stage_or_unstage_diff_hunks(
18647        &mut self,
18648        stage: bool,
18649        ranges: Vec<Range<Anchor>>,
18650        cx: &mut Context<Self>,
18651    ) {
18652        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18653        cx.spawn(async move |this, cx| {
18654            task.await?;
18655            this.update(cx, |this, cx| {
18656                let snapshot = this.buffer.read(cx).snapshot(cx);
18657                let chunk_by = this
18658                    .diff_hunks_in_ranges(&ranges, &snapshot)
18659                    .chunk_by(|hunk| hunk.buffer_id);
18660                for (buffer_id, hunks) in &chunk_by {
18661                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18662                }
18663            })
18664        })
18665        .detach_and_log_err(cx);
18666    }
18667
18668    fn save_buffers_for_ranges_if_needed(
18669        &mut self,
18670        ranges: &[Range<Anchor>],
18671        cx: &mut Context<Editor>,
18672    ) -> Task<Result<()>> {
18673        let multibuffer = self.buffer.read(cx);
18674        let snapshot = multibuffer.read(cx);
18675        let buffer_ids: HashSet<_> = ranges
18676            .iter()
18677            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18678            .collect();
18679        drop(snapshot);
18680
18681        let mut buffers = HashSet::default();
18682        for buffer_id in buffer_ids {
18683            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18684                let buffer = buffer_entity.read(cx);
18685                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18686                {
18687                    buffers.insert(buffer_entity);
18688                }
18689            }
18690        }
18691
18692        if let Some(project) = &self.project {
18693            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18694        } else {
18695            Task::ready(Ok(()))
18696        }
18697    }
18698
18699    fn do_stage_or_unstage_and_next(
18700        &mut self,
18701        stage: bool,
18702        window: &mut Window,
18703        cx: &mut Context<Self>,
18704    ) {
18705        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18706
18707        if ranges.iter().any(|range| range.start != range.end) {
18708            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18709            return;
18710        }
18711
18712        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18713        let snapshot = self.snapshot(window, cx);
18714        let position = self.selections.newest::<Point>(cx).head();
18715        let mut row = snapshot
18716            .buffer_snapshot
18717            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18718            .find(|hunk| hunk.row_range.start.0 > position.row)
18719            .map(|hunk| hunk.row_range.start);
18720
18721        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18722        // Outside of the project diff editor, wrap around to the beginning.
18723        if !all_diff_hunks_expanded {
18724            row = row.or_else(|| {
18725                snapshot
18726                    .buffer_snapshot
18727                    .diff_hunks_in_range(Point::zero()..position)
18728                    .find(|hunk| hunk.row_range.end.0 < position.row)
18729                    .map(|hunk| hunk.row_range.start)
18730            });
18731        }
18732
18733        if let Some(row) = row {
18734            let destination = Point::new(row.0, 0);
18735            let autoscroll = Autoscroll::center();
18736
18737            self.unfold_ranges(&[destination..destination], false, false, cx);
18738            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18739                s.select_ranges([destination..destination]);
18740            });
18741        }
18742    }
18743
18744    fn do_stage_or_unstage(
18745        &self,
18746        stage: bool,
18747        buffer_id: BufferId,
18748        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18749        cx: &mut App,
18750    ) -> Option<()> {
18751        let project = self.project()?;
18752        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18753        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18754        let buffer_snapshot = buffer.read(cx).snapshot();
18755        let file_exists = buffer_snapshot
18756            .file()
18757            .is_some_and(|file| file.disk_state().exists());
18758        diff.update(cx, |diff, cx| {
18759            diff.stage_or_unstage_hunks(
18760                stage,
18761                &hunks
18762                    .map(|hunk| buffer_diff::DiffHunk {
18763                        buffer_range: hunk.buffer_range,
18764                        diff_base_byte_range: hunk.diff_base_byte_range,
18765                        secondary_status: hunk.secondary_status,
18766                        range: Point::zero()..Point::zero(), // unused
18767                    })
18768                    .collect::<Vec<_>>(),
18769                &buffer_snapshot,
18770                file_exists,
18771                cx,
18772            )
18773        });
18774        None
18775    }
18776
18777    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18778        let ranges: Vec<_> = self
18779            .selections
18780            .disjoint_anchors()
18781            .iter()
18782            .map(|s| s.range())
18783            .collect();
18784        self.buffer
18785            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18786    }
18787
18788    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18789        self.buffer.update(cx, |buffer, cx| {
18790            let ranges = vec![Anchor::min()..Anchor::max()];
18791            if !buffer.all_diff_hunks_expanded()
18792                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18793            {
18794                buffer.collapse_diff_hunks(ranges, cx);
18795                true
18796            } else {
18797                false
18798            }
18799        })
18800    }
18801
18802    fn toggle_diff_hunks_in_ranges(
18803        &mut self,
18804        ranges: Vec<Range<Anchor>>,
18805        cx: &mut Context<Editor>,
18806    ) {
18807        self.buffer.update(cx, |buffer, cx| {
18808            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18809            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18810        })
18811    }
18812
18813    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18814        self.buffer.update(cx, |buffer, cx| {
18815            let snapshot = buffer.snapshot(cx);
18816            let excerpt_id = range.end.excerpt_id;
18817            let point_range = range.to_point(&snapshot);
18818            let expand = !buffer.single_hunk_is_expanded(range, cx);
18819            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18820        })
18821    }
18822
18823    pub(crate) fn apply_all_diff_hunks(
18824        &mut self,
18825        _: &ApplyAllDiffHunks,
18826        window: &mut Window,
18827        cx: &mut Context<Self>,
18828    ) {
18829        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18830
18831        let buffers = self.buffer.read(cx).all_buffers();
18832        for branch_buffer in buffers {
18833            branch_buffer.update(cx, |branch_buffer, cx| {
18834                branch_buffer.merge_into_base(Vec::new(), cx);
18835            });
18836        }
18837
18838        if let Some(project) = self.project.clone() {
18839            self.save(
18840                SaveOptions {
18841                    format: true,
18842                    autosave: false,
18843                },
18844                project,
18845                window,
18846                cx,
18847            )
18848            .detach_and_log_err(cx);
18849        }
18850    }
18851
18852    pub(crate) fn apply_selected_diff_hunks(
18853        &mut self,
18854        _: &ApplyDiffHunk,
18855        window: &mut Window,
18856        cx: &mut Context<Self>,
18857    ) {
18858        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18859        let snapshot = self.snapshot(window, cx);
18860        let hunks = snapshot.hunks_for_ranges(
18861            self.selections
18862                .all(cx)
18863                .into_iter()
18864                .map(|selection| selection.range()),
18865        );
18866        let mut ranges_by_buffer = HashMap::default();
18867        self.transact(window, cx, |editor, _window, cx| {
18868            for hunk in hunks {
18869                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18870                    ranges_by_buffer
18871                        .entry(buffer.clone())
18872                        .or_insert_with(Vec::new)
18873                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18874                }
18875            }
18876
18877            for (buffer, ranges) in ranges_by_buffer {
18878                buffer.update(cx, |buffer, cx| {
18879                    buffer.merge_into_base(ranges, cx);
18880                });
18881            }
18882        });
18883
18884        if let Some(project) = self.project.clone() {
18885            self.save(
18886                SaveOptions {
18887                    format: true,
18888                    autosave: false,
18889                },
18890                project,
18891                window,
18892                cx,
18893            )
18894            .detach_and_log_err(cx);
18895        }
18896    }
18897
18898    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18899        if hovered != self.gutter_hovered {
18900            self.gutter_hovered = hovered;
18901            cx.notify();
18902        }
18903    }
18904
18905    pub fn insert_blocks(
18906        &mut self,
18907        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18908        autoscroll: Option<Autoscroll>,
18909        cx: &mut Context<Self>,
18910    ) -> Vec<CustomBlockId> {
18911        let blocks = self
18912            .display_map
18913            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18914        if let Some(autoscroll) = autoscroll {
18915            self.request_autoscroll(autoscroll, cx);
18916        }
18917        cx.notify();
18918        blocks
18919    }
18920
18921    pub fn resize_blocks(
18922        &mut self,
18923        heights: HashMap<CustomBlockId, u32>,
18924        autoscroll: Option<Autoscroll>,
18925        cx: &mut Context<Self>,
18926    ) {
18927        self.display_map
18928            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18929        if let Some(autoscroll) = autoscroll {
18930            self.request_autoscroll(autoscroll, cx);
18931        }
18932        cx.notify();
18933    }
18934
18935    pub fn replace_blocks(
18936        &mut self,
18937        renderers: HashMap<CustomBlockId, RenderBlock>,
18938        autoscroll: Option<Autoscroll>,
18939        cx: &mut Context<Self>,
18940    ) {
18941        self.display_map
18942            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18943        if let Some(autoscroll) = autoscroll {
18944            self.request_autoscroll(autoscroll, cx);
18945        }
18946        cx.notify();
18947    }
18948
18949    pub fn remove_blocks(
18950        &mut self,
18951        block_ids: HashSet<CustomBlockId>,
18952        autoscroll: Option<Autoscroll>,
18953        cx: &mut Context<Self>,
18954    ) {
18955        self.display_map.update(cx, |display_map, cx| {
18956            display_map.remove_blocks(block_ids, cx)
18957        });
18958        if let Some(autoscroll) = autoscroll {
18959            self.request_autoscroll(autoscroll, cx);
18960        }
18961        cx.notify();
18962    }
18963
18964    pub fn row_for_block(
18965        &self,
18966        block_id: CustomBlockId,
18967        cx: &mut Context<Self>,
18968    ) -> Option<DisplayRow> {
18969        self.display_map
18970            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18971    }
18972
18973    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18974        self.focused_block = Some(focused_block);
18975    }
18976
18977    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18978        self.focused_block.take()
18979    }
18980
18981    pub fn insert_creases(
18982        &mut self,
18983        creases: impl IntoIterator<Item = Crease<Anchor>>,
18984        cx: &mut Context<Self>,
18985    ) -> Vec<CreaseId> {
18986        self.display_map
18987            .update(cx, |map, cx| map.insert_creases(creases, cx))
18988    }
18989
18990    pub fn remove_creases(
18991        &mut self,
18992        ids: impl IntoIterator<Item = CreaseId>,
18993        cx: &mut Context<Self>,
18994    ) -> Vec<(CreaseId, Range<Anchor>)> {
18995        self.display_map
18996            .update(cx, |map, cx| map.remove_creases(ids, cx))
18997    }
18998
18999    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19000        self.display_map
19001            .update(cx, |map, cx| map.snapshot(cx))
19002            .longest_row()
19003    }
19004
19005    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19006        self.display_map
19007            .update(cx, |map, cx| map.snapshot(cx))
19008            .max_point()
19009    }
19010
19011    pub fn text(&self, cx: &App) -> String {
19012        self.buffer.read(cx).read(cx).text()
19013    }
19014
19015    pub fn is_empty(&self, cx: &App) -> bool {
19016        self.buffer.read(cx).read(cx).is_empty()
19017    }
19018
19019    pub fn text_option(&self, cx: &App) -> Option<String> {
19020        let text = self.text(cx);
19021        let text = text.trim();
19022
19023        if text.is_empty() {
19024            return None;
19025        }
19026
19027        Some(text.to_string())
19028    }
19029
19030    pub fn set_text(
19031        &mut self,
19032        text: impl Into<Arc<str>>,
19033        window: &mut Window,
19034        cx: &mut Context<Self>,
19035    ) {
19036        self.transact(window, cx, |this, _, cx| {
19037            this.buffer
19038                .read(cx)
19039                .as_singleton()
19040                .expect("you can only call set_text on editors for singleton buffers")
19041                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19042        });
19043    }
19044
19045    pub fn display_text(&self, cx: &mut App) -> String {
19046        self.display_map
19047            .update(cx, |map, cx| map.snapshot(cx))
19048            .text()
19049    }
19050
19051    fn create_minimap(
19052        &self,
19053        minimap_settings: MinimapSettings,
19054        window: &mut Window,
19055        cx: &mut Context<Self>,
19056    ) -> Option<Entity<Self>> {
19057        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19058            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19059    }
19060
19061    fn initialize_new_minimap(
19062        &self,
19063        minimap_settings: MinimapSettings,
19064        window: &mut Window,
19065        cx: &mut Context<Self>,
19066    ) -> Entity<Self> {
19067        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19068
19069        let mut minimap = Editor::new_internal(
19070            EditorMode::Minimap {
19071                parent: cx.weak_entity(),
19072            },
19073            self.buffer.clone(),
19074            None,
19075            Some(self.display_map.clone()),
19076            window,
19077            cx,
19078        );
19079        minimap.scroll_manager.clone_state(&self.scroll_manager);
19080        minimap.set_text_style_refinement(TextStyleRefinement {
19081            font_size: Some(MINIMAP_FONT_SIZE),
19082            font_weight: Some(MINIMAP_FONT_WEIGHT),
19083            ..Default::default()
19084        });
19085        minimap.update_minimap_configuration(minimap_settings, cx);
19086        cx.new(|_| minimap)
19087    }
19088
19089    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19090        let current_line_highlight = minimap_settings
19091            .current_line_highlight
19092            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19093        self.set_current_line_highlight(Some(current_line_highlight));
19094    }
19095
19096    pub fn minimap(&self) -> Option<&Entity<Self>> {
19097        self.minimap
19098            .as_ref()
19099            .filter(|_| self.minimap_visibility.visible())
19100    }
19101
19102    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19103        let mut wrap_guides = smallvec![];
19104
19105        if self.show_wrap_guides == Some(false) {
19106            return wrap_guides;
19107        }
19108
19109        let settings = self.buffer.read(cx).language_settings(cx);
19110        if settings.show_wrap_guides {
19111            match self.soft_wrap_mode(cx) {
19112                SoftWrap::Column(soft_wrap) => {
19113                    wrap_guides.push((soft_wrap as usize, true));
19114                }
19115                SoftWrap::Bounded(soft_wrap) => {
19116                    wrap_guides.push((soft_wrap as usize, true));
19117                }
19118                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19119            }
19120            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19121        }
19122
19123        wrap_guides
19124    }
19125
19126    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19127        let settings = self.buffer.read(cx).language_settings(cx);
19128        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19129        match mode {
19130            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19131                SoftWrap::None
19132            }
19133            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19134            language_settings::SoftWrap::PreferredLineLength => {
19135                SoftWrap::Column(settings.preferred_line_length)
19136            }
19137            language_settings::SoftWrap::Bounded => {
19138                SoftWrap::Bounded(settings.preferred_line_length)
19139            }
19140        }
19141    }
19142
19143    pub fn set_soft_wrap_mode(
19144        &mut self,
19145        mode: language_settings::SoftWrap,
19146
19147        cx: &mut Context<Self>,
19148    ) {
19149        self.soft_wrap_mode_override = Some(mode);
19150        cx.notify();
19151    }
19152
19153    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19154        self.hard_wrap = hard_wrap;
19155        cx.notify();
19156    }
19157
19158    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19159        self.text_style_refinement = Some(style);
19160    }
19161
19162    /// called by the Element so we know what style we were most recently rendered with.
19163    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19164        // We intentionally do not inform the display map about the minimap style
19165        // so that wrapping is not recalculated and stays consistent for the editor
19166        // and its linked minimap.
19167        if !self.mode.is_minimap() {
19168            let font = style.text.font();
19169            let font_size = style.text.font_size.to_pixels(window.rem_size());
19170            let display_map = self
19171                .placeholder_display_map
19172                .as_ref()
19173                .filter(|_| self.is_empty(cx))
19174                .unwrap_or(&self.display_map);
19175
19176            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19177        }
19178        self.style = Some(style);
19179    }
19180
19181    pub fn style(&self) -> Option<&EditorStyle> {
19182        self.style.as_ref()
19183    }
19184
19185    // Called by the element. This method is not designed to be called outside of the editor
19186    // element's layout code because it does not notify when rewrapping is computed synchronously.
19187    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19188        if self.is_empty(cx) {
19189            self.placeholder_display_map
19190                .as_ref()
19191                .map_or(false, |display_map| {
19192                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19193                })
19194        } else {
19195            self.display_map
19196                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19197        }
19198    }
19199
19200    pub fn set_soft_wrap(&mut self) {
19201        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19202    }
19203
19204    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19205        if self.soft_wrap_mode_override.is_some() {
19206            self.soft_wrap_mode_override.take();
19207        } else {
19208            let soft_wrap = match self.soft_wrap_mode(cx) {
19209                SoftWrap::GitDiff => return,
19210                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19211                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19212                    language_settings::SoftWrap::None
19213                }
19214            };
19215            self.soft_wrap_mode_override = Some(soft_wrap);
19216        }
19217        cx.notify();
19218    }
19219
19220    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19221        let Some(workspace) = self.workspace() else {
19222            return;
19223        };
19224        let fs = workspace.read(cx).app_state().fs.clone();
19225        let current_show = TabBarSettings::get_global(cx).show;
19226        update_settings_file(fs, cx, move |setting, _| {
19227            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19228        });
19229    }
19230
19231    pub fn toggle_indent_guides(
19232        &mut self,
19233        _: &ToggleIndentGuides,
19234        _: &mut Window,
19235        cx: &mut Context<Self>,
19236    ) {
19237        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19238            self.buffer
19239                .read(cx)
19240                .language_settings(cx)
19241                .indent_guides
19242                .enabled
19243        });
19244        self.show_indent_guides = Some(!currently_enabled);
19245        cx.notify();
19246    }
19247
19248    fn should_show_indent_guides(&self) -> Option<bool> {
19249        self.show_indent_guides
19250    }
19251
19252    pub fn toggle_line_numbers(
19253        &mut self,
19254        _: &ToggleLineNumbers,
19255        _: &mut Window,
19256        cx: &mut Context<Self>,
19257    ) {
19258        let mut editor_settings = EditorSettings::get_global(cx).clone();
19259        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19260        EditorSettings::override_global(editor_settings, cx);
19261    }
19262
19263    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19264        if let Some(show_line_numbers) = self.show_line_numbers {
19265            return show_line_numbers;
19266        }
19267        EditorSettings::get_global(cx).gutter.line_numbers
19268    }
19269
19270    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19271        self.use_relative_line_numbers
19272            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19273    }
19274
19275    pub fn toggle_relative_line_numbers(
19276        &mut self,
19277        _: &ToggleRelativeLineNumbers,
19278        _: &mut Window,
19279        cx: &mut Context<Self>,
19280    ) {
19281        let is_relative = self.should_use_relative_line_numbers(cx);
19282        self.set_relative_line_number(Some(!is_relative), cx)
19283    }
19284
19285    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19286        self.use_relative_line_numbers = is_relative;
19287        cx.notify();
19288    }
19289
19290    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19291        self.show_gutter = show_gutter;
19292        cx.notify();
19293    }
19294
19295    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19296        self.show_scrollbars = ScrollbarAxes {
19297            horizontal: show,
19298            vertical: show,
19299        };
19300        cx.notify();
19301    }
19302
19303    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19304        self.show_scrollbars.vertical = show;
19305        cx.notify();
19306    }
19307
19308    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19309        self.show_scrollbars.horizontal = show;
19310        cx.notify();
19311    }
19312
19313    pub fn set_minimap_visibility(
19314        &mut self,
19315        minimap_visibility: MinimapVisibility,
19316        window: &mut Window,
19317        cx: &mut Context<Self>,
19318    ) {
19319        if self.minimap_visibility != minimap_visibility {
19320            if minimap_visibility.visible() && self.minimap.is_none() {
19321                let minimap_settings = EditorSettings::get_global(cx).minimap;
19322                self.minimap =
19323                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19324            }
19325            self.minimap_visibility = minimap_visibility;
19326            cx.notify();
19327        }
19328    }
19329
19330    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19331        self.set_show_scrollbars(false, cx);
19332        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19333    }
19334
19335    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19336        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19337    }
19338
19339    /// Normally the text in full mode and auto height editors is padded on the
19340    /// left side by roughly half a character width for improved hit testing.
19341    ///
19342    /// Use this method to disable this for cases where this is not wanted (e.g.
19343    /// if you want to align the editor text with some other text above or below)
19344    /// or if you want to add this padding to single-line editors.
19345    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19346        self.offset_content = offset_content;
19347        cx.notify();
19348    }
19349
19350    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19351        self.show_line_numbers = Some(show_line_numbers);
19352        cx.notify();
19353    }
19354
19355    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19356        self.disable_expand_excerpt_buttons = true;
19357        cx.notify();
19358    }
19359
19360    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19361        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19362        cx.notify();
19363    }
19364
19365    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19366        self.show_code_actions = Some(show_code_actions);
19367        cx.notify();
19368    }
19369
19370    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19371        self.show_runnables = Some(show_runnables);
19372        cx.notify();
19373    }
19374
19375    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19376        self.show_breakpoints = Some(show_breakpoints);
19377        cx.notify();
19378    }
19379
19380    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19381        if self.display_map.read(cx).masked != masked {
19382            self.display_map.update(cx, |map, _| map.masked = masked);
19383        }
19384        cx.notify()
19385    }
19386
19387    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19388        self.show_wrap_guides = Some(show_wrap_guides);
19389        cx.notify();
19390    }
19391
19392    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19393        self.show_indent_guides = Some(show_indent_guides);
19394        cx.notify();
19395    }
19396
19397    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19398        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19399            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19400                && let Some(dir) = file.abs_path(cx).parent()
19401            {
19402                return Some(dir.to_owned());
19403            }
19404        }
19405
19406        None
19407    }
19408
19409    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19410        self.active_excerpt(cx)?
19411            .1
19412            .read(cx)
19413            .file()
19414            .and_then(|f| f.as_local())
19415    }
19416
19417    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19418        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19419            let buffer = buffer.read(cx);
19420            if let Some(project_path) = buffer.project_path(cx) {
19421                let project = self.project()?.read(cx);
19422                project.absolute_path(&project_path, cx)
19423            } else {
19424                buffer
19425                    .file()
19426                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19427            }
19428        })
19429    }
19430
19431    pub fn reveal_in_finder(
19432        &mut self,
19433        _: &RevealInFileManager,
19434        _window: &mut Window,
19435        cx: &mut Context<Self>,
19436    ) {
19437        if let Some(target) = self.target_file(cx) {
19438            cx.reveal_path(&target.abs_path(cx));
19439        }
19440    }
19441
19442    pub fn copy_path(
19443        &mut self,
19444        _: &zed_actions::workspace::CopyPath,
19445        _window: &mut Window,
19446        cx: &mut Context<Self>,
19447    ) {
19448        if let Some(path) = self.target_file_abs_path(cx)
19449            && let Some(path) = path.to_str()
19450        {
19451            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19452        } else {
19453            cx.propagate();
19454        }
19455    }
19456
19457    pub fn copy_relative_path(
19458        &mut self,
19459        _: &zed_actions::workspace::CopyRelativePath,
19460        _window: &mut Window,
19461        cx: &mut Context<Self>,
19462    ) {
19463        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19464            let project = self.project()?.read(cx);
19465            let path = buffer.read(cx).file()?.path();
19466            let path = path.display(project.path_style(cx));
19467            Some(path)
19468        }) {
19469            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19470        } else {
19471            cx.propagate();
19472        }
19473    }
19474
19475    /// Returns the project path for the editor's buffer, if any buffer is
19476    /// opened in the editor.
19477    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19478        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19479            buffer.read(cx).project_path(cx)
19480        } else {
19481            None
19482        }
19483    }
19484
19485    // Returns true if the editor handled a go-to-line request
19486    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19487        maybe!({
19488            let breakpoint_store = self.breakpoint_store.as_ref()?;
19489
19490            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19491            else {
19492                self.clear_row_highlights::<ActiveDebugLine>();
19493                return None;
19494            };
19495
19496            let position = active_stack_frame.position;
19497            let buffer_id = position.buffer_id?;
19498            let snapshot = self
19499                .project
19500                .as_ref()?
19501                .read(cx)
19502                .buffer_for_id(buffer_id, cx)?
19503                .read(cx)
19504                .snapshot();
19505
19506            let mut handled = false;
19507            for (id, ExcerptRange { context, .. }) in
19508                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19509            {
19510                if context.start.cmp(&position, &snapshot).is_ge()
19511                    || context.end.cmp(&position, &snapshot).is_lt()
19512                {
19513                    continue;
19514                }
19515                let snapshot = self.buffer.read(cx).snapshot(cx);
19516                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19517
19518                handled = true;
19519                self.clear_row_highlights::<ActiveDebugLine>();
19520
19521                self.go_to_line::<ActiveDebugLine>(
19522                    multibuffer_anchor,
19523                    Some(cx.theme().colors().editor_debugger_active_line_background),
19524                    window,
19525                    cx,
19526                );
19527
19528                cx.notify();
19529            }
19530
19531            handled.then_some(())
19532        })
19533        .is_some()
19534    }
19535
19536    pub fn copy_file_name_without_extension(
19537        &mut self,
19538        _: &CopyFileNameWithoutExtension,
19539        _: &mut Window,
19540        cx: &mut Context<Self>,
19541    ) {
19542        if let Some(file) = self.target_file(cx)
19543            && let Some(file_stem) = file.path().file_stem()
19544        {
19545            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19546        }
19547    }
19548
19549    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19550        if let Some(file) = self.target_file(cx)
19551            && let Some(name) = file.path().file_name()
19552        {
19553            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19554        }
19555    }
19556
19557    pub fn toggle_git_blame(
19558        &mut self,
19559        _: &::git::Blame,
19560        window: &mut Window,
19561        cx: &mut Context<Self>,
19562    ) {
19563        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19564
19565        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19566            self.start_git_blame(true, window, cx);
19567        }
19568
19569        cx.notify();
19570    }
19571
19572    pub fn toggle_git_blame_inline(
19573        &mut self,
19574        _: &ToggleGitBlameInline,
19575        window: &mut Window,
19576        cx: &mut Context<Self>,
19577    ) {
19578        self.toggle_git_blame_inline_internal(true, window, cx);
19579        cx.notify();
19580    }
19581
19582    pub fn open_git_blame_commit(
19583        &mut self,
19584        _: &OpenGitBlameCommit,
19585        window: &mut Window,
19586        cx: &mut Context<Self>,
19587    ) {
19588        self.open_git_blame_commit_internal(window, cx);
19589    }
19590
19591    fn open_git_blame_commit_internal(
19592        &mut self,
19593        window: &mut Window,
19594        cx: &mut Context<Self>,
19595    ) -> Option<()> {
19596        let blame = self.blame.as_ref()?;
19597        let snapshot = self.snapshot(window, cx);
19598        let cursor = self.selections.newest::<Point>(cx).head();
19599        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19600        let (_, blame_entry) = blame
19601            .update(cx, |blame, cx| {
19602                blame
19603                    .blame_for_rows(
19604                        &[RowInfo {
19605                            buffer_id: Some(buffer.remote_id()),
19606                            buffer_row: Some(point.row),
19607                            ..Default::default()
19608                        }],
19609                        cx,
19610                    )
19611                    .next()
19612            })
19613            .flatten()?;
19614        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19615        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19616        let workspace = self.workspace()?.downgrade();
19617        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19618        None
19619    }
19620
19621    pub fn git_blame_inline_enabled(&self) -> bool {
19622        self.git_blame_inline_enabled
19623    }
19624
19625    pub fn toggle_selection_menu(
19626        &mut self,
19627        _: &ToggleSelectionMenu,
19628        _: &mut Window,
19629        cx: &mut Context<Self>,
19630    ) {
19631        self.show_selection_menu = self
19632            .show_selection_menu
19633            .map(|show_selections_menu| !show_selections_menu)
19634            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19635
19636        cx.notify();
19637    }
19638
19639    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19640        self.show_selection_menu
19641            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19642    }
19643
19644    fn start_git_blame(
19645        &mut self,
19646        user_triggered: bool,
19647        window: &mut Window,
19648        cx: &mut Context<Self>,
19649    ) {
19650        if let Some(project) = self.project() {
19651            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19652                && buffer.read(cx).file().is_none()
19653            {
19654                return;
19655            }
19656
19657            let focused = self.focus_handle(cx).contains_focused(window, cx);
19658
19659            let project = project.clone();
19660            let blame = cx
19661                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19662            self.blame_subscription =
19663                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19664            self.blame = Some(blame);
19665        }
19666    }
19667
19668    fn toggle_git_blame_inline_internal(
19669        &mut self,
19670        user_triggered: bool,
19671        window: &mut Window,
19672        cx: &mut Context<Self>,
19673    ) {
19674        if self.git_blame_inline_enabled {
19675            self.git_blame_inline_enabled = false;
19676            self.show_git_blame_inline = false;
19677            self.show_git_blame_inline_delay_task.take();
19678        } else {
19679            self.git_blame_inline_enabled = true;
19680            self.start_git_blame_inline(user_triggered, window, cx);
19681        }
19682
19683        cx.notify();
19684    }
19685
19686    fn start_git_blame_inline(
19687        &mut self,
19688        user_triggered: bool,
19689        window: &mut Window,
19690        cx: &mut Context<Self>,
19691    ) {
19692        self.start_git_blame(user_triggered, window, cx);
19693
19694        if ProjectSettings::get_global(cx)
19695            .git
19696            .inline_blame_delay()
19697            .is_some()
19698        {
19699            self.start_inline_blame_timer(window, cx);
19700        } else {
19701            self.show_git_blame_inline = true
19702        }
19703    }
19704
19705    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19706        self.blame.as_ref()
19707    }
19708
19709    pub fn show_git_blame_gutter(&self) -> bool {
19710        self.show_git_blame_gutter
19711    }
19712
19713    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19714        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19715    }
19716
19717    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19718        self.show_git_blame_inline
19719            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19720            && !self.newest_selection_head_on_empty_line(cx)
19721            && self.has_blame_entries(cx)
19722    }
19723
19724    fn has_blame_entries(&self, cx: &App) -> bool {
19725        self.blame()
19726            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19727    }
19728
19729    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19730        let cursor_anchor = self.selections.newest_anchor().head();
19731
19732        let snapshot = self.buffer.read(cx).snapshot(cx);
19733        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19734
19735        snapshot.line_len(buffer_row) == 0
19736    }
19737
19738    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19739        let buffer_and_selection = maybe!({
19740            let selection = self.selections.newest::<Point>(cx);
19741            let selection_range = selection.range();
19742
19743            let multi_buffer = self.buffer().read(cx);
19744            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19745            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19746
19747            let (buffer, range, _) = if selection.reversed {
19748                buffer_ranges.first()
19749            } else {
19750                buffer_ranges.last()
19751            }?;
19752
19753            let selection = text::ToPoint::to_point(&range.start, buffer).row
19754                ..text::ToPoint::to_point(&range.end, buffer).row;
19755            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19756        });
19757
19758        let Some((buffer, selection)) = buffer_and_selection else {
19759            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19760        };
19761
19762        let Some(project) = self.project() else {
19763            return Task::ready(Err(anyhow!("editor does not have project")));
19764        };
19765
19766        project.update(cx, |project, cx| {
19767            project.get_permalink_to_line(&buffer, selection, cx)
19768        })
19769    }
19770
19771    pub fn copy_permalink_to_line(
19772        &mut self,
19773        _: &CopyPermalinkToLine,
19774        window: &mut Window,
19775        cx: &mut Context<Self>,
19776    ) {
19777        let permalink_task = self.get_permalink_to_line(cx);
19778        let workspace = self.workspace();
19779
19780        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19781            Ok(permalink) => {
19782                cx.update(|_, cx| {
19783                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19784                })
19785                .ok();
19786            }
19787            Err(err) => {
19788                let message = format!("Failed to copy permalink: {err}");
19789
19790                anyhow::Result::<()>::Err(err).log_err();
19791
19792                if let Some(workspace) = workspace {
19793                    workspace
19794                        .update_in(cx, |workspace, _, cx| {
19795                            struct CopyPermalinkToLine;
19796
19797                            workspace.show_toast(
19798                                Toast::new(
19799                                    NotificationId::unique::<CopyPermalinkToLine>(),
19800                                    message,
19801                                ),
19802                                cx,
19803                            )
19804                        })
19805                        .ok();
19806                }
19807            }
19808        })
19809        .detach();
19810    }
19811
19812    pub fn copy_file_location(
19813        &mut self,
19814        _: &CopyFileLocation,
19815        _: &mut Window,
19816        cx: &mut Context<Self>,
19817    ) {
19818        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19819        if let Some(file) = self.target_file(cx) {
19820            let path = file.path().display(file.path_style(cx));
19821            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19822        }
19823    }
19824
19825    pub fn open_permalink_to_line(
19826        &mut self,
19827        _: &OpenPermalinkToLine,
19828        window: &mut Window,
19829        cx: &mut Context<Self>,
19830    ) {
19831        let permalink_task = self.get_permalink_to_line(cx);
19832        let workspace = self.workspace();
19833
19834        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19835            Ok(permalink) => {
19836                cx.update(|_, cx| {
19837                    cx.open_url(permalink.as_ref());
19838                })
19839                .ok();
19840            }
19841            Err(err) => {
19842                let message = format!("Failed to open permalink: {err}");
19843
19844                anyhow::Result::<()>::Err(err).log_err();
19845
19846                if let Some(workspace) = workspace {
19847                    workspace
19848                        .update(cx, |workspace, cx| {
19849                            struct OpenPermalinkToLine;
19850
19851                            workspace.show_toast(
19852                                Toast::new(
19853                                    NotificationId::unique::<OpenPermalinkToLine>(),
19854                                    message,
19855                                ),
19856                                cx,
19857                            )
19858                        })
19859                        .ok();
19860                }
19861            }
19862        })
19863        .detach();
19864    }
19865
19866    pub fn insert_uuid_v4(
19867        &mut self,
19868        _: &InsertUuidV4,
19869        window: &mut Window,
19870        cx: &mut Context<Self>,
19871    ) {
19872        self.insert_uuid(UuidVersion::V4, window, cx);
19873    }
19874
19875    pub fn insert_uuid_v7(
19876        &mut self,
19877        _: &InsertUuidV7,
19878        window: &mut Window,
19879        cx: &mut Context<Self>,
19880    ) {
19881        self.insert_uuid(UuidVersion::V7, window, cx);
19882    }
19883
19884    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19885        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19886        self.transact(window, cx, |this, window, cx| {
19887            let edits = this
19888                .selections
19889                .all::<Point>(cx)
19890                .into_iter()
19891                .map(|selection| {
19892                    let uuid = match version {
19893                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19894                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19895                    };
19896
19897                    (selection.range(), uuid.to_string())
19898                });
19899            this.edit(edits, cx);
19900            this.refresh_edit_prediction(true, false, window, cx);
19901        });
19902    }
19903
19904    pub fn open_selections_in_multibuffer(
19905        &mut self,
19906        _: &OpenSelectionsInMultibuffer,
19907        window: &mut Window,
19908        cx: &mut Context<Self>,
19909    ) {
19910        let multibuffer = self.buffer.read(cx);
19911
19912        let Some(buffer) = multibuffer.as_singleton() else {
19913            return;
19914        };
19915
19916        let Some(workspace) = self.workspace() else {
19917            return;
19918        };
19919
19920        let title = multibuffer.title(cx).to_string();
19921
19922        let locations = self
19923            .selections
19924            .all_anchors(cx)
19925            .iter()
19926            .map(|selection| {
19927                (
19928                    buffer.clone(),
19929                    (selection.start.text_anchor..selection.end.text_anchor)
19930                        .to_point(buffer.read(cx)),
19931                )
19932            })
19933            .into_group_map();
19934
19935        cx.spawn_in(window, async move |_, cx| {
19936            workspace.update_in(cx, |workspace, window, cx| {
19937                Self::open_locations_in_multibuffer(
19938                    workspace,
19939                    locations,
19940                    format!("Selections for '{title}'"),
19941                    false,
19942                    MultibufferSelectionMode::All,
19943                    window,
19944                    cx,
19945                );
19946            })
19947        })
19948        .detach();
19949    }
19950
19951    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19952    /// last highlight added will be used.
19953    ///
19954    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19955    pub fn highlight_rows<T: 'static>(
19956        &mut self,
19957        range: Range<Anchor>,
19958        color: Hsla,
19959        options: RowHighlightOptions,
19960        cx: &mut Context<Self>,
19961    ) {
19962        let snapshot = self.buffer().read(cx).snapshot(cx);
19963        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19964        let ix = row_highlights.binary_search_by(|highlight| {
19965            Ordering::Equal
19966                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19967                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19968        });
19969
19970        if let Err(mut ix) = ix {
19971            let index = post_inc(&mut self.highlight_order);
19972
19973            // If this range intersects with the preceding highlight, then merge it with
19974            // the preceding highlight. Otherwise insert a new highlight.
19975            let mut merged = false;
19976            if ix > 0 {
19977                let prev_highlight = &mut row_highlights[ix - 1];
19978                if prev_highlight
19979                    .range
19980                    .end
19981                    .cmp(&range.start, &snapshot)
19982                    .is_ge()
19983                {
19984                    ix -= 1;
19985                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19986                        prev_highlight.range.end = range.end;
19987                    }
19988                    merged = true;
19989                    prev_highlight.index = index;
19990                    prev_highlight.color = color;
19991                    prev_highlight.options = options;
19992                }
19993            }
19994
19995            if !merged {
19996                row_highlights.insert(
19997                    ix,
19998                    RowHighlight {
19999                        range,
20000                        index,
20001                        color,
20002                        options,
20003                        type_id: TypeId::of::<T>(),
20004                    },
20005                );
20006            }
20007
20008            // If any of the following highlights intersect with this one, merge them.
20009            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20010                let highlight = &row_highlights[ix];
20011                if next_highlight
20012                    .range
20013                    .start
20014                    .cmp(&highlight.range.end, &snapshot)
20015                    .is_le()
20016                {
20017                    if next_highlight
20018                        .range
20019                        .end
20020                        .cmp(&highlight.range.end, &snapshot)
20021                        .is_gt()
20022                    {
20023                        row_highlights[ix].range.end = next_highlight.range.end;
20024                    }
20025                    row_highlights.remove(ix + 1);
20026                } else {
20027                    break;
20028                }
20029            }
20030        }
20031    }
20032
20033    /// Remove any highlighted row ranges of the given type that intersect the
20034    /// given ranges.
20035    pub fn remove_highlighted_rows<T: 'static>(
20036        &mut self,
20037        ranges_to_remove: Vec<Range<Anchor>>,
20038        cx: &mut Context<Self>,
20039    ) {
20040        let snapshot = self.buffer().read(cx).snapshot(cx);
20041        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20042        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20043        row_highlights.retain(|highlight| {
20044            while let Some(range_to_remove) = ranges_to_remove.peek() {
20045                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20046                    Ordering::Less | Ordering::Equal => {
20047                        ranges_to_remove.next();
20048                    }
20049                    Ordering::Greater => {
20050                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20051                            Ordering::Less | Ordering::Equal => {
20052                                return false;
20053                            }
20054                            Ordering::Greater => break,
20055                        }
20056                    }
20057                }
20058            }
20059
20060            true
20061        })
20062    }
20063
20064    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20065    pub fn clear_row_highlights<T: 'static>(&mut self) {
20066        self.highlighted_rows.remove(&TypeId::of::<T>());
20067    }
20068
20069    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20070    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20071        self.highlighted_rows
20072            .get(&TypeId::of::<T>())
20073            .map_or(&[] as &[_], |vec| vec.as_slice())
20074            .iter()
20075            .map(|highlight| (highlight.range.clone(), highlight.color))
20076    }
20077
20078    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20079    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20080    /// Allows to ignore certain kinds of highlights.
20081    pub fn highlighted_display_rows(
20082        &self,
20083        window: &mut Window,
20084        cx: &mut App,
20085    ) -> BTreeMap<DisplayRow, LineHighlight> {
20086        let snapshot = self.snapshot(window, cx);
20087        let mut used_highlight_orders = HashMap::default();
20088        self.highlighted_rows
20089            .iter()
20090            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20091            .fold(
20092                BTreeMap::<DisplayRow, LineHighlight>::new(),
20093                |mut unique_rows, highlight| {
20094                    let start = highlight.range.start.to_display_point(&snapshot);
20095                    let end = highlight.range.end.to_display_point(&snapshot);
20096                    let start_row = start.row().0;
20097                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20098                        && end.column() == 0
20099                    {
20100                        end.row().0.saturating_sub(1)
20101                    } else {
20102                        end.row().0
20103                    };
20104                    for row in start_row..=end_row {
20105                        let used_index =
20106                            used_highlight_orders.entry(row).or_insert(highlight.index);
20107                        if highlight.index >= *used_index {
20108                            *used_index = highlight.index;
20109                            unique_rows.insert(
20110                                DisplayRow(row),
20111                                LineHighlight {
20112                                    include_gutter: highlight.options.include_gutter,
20113                                    border: None,
20114                                    background: highlight.color.into(),
20115                                    type_id: Some(highlight.type_id),
20116                                },
20117                            );
20118                        }
20119                    }
20120                    unique_rows
20121                },
20122            )
20123    }
20124
20125    pub fn highlighted_display_row_for_autoscroll(
20126        &self,
20127        snapshot: &DisplaySnapshot,
20128    ) -> Option<DisplayRow> {
20129        self.highlighted_rows
20130            .values()
20131            .flat_map(|highlighted_rows| highlighted_rows.iter())
20132            .filter_map(|highlight| {
20133                if highlight.options.autoscroll {
20134                    Some(highlight.range.start.to_display_point(snapshot).row())
20135                } else {
20136                    None
20137                }
20138            })
20139            .min()
20140    }
20141
20142    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20143        self.highlight_background::<SearchWithinRange>(
20144            ranges,
20145            |colors| colors.colors().editor_document_highlight_read_background,
20146            cx,
20147        )
20148    }
20149
20150    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20151        self.breadcrumb_header = Some(new_header);
20152    }
20153
20154    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20155        self.clear_background_highlights::<SearchWithinRange>(cx);
20156    }
20157
20158    pub fn highlight_background<T: 'static>(
20159        &mut self,
20160        ranges: &[Range<Anchor>],
20161        color_fetcher: fn(&Theme) -> Hsla,
20162        cx: &mut Context<Self>,
20163    ) {
20164        self.background_highlights.insert(
20165            HighlightKey::Type(TypeId::of::<T>()),
20166            (color_fetcher, Arc::from(ranges)),
20167        );
20168        self.scrollbar_marker_state.dirty = true;
20169        cx.notify();
20170    }
20171
20172    pub fn highlight_background_key<T: 'static>(
20173        &mut self,
20174        key: usize,
20175        ranges: &[Range<Anchor>],
20176        color_fetcher: fn(&Theme) -> Hsla,
20177        cx: &mut Context<Self>,
20178    ) {
20179        self.background_highlights.insert(
20180            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20181            (color_fetcher, Arc::from(ranges)),
20182        );
20183        self.scrollbar_marker_state.dirty = true;
20184        cx.notify();
20185    }
20186
20187    pub fn clear_background_highlights<T: 'static>(
20188        &mut self,
20189        cx: &mut Context<Self>,
20190    ) -> Option<BackgroundHighlight> {
20191        let text_highlights = self
20192            .background_highlights
20193            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20194        if !text_highlights.1.is_empty() {
20195            self.scrollbar_marker_state.dirty = true;
20196            cx.notify();
20197        }
20198        Some(text_highlights)
20199    }
20200
20201    pub fn highlight_gutter<T: 'static>(
20202        &mut self,
20203        ranges: impl Into<Vec<Range<Anchor>>>,
20204        color_fetcher: fn(&App) -> Hsla,
20205        cx: &mut Context<Self>,
20206    ) {
20207        self.gutter_highlights
20208            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20209        cx.notify();
20210    }
20211
20212    pub fn clear_gutter_highlights<T: 'static>(
20213        &mut self,
20214        cx: &mut Context<Self>,
20215    ) -> Option<GutterHighlight> {
20216        cx.notify();
20217        self.gutter_highlights.remove(&TypeId::of::<T>())
20218    }
20219
20220    pub fn insert_gutter_highlight<T: 'static>(
20221        &mut self,
20222        range: Range<Anchor>,
20223        color_fetcher: fn(&App) -> Hsla,
20224        cx: &mut Context<Self>,
20225    ) {
20226        let snapshot = self.buffer().read(cx).snapshot(cx);
20227        let mut highlights = self
20228            .gutter_highlights
20229            .remove(&TypeId::of::<T>())
20230            .map(|(_, highlights)| highlights)
20231            .unwrap_or_default();
20232        let ix = highlights.binary_search_by(|highlight| {
20233            Ordering::Equal
20234                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20235                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20236        });
20237        if let Err(ix) = ix {
20238            highlights.insert(ix, range);
20239        }
20240        self.gutter_highlights
20241            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20242    }
20243
20244    pub fn remove_gutter_highlights<T: 'static>(
20245        &mut self,
20246        ranges_to_remove: Vec<Range<Anchor>>,
20247        cx: &mut Context<Self>,
20248    ) {
20249        let snapshot = self.buffer().read(cx).snapshot(cx);
20250        let Some((color_fetcher, mut gutter_highlights)) =
20251            self.gutter_highlights.remove(&TypeId::of::<T>())
20252        else {
20253            return;
20254        };
20255        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20256        gutter_highlights.retain(|highlight| {
20257            while let Some(range_to_remove) = ranges_to_remove.peek() {
20258                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20259                    Ordering::Less | Ordering::Equal => {
20260                        ranges_to_remove.next();
20261                    }
20262                    Ordering::Greater => {
20263                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20264                            Ordering::Less | Ordering::Equal => {
20265                                return false;
20266                            }
20267                            Ordering::Greater => break,
20268                        }
20269                    }
20270                }
20271            }
20272
20273            true
20274        });
20275        self.gutter_highlights
20276            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20277    }
20278
20279    #[cfg(feature = "test-support")]
20280    pub fn all_text_highlights(
20281        &self,
20282        window: &mut Window,
20283        cx: &mut Context<Self>,
20284    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20285        let snapshot = self.snapshot(window, cx);
20286        self.display_map.update(cx, |display_map, _| {
20287            display_map
20288                .all_text_highlights()
20289                .map(|highlight| {
20290                    let (style, ranges) = highlight.as_ref();
20291                    (
20292                        *style,
20293                        ranges
20294                            .iter()
20295                            .map(|range| range.clone().to_display_points(&snapshot))
20296                            .collect(),
20297                    )
20298                })
20299                .collect()
20300        })
20301    }
20302
20303    #[cfg(feature = "test-support")]
20304    pub fn all_text_background_highlights(
20305        &self,
20306        window: &mut Window,
20307        cx: &mut Context<Self>,
20308    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20309        let snapshot = self.snapshot(window, cx);
20310        let buffer = &snapshot.buffer_snapshot;
20311        let start = buffer.anchor_before(0);
20312        let end = buffer.anchor_after(buffer.len());
20313        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20314    }
20315
20316    #[cfg(any(test, feature = "test-support"))]
20317    pub fn sorted_background_highlights_in_range(
20318        &self,
20319        search_range: Range<Anchor>,
20320        display_snapshot: &DisplaySnapshot,
20321        theme: &Theme,
20322    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20323        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20324        res.sort_by(|a, b| {
20325            a.0.start
20326                .cmp(&b.0.start)
20327                .then_with(|| a.0.end.cmp(&b.0.end))
20328                .then_with(|| a.1.cmp(&b.1))
20329        });
20330        res
20331    }
20332
20333    #[cfg(feature = "test-support")]
20334    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20335        let snapshot = self.buffer().read(cx).snapshot(cx);
20336
20337        let highlights = self
20338            .background_highlights
20339            .get(&HighlightKey::Type(TypeId::of::<
20340                items::BufferSearchHighlights,
20341            >()));
20342
20343        if let Some((_color, ranges)) = highlights {
20344            ranges
20345                .iter()
20346                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20347                .collect_vec()
20348        } else {
20349            vec![]
20350        }
20351    }
20352
20353    fn document_highlights_for_position<'a>(
20354        &'a self,
20355        position: Anchor,
20356        buffer: &'a MultiBufferSnapshot,
20357    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20358        let read_highlights = self
20359            .background_highlights
20360            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20361            .map(|h| &h.1);
20362        let write_highlights = self
20363            .background_highlights
20364            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20365            .map(|h| &h.1);
20366        let left_position = position.bias_left(buffer);
20367        let right_position = position.bias_right(buffer);
20368        read_highlights
20369            .into_iter()
20370            .chain(write_highlights)
20371            .flat_map(move |ranges| {
20372                let start_ix = match ranges.binary_search_by(|probe| {
20373                    let cmp = probe.end.cmp(&left_position, buffer);
20374                    if cmp.is_ge() {
20375                        Ordering::Greater
20376                    } else {
20377                        Ordering::Less
20378                    }
20379                }) {
20380                    Ok(i) | Err(i) => i,
20381                };
20382
20383                ranges[start_ix..]
20384                    .iter()
20385                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20386            })
20387    }
20388
20389    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20390        self.background_highlights
20391            .get(&HighlightKey::Type(TypeId::of::<T>()))
20392            .is_some_and(|(_, highlights)| !highlights.is_empty())
20393    }
20394
20395    /// Returns all background highlights for a given range.
20396    ///
20397    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20398    pub fn background_highlights_in_range(
20399        &self,
20400        search_range: Range<Anchor>,
20401        display_snapshot: &DisplaySnapshot,
20402        theme: &Theme,
20403    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20404        let mut results = Vec::new();
20405        for (color_fetcher, ranges) in self.background_highlights.values() {
20406            let color = color_fetcher(theme);
20407            let start_ix = match ranges.binary_search_by(|probe| {
20408                let cmp = probe
20409                    .end
20410                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20411                if cmp.is_gt() {
20412                    Ordering::Greater
20413                } else {
20414                    Ordering::Less
20415                }
20416            }) {
20417                Ok(i) | Err(i) => i,
20418            };
20419            for range in &ranges[start_ix..] {
20420                if range
20421                    .start
20422                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20423                    .is_ge()
20424                {
20425                    break;
20426                }
20427
20428                let start = range.start.to_display_point(display_snapshot);
20429                let end = range.end.to_display_point(display_snapshot);
20430                results.push((start..end, color))
20431            }
20432        }
20433        results
20434    }
20435
20436    pub fn gutter_highlights_in_range(
20437        &self,
20438        search_range: Range<Anchor>,
20439        display_snapshot: &DisplaySnapshot,
20440        cx: &App,
20441    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20442        let mut results = Vec::new();
20443        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20444            let color = color_fetcher(cx);
20445            let start_ix = match ranges.binary_search_by(|probe| {
20446                let cmp = probe
20447                    .end
20448                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20449                if cmp.is_gt() {
20450                    Ordering::Greater
20451                } else {
20452                    Ordering::Less
20453                }
20454            }) {
20455                Ok(i) | Err(i) => i,
20456            };
20457            for range in &ranges[start_ix..] {
20458                if range
20459                    .start
20460                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20461                    .is_ge()
20462                {
20463                    break;
20464                }
20465
20466                let start = range.start.to_display_point(display_snapshot);
20467                let end = range.end.to_display_point(display_snapshot);
20468                results.push((start..end, color))
20469            }
20470        }
20471        results
20472    }
20473
20474    /// Get the text ranges corresponding to the redaction query
20475    pub fn redacted_ranges(
20476        &self,
20477        search_range: Range<Anchor>,
20478        display_snapshot: &DisplaySnapshot,
20479        cx: &App,
20480    ) -> Vec<Range<DisplayPoint>> {
20481        display_snapshot
20482            .buffer_snapshot
20483            .redacted_ranges(search_range, |file| {
20484                if let Some(file) = file {
20485                    file.is_private()
20486                        && EditorSettings::get(
20487                            Some(SettingsLocation {
20488                                worktree_id: file.worktree_id(cx),
20489                                path: file.path().as_ref(),
20490                            }),
20491                            cx,
20492                        )
20493                        .redact_private_values
20494                } else {
20495                    false
20496                }
20497            })
20498            .map(|range| {
20499                range.start.to_display_point(display_snapshot)
20500                    ..range.end.to_display_point(display_snapshot)
20501            })
20502            .collect()
20503    }
20504
20505    pub fn highlight_text_key<T: 'static>(
20506        &mut self,
20507        key: usize,
20508        ranges: Vec<Range<Anchor>>,
20509        style: HighlightStyle,
20510        cx: &mut Context<Self>,
20511    ) {
20512        self.display_map.update(cx, |map, _| {
20513            map.highlight_text(
20514                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20515                ranges,
20516                style,
20517            );
20518        });
20519        cx.notify();
20520    }
20521
20522    pub fn highlight_text<T: 'static>(
20523        &mut self,
20524        ranges: Vec<Range<Anchor>>,
20525        style: HighlightStyle,
20526        cx: &mut Context<Self>,
20527    ) {
20528        self.display_map.update(cx, |map, _| {
20529            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20530        });
20531        cx.notify();
20532    }
20533
20534    pub(crate) fn highlight_inlays<T: 'static>(
20535        &mut self,
20536        highlights: Vec<InlayHighlight>,
20537        style: HighlightStyle,
20538        cx: &mut Context<Self>,
20539    ) {
20540        self.display_map.update(cx, |map, _| {
20541            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20542        });
20543        cx.notify();
20544    }
20545
20546    pub fn text_highlights<'a, T: 'static>(
20547        &'a self,
20548        cx: &'a App,
20549    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20550        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20551    }
20552
20553    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20554        let cleared = self
20555            .display_map
20556            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20557        if cleared {
20558            cx.notify();
20559        }
20560    }
20561
20562    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20563        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20564            && self.focus_handle.is_focused(window)
20565    }
20566
20567    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20568        self.show_cursor_when_unfocused = is_enabled;
20569        cx.notify();
20570    }
20571
20572    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20573        cx.notify();
20574    }
20575
20576    fn on_debug_session_event(
20577        &mut self,
20578        _session: Entity<Session>,
20579        event: &SessionEvent,
20580        cx: &mut Context<Self>,
20581    ) {
20582        if let SessionEvent::InvalidateInlineValue = event {
20583            self.refresh_inline_values(cx);
20584        }
20585    }
20586
20587    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20588        let Some(project) = self.project.clone() else {
20589            return;
20590        };
20591
20592        if !self.inline_value_cache.enabled {
20593            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20594            self.splice_inlays(&inlays, Vec::new(), cx);
20595            return;
20596        }
20597
20598        let current_execution_position = self
20599            .highlighted_rows
20600            .get(&TypeId::of::<ActiveDebugLine>())
20601            .and_then(|lines| lines.last().map(|line| line.range.end));
20602
20603        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20604            let inline_values = editor
20605                .update(cx, |editor, cx| {
20606                    let Some(current_execution_position) = current_execution_position else {
20607                        return Some(Task::ready(Ok(Vec::new())));
20608                    };
20609
20610                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20611                        let snapshot = buffer.snapshot(cx);
20612
20613                        let excerpt = snapshot.excerpt_containing(
20614                            current_execution_position..current_execution_position,
20615                        )?;
20616
20617                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20618                    })?;
20619
20620                    let range =
20621                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20622
20623                    project.inline_values(buffer, range, cx)
20624                })
20625                .ok()
20626                .flatten()?
20627                .await
20628                .context("refreshing debugger inlays")
20629                .log_err()?;
20630
20631            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20632
20633            for (buffer_id, inline_value) in inline_values
20634                .into_iter()
20635                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20636            {
20637                buffer_inline_values
20638                    .entry(buffer_id)
20639                    .or_default()
20640                    .push(inline_value);
20641            }
20642
20643            editor
20644                .update(cx, |editor, cx| {
20645                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20646                    let mut new_inlays = Vec::default();
20647
20648                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20649                        let buffer_id = buffer_snapshot.remote_id();
20650                        buffer_inline_values
20651                            .get(&buffer_id)
20652                            .into_iter()
20653                            .flatten()
20654                            .for_each(|hint| {
20655                                let inlay = Inlay::debugger(
20656                                    post_inc(&mut editor.next_inlay_id),
20657                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20658                                    hint.text(),
20659                                );
20660                                if !inlay.text().chars().contains(&'\n') {
20661                                    new_inlays.push(inlay);
20662                                }
20663                            });
20664                    }
20665
20666                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20667                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20668
20669                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20670                })
20671                .ok()?;
20672            Some(())
20673        });
20674    }
20675
20676    fn on_buffer_event(
20677        &mut self,
20678        multibuffer: &Entity<MultiBuffer>,
20679        event: &multi_buffer::Event,
20680        window: &mut Window,
20681        cx: &mut Context<Self>,
20682    ) {
20683        match event {
20684            multi_buffer::Event::Edited {
20685                singleton_buffer_edited,
20686                edited_buffer,
20687            } => {
20688                self.scrollbar_marker_state.dirty = true;
20689                self.active_indent_guides_state.dirty = true;
20690                self.refresh_active_diagnostics(cx);
20691                self.refresh_code_actions(window, cx);
20692                self.refresh_selected_text_highlights(true, window, cx);
20693                self.refresh_single_line_folds(window, cx);
20694                refresh_matching_bracket_highlights(self, window, cx);
20695                if self.has_active_edit_prediction() {
20696                    self.update_visible_edit_prediction(window, cx);
20697                }
20698                if let Some(project) = self.project.as_ref()
20699                    && let Some(edited_buffer) = edited_buffer
20700                {
20701                    project.update(cx, |project, cx| {
20702                        self.registered_buffers
20703                            .entry(edited_buffer.read(cx).remote_id())
20704                            .or_insert_with(|| {
20705                                project.register_buffer_with_language_servers(edited_buffer, cx)
20706                            });
20707                    });
20708                }
20709                cx.emit(EditorEvent::BufferEdited);
20710                cx.emit(SearchEvent::MatchesInvalidated);
20711
20712                if let Some(buffer) = edited_buffer {
20713                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20714                }
20715
20716                if *singleton_buffer_edited {
20717                    if let Some(buffer) = edited_buffer
20718                        && buffer.read(cx).file().is_none()
20719                    {
20720                        cx.emit(EditorEvent::TitleChanged);
20721                    }
20722                    if let Some(project) = &self.project {
20723                        #[allow(clippy::mutable_key_type)]
20724                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20725                            multibuffer
20726                                .all_buffers()
20727                                .into_iter()
20728                                .filter_map(|buffer| {
20729                                    buffer.update(cx, |buffer, cx| {
20730                                        let language = buffer.language()?;
20731                                        let should_discard = project.update(cx, |project, cx| {
20732                                            project.is_local()
20733                                                && !project.has_language_servers_for(buffer, cx)
20734                                        });
20735                                        should_discard.not().then_some(language.clone())
20736                                    })
20737                                })
20738                                .collect::<HashSet<_>>()
20739                        });
20740                        if !languages_affected.is_empty() {
20741                            self.refresh_inlay_hints(
20742                                InlayHintRefreshReason::BufferEdited(languages_affected),
20743                                cx,
20744                            );
20745                        }
20746                    }
20747                }
20748
20749                let Some(project) = &self.project else { return };
20750                let (telemetry, is_via_ssh) = {
20751                    let project = project.read(cx);
20752                    let telemetry = project.client().telemetry().clone();
20753                    let is_via_ssh = project.is_via_remote_server();
20754                    (telemetry, is_via_ssh)
20755                };
20756                refresh_linked_ranges(self, window, cx);
20757                telemetry.log_edit_event("editor", is_via_ssh);
20758            }
20759            multi_buffer::Event::ExcerptsAdded {
20760                buffer,
20761                predecessor,
20762                excerpts,
20763            } => {
20764                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20765                let buffer_id = buffer.read(cx).remote_id();
20766                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20767                    && let Some(project) = &self.project
20768                {
20769                    update_uncommitted_diff_for_buffer(
20770                        cx.entity(),
20771                        project,
20772                        [buffer.clone()],
20773                        self.buffer.clone(),
20774                        cx,
20775                    )
20776                    .detach();
20777                }
20778                if self.active_diagnostics != ActiveDiagnostic::All {
20779                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20780                }
20781                cx.emit(EditorEvent::ExcerptsAdded {
20782                    buffer: buffer.clone(),
20783                    predecessor: *predecessor,
20784                    excerpts: excerpts.clone(),
20785                });
20786                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20787            }
20788            multi_buffer::Event::ExcerptsRemoved {
20789                ids,
20790                removed_buffer_ids,
20791            } => {
20792                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20793                let buffer = self.buffer.read(cx);
20794                self.registered_buffers
20795                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20796                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20797                cx.emit(EditorEvent::ExcerptsRemoved {
20798                    ids: ids.clone(),
20799                    removed_buffer_ids: removed_buffer_ids.clone(),
20800                });
20801            }
20802            multi_buffer::Event::ExcerptsEdited {
20803                excerpt_ids,
20804                buffer_ids,
20805            } => {
20806                self.display_map.update(cx, |map, cx| {
20807                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20808                });
20809                cx.emit(EditorEvent::ExcerptsEdited {
20810                    ids: excerpt_ids.clone(),
20811                });
20812            }
20813            multi_buffer::Event::ExcerptsExpanded { ids } => {
20814                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20815                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20816            }
20817            multi_buffer::Event::Reparsed(buffer_id) => {
20818                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20819                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20820
20821                cx.emit(EditorEvent::Reparsed(*buffer_id));
20822            }
20823            multi_buffer::Event::DiffHunksToggled => {
20824                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20825            }
20826            multi_buffer::Event::LanguageChanged(buffer_id) => {
20827                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20828                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20829                cx.emit(EditorEvent::Reparsed(*buffer_id));
20830                cx.notify();
20831            }
20832            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20833            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20834            multi_buffer::Event::FileHandleChanged
20835            | multi_buffer::Event::Reloaded
20836            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20837            multi_buffer::Event::DiagnosticsUpdated => {
20838                self.update_diagnostics_state(window, cx);
20839            }
20840            _ => {}
20841        };
20842    }
20843
20844    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20845        if !self.diagnostics_enabled() {
20846            return;
20847        }
20848        self.refresh_active_diagnostics(cx);
20849        self.refresh_inline_diagnostics(true, window, cx);
20850        self.scrollbar_marker_state.dirty = true;
20851        cx.notify();
20852    }
20853
20854    pub fn start_temporary_diff_override(&mut self) {
20855        self.load_diff_task.take();
20856        self.temporary_diff_override = true;
20857    }
20858
20859    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20860        self.temporary_diff_override = false;
20861        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20862        self.buffer.update(cx, |buffer, cx| {
20863            buffer.set_all_diff_hunks_collapsed(cx);
20864        });
20865
20866        if let Some(project) = self.project.clone() {
20867            self.load_diff_task = Some(
20868                update_uncommitted_diff_for_buffer(
20869                    cx.entity(),
20870                    &project,
20871                    self.buffer.read(cx).all_buffers(),
20872                    self.buffer.clone(),
20873                    cx,
20874                )
20875                .shared(),
20876            );
20877        }
20878    }
20879
20880    fn on_display_map_changed(
20881        &mut self,
20882        _: Entity<DisplayMap>,
20883        _: &mut Window,
20884        cx: &mut Context<Self>,
20885    ) {
20886        cx.notify();
20887    }
20888
20889    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20890        if self.diagnostics_enabled() {
20891            let new_severity = EditorSettings::get_global(cx)
20892                .diagnostics_max_severity
20893                .unwrap_or(DiagnosticSeverity::Hint);
20894            self.set_max_diagnostics_severity(new_severity, cx);
20895        }
20896        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20897        self.update_edit_prediction_settings(cx);
20898        self.refresh_edit_prediction(true, false, window, cx);
20899        self.refresh_inline_values(cx);
20900        self.refresh_inlay_hints(
20901            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20902                self.selections.newest_anchor().head(),
20903                &self.buffer.read(cx).snapshot(cx),
20904                cx,
20905            )),
20906            cx,
20907        );
20908
20909        let old_cursor_shape = self.cursor_shape;
20910        let old_show_breadcrumbs = self.show_breadcrumbs;
20911
20912        {
20913            let editor_settings = EditorSettings::get_global(cx);
20914            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20915            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20916            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20917            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20918        }
20919
20920        if old_cursor_shape != self.cursor_shape {
20921            cx.emit(EditorEvent::CursorShapeChanged);
20922        }
20923
20924        if old_show_breadcrumbs != self.show_breadcrumbs {
20925            cx.emit(EditorEvent::BreadcrumbsChanged);
20926        }
20927
20928        let project_settings = ProjectSettings::get_global(cx);
20929        self.serialize_dirty_buffers =
20930            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20931
20932        if self.mode.is_full() {
20933            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20934            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20935            if self.show_inline_diagnostics != show_inline_diagnostics {
20936                self.show_inline_diagnostics = show_inline_diagnostics;
20937                self.refresh_inline_diagnostics(false, window, cx);
20938            }
20939
20940            if self.git_blame_inline_enabled != inline_blame_enabled {
20941                self.toggle_git_blame_inline_internal(false, window, cx);
20942            }
20943
20944            let minimap_settings = EditorSettings::get_global(cx).minimap;
20945            if self.minimap_visibility != MinimapVisibility::Disabled {
20946                if self.minimap_visibility.settings_visibility()
20947                    != minimap_settings.minimap_enabled()
20948                {
20949                    self.set_minimap_visibility(
20950                        MinimapVisibility::for_mode(self.mode(), cx),
20951                        window,
20952                        cx,
20953                    );
20954                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20955                    minimap_entity.update(cx, |minimap_editor, cx| {
20956                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20957                    })
20958                }
20959            }
20960        }
20961
20962        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20963            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20964        }) {
20965            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20966                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20967            }
20968            self.refresh_colors(false, None, window, cx);
20969        }
20970
20971        cx.notify();
20972    }
20973
20974    pub fn set_searchable(&mut self, searchable: bool) {
20975        self.searchable = searchable;
20976    }
20977
20978    pub fn searchable(&self) -> bool {
20979        self.searchable
20980    }
20981
20982    fn open_proposed_changes_editor(
20983        &mut self,
20984        _: &OpenProposedChangesEditor,
20985        window: &mut Window,
20986        cx: &mut Context<Self>,
20987    ) {
20988        let Some(workspace) = self.workspace() else {
20989            cx.propagate();
20990            return;
20991        };
20992
20993        let selections = self.selections.all::<usize>(cx);
20994        let multi_buffer = self.buffer.read(cx);
20995        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20996        let mut new_selections_by_buffer = HashMap::default();
20997        for selection in selections {
20998            for (buffer, range, _) in
20999                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21000            {
21001                let mut range = range.to_point(buffer);
21002                range.start.column = 0;
21003                range.end.column = buffer.line_len(range.end.row);
21004                new_selections_by_buffer
21005                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21006                    .or_insert(Vec::new())
21007                    .push(range)
21008            }
21009        }
21010
21011        let proposed_changes_buffers = new_selections_by_buffer
21012            .into_iter()
21013            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21014            .collect::<Vec<_>>();
21015        let proposed_changes_editor = cx.new(|cx| {
21016            ProposedChangesEditor::new(
21017                "Proposed changes",
21018                proposed_changes_buffers,
21019                self.project.clone(),
21020                window,
21021                cx,
21022            )
21023        });
21024
21025        window.defer(cx, move |window, cx| {
21026            workspace.update(cx, |workspace, cx| {
21027                workspace.active_pane().update(cx, |pane, cx| {
21028                    pane.add_item(
21029                        Box::new(proposed_changes_editor),
21030                        true,
21031                        true,
21032                        None,
21033                        window,
21034                        cx,
21035                    );
21036                });
21037            });
21038        });
21039    }
21040
21041    pub fn open_excerpts_in_split(
21042        &mut self,
21043        _: &OpenExcerptsSplit,
21044        window: &mut Window,
21045        cx: &mut Context<Self>,
21046    ) {
21047        self.open_excerpts_common(None, true, window, cx)
21048    }
21049
21050    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21051        self.open_excerpts_common(None, false, window, cx)
21052    }
21053
21054    fn open_excerpts_common(
21055        &mut self,
21056        jump_data: Option<JumpData>,
21057        split: bool,
21058        window: &mut Window,
21059        cx: &mut Context<Self>,
21060    ) {
21061        let Some(workspace) = self.workspace() else {
21062            cx.propagate();
21063            return;
21064        };
21065
21066        if self.buffer.read(cx).is_singleton() {
21067            cx.propagate();
21068            return;
21069        }
21070
21071        let mut new_selections_by_buffer = HashMap::default();
21072        match &jump_data {
21073            Some(JumpData::MultiBufferPoint {
21074                excerpt_id,
21075                position,
21076                anchor,
21077                line_offset_from_top,
21078            }) => {
21079                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21080                if let Some(buffer) = multi_buffer_snapshot
21081                    .buffer_id_for_excerpt(*excerpt_id)
21082                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21083                {
21084                    let buffer_snapshot = buffer.read(cx).snapshot();
21085                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21086                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21087                    } else {
21088                        buffer_snapshot.clip_point(*position, Bias::Left)
21089                    };
21090                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21091                    new_selections_by_buffer.insert(
21092                        buffer,
21093                        (
21094                            vec![jump_to_offset..jump_to_offset],
21095                            Some(*line_offset_from_top),
21096                        ),
21097                    );
21098                }
21099            }
21100            Some(JumpData::MultiBufferRow {
21101                row,
21102                line_offset_from_top,
21103            }) => {
21104                let point = MultiBufferPoint::new(row.0, 0);
21105                if let Some((buffer, buffer_point, _)) =
21106                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21107                {
21108                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21109                    new_selections_by_buffer
21110                        .entry(buffer)
21111                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21112                        .0
21113                        .push(buffer_offset..buffer_offset)
21114                }
21115            }
21116            None => {
21117                let selections = self.selections.all::<usize>(cx);
21118                let multi_buffer = self.buffer.read(cx);
21119                for selection in selections {
21120                    for (snapshot, range, _, anchor) in multi_buffer
21121                        .snapshot(cx)
21122                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21123                    {
21124                        if let Some(anchor) = anchor {
21125                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21126                            else {
21127                                continue;
21128                            };
21129                            let offset = text::ToOffset::to_offset(
21130                                &anchor.text_anchor,
21131                                &buffer_handle.read(cx).snapshot(),
21132                            );
21133                            let range = offset..offset;
21134                            new_selections_by_buffer
21135                                .entry(buffer_handle)
21136                                .or_insert((Vec::new(), None))
21137                                .0
21138                                .push(range)
21139                        } else {
21140                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21141                            else {
21142                                continue;
21143                            };
21144                            new_selections_by_buffer
21145                                .entry(buffer_handle)
21146                                .or_insert((Vec::new(), None))
21147                                .0
21148                                .push(range)
21149                        }
21150                    }
21151                }
21152            }
21153        }
21154
21155        new_selections_by_buffer
21156            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21157
21158        if new_selections_by_buffer.is_empty() {
21159            return;
21160        }
21161
21162        // We defer the pane interaction because we ourselves are a workspace item
21163        // and activating a new item causes the pane to call a method on us reentrantly,
21164        // which panics if we're on the stack.
21165        window.defer(cx, move |window, cx| {
21166            workspace.update(cx, |workspace, cx| {
21167                let pane = if split {
21168                    workspace.adjacent_pane(window, cx)
21169                } else {
21170                    workspace.active_pane().clone()
21171                };
21172
21173                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21174                    let editor = buffer
21175                        .read(cx)
21176                        .file()
21177                        .is_none()
21178                        .then(|| {
21179                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21180                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21181                            // Instead, we try to activate the existing editor in the pane first.
21182                            let (editor, pane_item_index) =
21183                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21184                                    let editor = item.downcast::<Editor>()?;
21185                                    let singleton_buffer =
21186                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21187                                    if singleton_buffer == buffer {
21188                                        Some((editor, i))
21189                                    } else {
21190                                        None
21191                                    }
21192                                })?;
21193                            pane.update(cx, |pane, cx| {
21194                                pane.activate_item(pane_item_index, true, true, window, cx)
21195                            });
21196                            Some(editor)
21197                        })
21198                        .flatten()
21199                        .unwrap_or_else(|| {
21200                            workspace.open_project_item::<Self>(
21201                                pane.clone(),
21202                                buffer,
21203                                true,
21204                                true,
21205                                window,
21206                                cx,
21207                            )
21208                        });
21209
21210                    editor.update(cx, |editor, cx| {
21211                        let autoscroll = match scroll_offset {
21212                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21213                            None => Autoscroll::newest(),
21214                        };
21215                        let nav_history = editor.nav_history.take();
21216                        editor.change_selections(
21217                            SelectionEffects::scroll(autoscroll),
21218                            window,
21219                            cx,
21220                            |s| {
21221                                s.select_ranges(ranges);
21222                            },
21223                        );
21224                        editor.nav_history = nav_history;
21225                    });
21226                }
21227            })
21228        });
21229    }
21230
21231    // For now, don't allow opening excerpts in buffers that aren't backed by
21232    // regular project files.
21233    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21234        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21235    }
21236
21237    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21238        let snapshot = self.buffer.read(cx).read(cx);
21239        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21240        Some(
21241            ranges
21242                .iter()
21243                .map(move |range| {
21244                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21245                })
21246                .collect(),
21247        )
21248    }
21249
21250    fn selection_replacement_ranges(
21251        &self,
21252        range: Range<OffsetUtf16>,
21253        cx: &mut App,
21254    ) -> Vec<Range<OffsetUtf16>> {
21255        let selections = self.selections.all::<OffsetUtf16>(cx);
21256        let newest_selection = selections
21257            .iter()
21258            .max_by_key(|selection| selection.id)
21259            .unwrap();
21260        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21261        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21262        let snapshot = self.buffer.read(cx).read(cx);
21263        selections
21264            .into_iter()
21265            .map(|mut selection| {
21266                selection.start.0 =
21267                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21268                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21269                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21270                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21271            })
21272            .collect()
21273    }
21274
21275    fn report_editor_event(
21276        &self,
21277        reported_event: ReportEditorEvent,
21278        file_extension: Option<String>,
21279        cx: &App,
21280    ) {
21281        if cfg!(any(test, feature = "test-support")) {
21282            return;
21283        }
21284
21285        let Some(project) = &self.project else { return };
21286
21287        // If None, we are in a file without an extension
21288        let file = self
21289            .buffer
21290            .read(cx)
21291            .as_singleton()
21292            .and_then(|b| b.read(cx).file());
21293        let file_extension = file_extension.or(file
21294            .as_ref()
21295            .and_then(|file| Path::new(file.file_name(cx)).extension())
21296            .and_then(|e| e.to_str())
21297            .map(|a| a.to_string()));
21298
21299        let vim_mode = vim_enabled(cx);
21300
21301        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21302        let copilot_enabled = edit_predictions_provider
21303            == language::language_settings::EditPredictionProvider::Copilot;
21304        let copilot_enabled_for_language = self
21305            .buffer
21306            .read(cx)
21307            .language_settings(cx)
21308            .show_edit_predictions;
21309
21310        let project = project.read(cx);
21311        let event_type = reported_event.event_type();
21312
21313        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21314            telemetry::event!(
21315                event_type,
21316                type = if auto_saved {"autosave"} else {"manual"},
21317                file_extension,
21318                vim_mode,
21319                copilot_enabled,
21320                copilot_enabled_for_language,
21321                edit_predictions_provider,
21322                is_via_ssh = project.is_via_remote_server(),
21323            );
21324        } else {
21325            telemetry::event!(
21326                event_type,
21327                file_extension,
21328                vim_mode,
21329                copilot_enabled,
21330                copilot_enabled_for_language,
21331                edit_predictions_provider,
21332                is_via_ssh = project.is_via_remote_server(),
21333            );
21334        };
21335    }
21336
21337    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21338    /// with each line being an array of {text, highlight} objects.
21339    fn copy_highlight_json(
21340        &mut self,
21341        _: &CopyHighlightJson,
21342        window: &mut Window,
21343        cx: &mut Context<Self>,
21344    ) {
21345        #[derive(Serialize)]
21346        struct Chunk<'a> {
21347            text: String,
21348            highlight: Option<&'a str>,
21349        }
21350
21351        let snapshot = self.buffer.read(cx).snapshot(cx);
21352        let range = self
21353            .selected_text_range(false, window, cx)
21354            .and_then(|selection| {
21355                if selection.range.is_empty() {
21356                    None
21357                } else {
21358                    Some(selection.range)
21359                }
21360            })
21361            .unwrap_or_else(|| 0..snapshot.len());
21362
21363        let chunks = snapshot.chunks(range, true);
21364        let mut lines = Vec::new();
21365        let mut line: VecDeque<Chunk> = VecDeque::new();
21366
21367        let Some(style) = self.style.as_ref() else {
21368            return;
21369        };
21370
21371        for chunk in chunks {
21372            let highlight = chunk
21373                .syntax_highlight_id
21374                .and_then(|id| id.name(&style.syntax));
21375            let mut chunk_lines = chunk.text.split('\n').peekable();
21376            while let Some(text) = chunk_lines.next() {
21377                let mut merged_with_last_token = false;
21378                if let Some(last_token) = line.back_mut()
21379                    && last_token.highlight == highlight
21380                {
21381                    last_token.text.push_str(text);
21382                    merged_with_last_token = true;
21383                }
21384
21385                if !merged_with_last_token {
21386                    line.push_back(Chunk {
21387                        text: text.into(),
21388                        highlight,
21389                    });
21390                }
21391
21392                if chunk_lines.peek().is_some() {
21393                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21394                        line.pop_front();
21395                    }
21396                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21397                        line.pop_back();
21398                    }
21399
21400                    lines.push(mem::take(&mut line));
21401                }
21402            }
21403        }
21404
21405        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21406            return;
21407        };
21408        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21409    }
21410
21411    pub fn open_context_menu(
21412        &mut self,
21413        _: &OpenContextMenu,
21414        window: &mut Window,
21415        cx: &mut Context<Self>,
21416    ) {
21417        self.request_autoscroll(Autoscroll::newest(), cx);
21418        let position = self.selections.newest_display(cx).start;
21419        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21420    }
21421
21422    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21423        &self.inlay_hint_cache
21424    }
21425
21426    pub fn replay_insert_event(
21427        &mut self,
21428        text: &str,
21429        relative_utf16_range: Option<Range<isize>>,
21430        window: &mut Window,
21431        cx: &mut Context<Self>,
21432    ) {
21433        if !self.input_enabled {
21434            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21435            return;
21436        }
21437        if let Some(relative_utf16_range) = relative_utf16_range {
21438            let selections = self.selections.all::<OffsetUtf16>(cx);
21439            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21440                let new_ranges = selections.into_iter().map(|range| {
21441                    let start = OffsetUtf16(
21442                        range
21443                            .head()
21444                            .0
21445                            .saturating_add_signed(relative_utf16_range.start),
21446                    );
21447                    let end = OffsetUtf16(
21448                        range
21449                            .head()
21450                            .0
21451                            .saturating_add_signed(relative_utf16_range.end),
21452                    );
21453                    start..end
21454                });
21455                s.select_ranges(new_ranges);
21456            });
21457        }
21458
21459        self.handle_input(text, window, cx);
21460    }
21461
21462    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21463        let Some(provider) = self.semantics_provider.as_ref() else {
21464            return false;
21465        };
21466
21467        let mut supports = false;
21468        self.buffer().update(cx, |this, cx| {
21469            this.for_each_buffer(|buffer| {
21470                supports |= provider.supports_inlay_hints(buffer, cx);
21471            });
21472        });
21473
21474        supports
21475    }
21476
21477    pub fn is_focused(&self, window: &Window) -> bool {
21478        self.focus_handle.is_focused(window)
21479    }
21480
21481    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21482        cx.emit(EditorEvent::Focused);
21483
21484        if let Some(descendant) = self
21485            .last_focused_descendant
21486            .take()
21487            .and_then(|descendant| descendant.upgrade())
21488        {
21489            window.focus(&descendant);
21490        } else {
21491            if let Some(blame) = self.blame.as_ref() {
21492                blame.update(cx, GitBlame::focus)
21493            }
21494
21495            self.blink_manager.update(cx, BlinkManager::enable);
21496            self.show_cursor_names(window, cx);
21497            self.buffer.update(cx, |buffer, cx| {
21498                buffer.finalize_last_transaction(cx);
21499                if self.leader_id.is_none() {
21500                    buffer.set_active_selections(
21501                        &self.selections.disjoint_anchors_arc(),
21502                        self.selections.line_mode(),
21503                        self.cursor_shape,
21504                        cx,
21505                    );
21506                }
21507            });
21508        }
21509    }
21510
21511    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21512        cx.emit(EditorEvent::FocusedIn)
21513    }
21514
21515    fn handle_focus_out(
21516        &mut self,
21517        event: FocusOutEvent,
21518        _window: &mut Window,
21519        cx: &mut Context<Self>,
21520    ) {
21521        if event.blurred != self.focus_handle {
21522            self.last_focused_descendant = Some(event.blurred);
21523        }
21524        self.selection_drag_state = SelectionDragState::None;
21525        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21526    }
21527
21528    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21529        self.blink_manager.update(cx, BlinkManager::disable);
21530        self.buffer
21531            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21532
21533        if let Some(blame) = self.blame.as_ref() {
21534            blame.update(cx, GitBlame::blur)
21535        }
21536        if !self.hover_state.focused(window, cx) {
21537            hide_hover(self, cx);
21538        }
21539        if !self
21540            .context_menu
21541            .borrow()
21542            .as_ref()
21543            .is_some_and(|context_menu| context_menu.focused(window, cx))
21544        {
21545            self.hide_context_menu(window, cx);
21546        }
21547        self.take_active_edit_prediction(cx);
21548        cx.emit(EditorEvent::Blurred);
21549        cx.notify();
21550    }
21551
21552    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21553        let mut pending: String = window
21554            .pending_input_keystrokes()
21555            .into_iter()
21556            .flatten()
21557            .filter_map(|keystroke| {
21558                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21559                    keystroke.key_char.clone()
21560                } else {
21561                    None
21562                }
21563            })
21564            .collect();
21565
21566        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21567            pending = "".to_string();
21568        }
21569
21570        let existing_pending = self
21571            .text_highlights::<PendingInput>(cx)
21572            .map(|(_, ranges)| ranges.to_vec());
21573        if existing_pending.is_none() && pending.is_empty() {
21574            return;
21575        }
21576        let transaction =
21577            self.transact(window, cx, |this, window, cx| {
21578                let selections = this.selections.all::<usize>(cx);
21579                let edits = selections
21580                    .iter()
21581                    .map(|selection| (selection.end..selection.end, pending.clone()));
21582                this.edit(edits, cx);
21583                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21584                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21585                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21586                    }));
21587                });
21588                if let Some(existing_ranges) = existing_pending {
21589                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21590                    this.edit(edits, cx);
21591                }
21592            });
21593
21594        let snapshot = self.snapshot(window, cx);
21595        let ranges = self
21596            .selections
21597            .all::<usize>(cx)
21598            .into_iter()
21599            .map(|selection| {
21600                snapshot.buffer_snapshot.anchor_after(selection.end)
21601                    ..snapshot
21602                        .buffer_snapshot
21603                        .anchor_before(selection.end + pending.len())
21604            })
21605            .collect();
21606
21607        if pending.is_empty() {
21608            self.clear_highlights::<PendingInput>(cx);
21609        } else {
21610            self.highlight_text::<PendingInput>(
21611                ranges,
21612                HighlightStyle {
21613                    underline: Some(UnderlineStyle {
21614                        thickness: px(1.),
21615                        color: None,
21616                        wavy: false,
21617                    }),
21618                    ..Default::default()
21619                },
21620                cx,
21621            );
21622        }
21623
21624        self.ime_transaction = self.ime_transaction.or(transaction);
21625        if let Some(transaction) = self.ime_transaction {
21626            self.buffer.update(cx, |buffer, cx| {
21627                buffer.group_until_transaction(transaction, cx);
21628            });
21629        }
21630
21631        if self.text_highlights::<PendingInput>(cx).is_none() {
21632            self.ime_transaction.take();
21633        }
21634    }
21635
21636    pub fn register_action_renderer(
21637        &mut self,
21638        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21639    ) -> Subscription {
21640        let id = self.next_editor_action_id.post_inc();
21641        self.editor_actions
21642            .borrow_mut()
21643            .insert(id, Box::new(listener));
21644
21645        let editor_actions = self.editor_actions.clone();
21646        Subscription::new(move || {
21647            editor_actions.borrow_mut().remove(&id);
21648        })
21649    }
21650
21651    pub fn register_action<A: Action>(
21652        &mut self,
21653        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21654    ) -> Subscription {
21655        let id = self.next_editor_action_id.post_inc();
21656        let listener = Arc::new(listener);
21657        self.editor_actions.borrow_mut().insert(
21658            id,
21659            Box::new(move |_, window, _| {
21660                let listener = listener.clone();
21661                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21662                    let action = action.downcast_ref().unwrap();
21663                    if phase == DispatchPhase::Bubble {
21664                        listener(action, window, cx)
21665                    }
21666                })
21667            }),
21668        );
21669
21670        let editor_actions = self.editor_actions.clone();
21671        Subscription::new(move || {
21672            editor_actions.borrow_mut().remove(&id);
21673        })
21674    }
21675
21676    pub fn file_header_size(&self) -> u32 {
21677        FILE_HEADER_HEIGHT
21678    }
21679
21680    pub fn restore(
21681        &mut self,
21682        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21683        window: &mut Window,
21684        cx: &mut Context<Self>,
21685    ) {
21686        let workspace = self.workspace();
21687        let project = self.project();
21688        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21689            let mut tasks = Vec::new();
21690            for (buffer_id, changes) in revert_changes {
21691                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21692                    buffer.update(cx, |buffer, cx| {
21693                        buffer.edit(
21694                            changes
21695                                .into_iter()
21696                                .map(|(range, text)| (range, text.to_string())),
21697                            None,
21698                            cx,
21699                        );
21700                    });
21701
21702                    if let Some(project) =
21703                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21704                    {
21705                        project.update(cx, |project, cx| {
21706                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21707                        })
21708                    }
21709                }
21710            }
21711            tasks
21712        });
21713        cx.spawn_in(window, async move |_, cx| {
21714            for (buffer, task) in save_tasks {
21715                let result = task.await;
21716                if result.is_err() {
21717                    let Some(path) = buffer
21718                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21719                        .ok()
21720                    else {
21721                        continue;
21722                    };
21723                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21724                        let Some(task) = cx
21725                            .update_window_entity(workspace, |workspace, window, cx| {
21726                                workspace
21727                                    .open_path_preview(path, None, false, false, false, window, cx)
21728                            })
21729                            .ok()
21730                        else {
21731                            continue;
21732                        };
21733                        task.await.log_err();
21734                    }
21735                }
21736            }
21737        })
21738        .detach();
21739        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21740            selections.refresh()
21741        });
21742    }
21743
21744    pub fn to_pixel_point(
21745        &self,
21746        source: multi_buffer::Anchor,
21747        editor_snapshot: &EditorSnapshot,
21748        window: &mut Window,
21749    ) -> Option<gpui::Point<Pixels>> {
21750        let source_point = source.to_display_point(editor_snapshot);
21751        self.display_to_pixel_point(source_point, editor_snapshot, window)
21752    }
21753
21754    pub fn display_to_pixel_point(
21755        &self,
21756        source: DisplayPoint,
21757        editor_snapshot: &EditorSnapshot,
21758        window: &mut Window,
21759    ) -> Option<gpui::Point<Pixels>> {
21760        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21761        let text_layout_details = self.text_layout_details(window);
21762        let scroll_top = text_layout_details
21763            .scroll_anchor
21764            .scroll_position(editor_snapshot)
21765            .y;
21766
21767        if source.row().as_f64() < scroll_top.floor() {
21768            return None;
21769        }
21770        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21771        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21772        Some(gpui::Point::new(source_x, source_y))
21773    }
21774
21775    pub fn has_visible_completions_menu(&self) -> bool {
21776        !self.edit_prediction_preview_is_active()
21777            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21778                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21779            })
21780    }
21781
21782    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21783        if self.mode.is_minimap() {
21784            return;
21785        }
21786        self.addons
21787            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21788    }
21789
21790    pub fn unregister_addon<T: Addon>(&mut self) {
21791        self.addons.remove(&std::any::TypeId::of::<T>());
21792    }
21793
21794    pub fn addon<T: Addon>(&self) -> Option<&T> {
21795        let type_id = std::any::TypeId::of::<T>();
21796        self.addons
21797            .get(&type_id)
21798            .and_then(|item| item.to_any().downcast_ref::<T>())
21799    }
21800
21801    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21802        let type_id = std::any::TypeId::of::<T>();
21803        self.addons
21804            .get_mut(&type_id)
21805            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21806    }
21807
21808    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21809        let text_layout_details = self.text_layout_details(window);
21810        let style = &text_layout_details.editor_style;
21811        let font_id = window.text_system().resolve_font(&style.text.font());
21812        let font_size = style.text.font_size.to_pixels(window.rem_size());
21813        let line_height = style.text.line_height_in_pixels(window.rem_size());
21814        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21815        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21816
21817        CharacterDimensions {
21818            em_width,
21819            em_advance,
21820            line_height,
21821        }
21822    }
21823
21824    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21825        self.load_diff_task.clone()
21826    }
21827
21828    fn read_metadata_from_db(
21829        &mut self,
21830        item_id: u64,
21831        workspace_id: WorkspaceId,
21832        window: &mut Window,
21833        cx: &mut Context<Editor>,
21834    ) {
21835        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21836            && !self.mode.is_minimap()
21837            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21838        {
21839            let buffer_snapshot = OnceCell::new();
21840
21841            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21842                && !folds.is_empty()
21843            {
21844                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21845                self.fold_ranges(
21846                    folds
21847                        .into_iter()
21848                        .map(|(start, end)| {
21849                            snapshot.clip_offset(start, Bias::Left)
21850                                ..snapshot.clip_offset(end, Bias::Right)
21851                        })
21852                        .collect(),
21853                    false,
21854                    window,
21855                    cx,
21856                );
21857            }
21858
21859            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21860                && !selections.is_empty()
21861            {
21862                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21863                // skip adding the initial selection to selection history
21864                self.selection_history.mode = SelectionHistoryMode::Skipping;
21865                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21866                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21867                        snapshot.clip_offset(start, Bias::Left)
21868                            ..snapshot.clip_offset(end, Bias::Right)
21869                    }));
21870                });
21871                self.selection_history.mode = SelectionHistoryMode::Normal;
21872            };
21873        }
21874
21875        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21876    }
21877
21878    fn update_lsp_data(
21879        &mut self,
21880        ignore_cache: bool,
21881        for_buffer: Option<BufferId>,
21882        window: &mut Window,
21883        cx: &mut Context<'_, Self>,
21884    ) {
21885        self.pull_diagnostics(for_buffer, window, cx);
21886        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21887    }
21888}
21889
21890fn edit_for_markdown_paste<'a>(
21891    buffer: &MultiBufferSnapshot,
21892    range: Range<usize>,
21893    to_insert: &'a str,
21894    url: Option<url::Url>,
21895) -> (Range<usize>, Cow<'a, str>) {
21896    if url.is_none() {
21897        return (range, Cow::Borrowed(to_insert));
21898    };
21899
21900    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21901
21902    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21903        Cow::Borrowed(to_insert)
21904    } else {
21905        Cow::Owned(format!("[{old_text}]({to_insert})"))
21906    };
21907    (range, new_text)
21908}
21909
21910fn vim_enabled(cx: &App) -> bool {
21911    vim_mode_setting::VimModeSetting::try_get(cx)
21912        .map(|vim_mode| vim_mode.0)
21913        .unwrap_or(false)
21914}
21915
21916fn process_completion_for_edit(
21917    completion: &Completion,
21918    intent: CompletionIntent,
21919    buffer: &Entity<Buffer>,
21920    cursor_position: &text::Anchor,
21921    cx: &mut Context<Editor>,
21922) -> CompletionEdit {
21923    let buffer = buffer.read(cx);
21924    let buffer_snapshot = buffer.snapshot();
21925    let (snippet, new_text) = if completion.is_snippet() {
21926        // Workaround for typescript language server issues so that methods don't expand within
21927        // strings and functions with type expressions. The previous point is used because the query
21928        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21929        let mut snippet_source = completion.new_text.clone();
21930        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21931        previous_point.column = previous_point.column.saturating_sub(1);
21932        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21933            && scope.prefers_label_for_snippet_in_completion()
21934            && let Some(label) = completion.label()
21935            && matches!(
21936                completion.kind(),
21937                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21938            )
21939        {
21940            snippet_source = label;
21941        }
21942        match Snippet::parse(&snippet_source).log_err() {
21943            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21944            None => (None, completion.new_text.clone()),
21945        }
21946    } else {
21947        (None, completion.new_text.clone())
21948    };
21949
21950    let mut range_to_replace = {
21951        let replace_range = &completion.replace_range;
21952        if let CompletionSource::Lsp {
21953            insert_range: Some(insert_range),
21954            ..
21955        } = &completion.source
21956        {
21957            debug_assert_eq!(
21958                insert_range.start, replace_range.start,
21959                "insert_range and replace_range should start at the same position"
21960            );
21961            debug_assert!(
21962                insert_range
21963                    .start
21964                    .cmp(cursor_position, &buffer_snapshot)
21965                    .is_le(),
21966                "insert_range should start before or at cursor position"
21967            );
21968            debug_assert!(
21969                replace_range
21970                    .start
21971                    .cmp(cursor_position, &buffer_snapshot)
21972                    .is_le(),
21973                "replace_range should start before or at cursor position"
21974            );
21975
21976            let should_replace = match intent {
21977                CompletionIntent::CompleteWithInsert => false,
21978                CompletionIntent::CompleteWithReplace => true,
21979                CompletionIntent::Complete | CompletionIntent::Compose => {
21980                    let insert_mode =
21981                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21982                            .completions
21983                            .lsp_insert_mode;
21984                    match insert_mode {
21985                        LspInsertMode::Insert => false,
21986                        LspInsertMode::Replace => true,
21987                        LspInsertMode::ReplaceSubsequence => {
21988                            let mut text_to_replace = buffer.chars_for_range(
21989                                buffer.anchor_before(replace_range.start)
21990                                    ..buffer.anchor_after(replace_range.end),
21991                            );
21992                            let mut current_needle = text_to_replace.next();
21993                            for haystack_ch in completion.label.text.chars() {
21994                                if let Some(needle_ch) = current_needle
21995                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21996                                {
21997                                    current_needle = text_to_replace.next();
21998                                }
21999                            }
22000                            current_needle.is_none()
22001                        }
22002                        LspInsertMode::ReplaceSuffix => {
22003                            if replace_range
22004                                .end
22005                                .cmp(cursor_position, &buffer_snapshot)
22006                                .is_gt()
22007                            {
22008                                let range_after_cursor = *cursor_position..replace_range.end;
22009                                let text_after_cursor = buffer
22010                                    .text_for_range(
22011                                        buffer.anchor_before(range_after_cursor.start)
22012                                            ..buffer.anchor_after(range_after_cursor.end),
22013                                    )
22014                                    .collect::<String>()
22015                                    .to_ascii_lowercase();
22016                                completion
22017                                    .label
22018                                    .text
22019                                    .to_ascii_lowercase()
22020                                    .ends_with(&text_after_cursor)
22021                            } else {
22022                                true
22023                            }
22024                        }
22025                    }
22026                }
22027            };
22028
22029            if should_replace {
22030                replace_range.clone()
22031            } else {
22032                insert_range.clone()
22033            }
22034        } else {
22035            replace_range.clone()
22036        }
22037    };
22038
22039    if range_to_replace
22040        .end
22041        .cmp(cursor_position, &buffer_snapshot)
22042        .is_lt()
22043    {
22044        range_to_replace.end = *cursor_position;
22045    }
22046
22047    CompletionEdit {
22048        new_text,
22049        replace_range: range_to_replace.to_offset(buffer),
22050        snippet,
22051    }
22052}
22053
22054struct CompletionEdit {
22055    new_text: String,
22056    replace_range: Range<usize>,
22057    snippet: Option<Snippet>,
22058}
22059
22060fn insert_extra_newline_brackets(
22061    buffer: &MultiBufferSnapshot,
22062    range: Range<usize>,
22063    language: &language::LanguageScope,
22064) -> bool {
22065    let leading_whitespace_len = buffer
22066        .reversed_chars_at(range.start)
22067        .take_while(|c| c.is_whitespace() && *c != '\n')
22068        .map(|c| c.len_utf8())
22069        .sum::<usize>();
22070    let trailing_whitespace_len = buffer
22071        .chars_at(range.end)
22072        .take_while(|c| c.is_whitespace() && *c != '\n')
22073        .map(|c| c.len_utf8())
22074        .sum::<usize>();
22075    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22076
22077    language.brackets().any(|(pair, enabled)| {
22078        let pair_start = pair.start.trim_end();
22079        let pair_end = pair.end.trim_start();
22080
22081        enabled
22082            && pair.newline
22083            && buffer.contains_str_at(range.end, pair_end)
22084            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22085    })
22086}
22087
22088fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22089    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22090        [(buffer, range, _)] => (*buffer, range.clone()),
22091        _ => return false,
22092    };
22093    let pair = {
22094        let mut result: Option<BracketMatch> = None;
22095
22096        for pair in buffer
22097            .all_bracket_ranges(range.clone())
22098            .filter(move |pair| {
22099                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22100            })
22101        {
22102            let len = pair.close_range.end - pair.open_range.start;
22103
22104            if let Some(existing) = &result {
22105                let existing_len = existing.close_range.end - existing.open_range.start;
22106                if len > existing_len {
22107                    continue;
22108                }
22109            }
22110
22111            result = Some(pair);
22112        }
22113
22114        result
22115    };
22116    let Some(pair) = pair else {
22117        return false;
22118    };
22119    pair.newline_only
22120        && buffer
22121            .chars_for_range(pair.open_range.end..range.start)
22122            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22123            .all(|c| c.is_whitespace() && c != '\n')
22124}
22125
22126fn update_uncommitted_diff_for_buffer(
22127    editor: Entity<Editor>,
22128    project: &Entity<Project>,
22129    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22130    buffer: Entity<MultiBuffer>,
22131    cx: &mut App,
22132) -> Task<()> {
22133    let mut tasks = Vec::new();
22134    project.update(cx, |project, cx| {
22135        for buffer in buffers {
22136            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22137                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22138            }
22139        }
22140    });
22141    cx.spawn(async move |cx| {
22142        let diffs = future::join_all(tasks).await;
22143        if editor
22144            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22145            .unwrap_or(false)
22146        {
22147            return;
22148        }
22149
22150        buffer
22151            .update(cx, |buffer, cx| {
22152                for diff in diffs.into_iter().flatten() {
22153                    buffer.add_diff(diff, cx);
22154                }
22155            })
22156            .ok();
22157    })
22158}
22159
22160fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22161    let tab_size = tab_size.get() as usize;
22162    let mut width = offset;
22163
22164    for ch in text.chars() {
22165        width += if ch == '\t' {
22166            tab_size - (width % tab_size)
22167        } else {
22168            1
22169        };
22170    }
22171
22172    width - offset
22173}
22174
22175#[cfg(test)]
22176mod tests {
22177    use super::*;
22178
22179    #[test]
22180    fn test_string_size_with_expanded_tabs() {
22181        let nz = |val| NonZeroU32::new(val).unwrap();
22182        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22183        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22184        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22185        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22186        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22187        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22188        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22189        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22190    }
22191}
22192
22193/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22194struct WordBreakingTokenizer<'a> {
22195    input: &'a str,
22196}
22197
22198impl<'a> WordBreakingTokenizer<'a> {
22199    fn new(input: &'a str) -> Self {
22200        Self { input }
22201    }
22202}
22203
22204fn is_char_ideographic(ch: char) -> bool {
22205    use unicode_script::Script::*;
22206    use unicode_script::UnicodeScript;
22207    matches!(ch.script(), Han | Tangut | Yi)
22208}
22209
22210fn is_grapheme_ideographic(text: &str) -> bool {
22211    text.chars().any(is_char_ideographic)
22212}
22213
22214fn is_grapheme_whitespace(text: &str) -> bool {
22215    text.chars().any(|x| x.is_whitespace())
22216}
22217
22218fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22219    text.chars()
22220        .next()
22221        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22222}
22223
22224#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22225enum WordBreakToken<'a> {
22226    Word { token: &'a str, grapheme_len: usize },
22227    InlineWhitespace { token: &'a str, grapheme_len: usize },
22228    Newline,
22229}
22230
22231impl<'a> Iterator for WordBreakingTokenizer<'a> {
22232    /// Yields a span, the count of graphemes in the token, and whether it was
22233    /// whitespace. Note that it also breaks at word boundaries.
22234    type Item = WordBreakToken<'a>;
22235
22236    fn next(&mut self) -> Option<Self::Item> {
22237        use unicode_segmentation::UnicodeSegmentation;
22238        if self.input.is_empty() {
22239            return None;
22240        }
22241
22242        let mut iter = self.input.graphemes(true).peekable();
22243        let mut offset = 0;
22244        let mut grapheme_len = 0;
22245        if let Some(first_grapheme) = iter.next() {
22246            let is_newline = first_grapheme == "\n";
22247            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22248            offset += first_grapheme.len();
22249            grapheme_len += 1;
22250            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22251                if let Some(grapheme) = iter.peek().copied()
22252                    && should_stay_with_preceding_ideograph(grapheme)
22253                {
22254                    offset += grapheme.len();
22255                    grapheme_len += 1;
22256                }
22257            } else {
22258                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22259                let mut next_word_bound = words.peek().copied();
22260                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22261                    next_word_bound = words.next();
22262                }
22263                while let Some(grapheme) = iter.peek().copied() {
22264                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22265                        break;
22266                    };
22267                    if is_grapheme_whitespace(grapheme) != is_whitespace
22268                        || (grapheme == "\n") != is_newline
22269                    {
22270                        break;
22271                    };
22272                    offset += grapheme.len();
22273                    grapheme_len += 1;
22274                    iter.next();
22275                }
22276            }
22277            let token = &self.input[..offset];
22278            self.input = &self.input[offset..];
22279            if token == "\n" {
22280                Some(WordBreakToken::Newline)
22281            } else if is_whitespace {
22282                Some(WordBreakToken::InlineWhitespace {
22283                    token,
22284                    grapheme_len,
22285                })
22286            } else {
22287                Some(WordBreakToken::Word {
22288                    token,
22289                    grapheme_len,
22290                })
22291            }
22292        } else {
22293            None
22294        }
22295    }
22296}
22297
22298#[test]
22299fn test_word_breaking_tokenizer() {
22300    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22301        ("", &[]),
22302        ("  ", &[whitespace("  ", 2)]),
22303        ("Ʒ", &[word("Ʒ", 1)]),
22304        ("Ǽ", &[word("Ǽ", 1)]),
22305        ("", &[word("", 1)]),
22306        ("⋑⋑", &[word("⋑⋑", 2)]),
22307        (
22308            "原理,进而",
22309            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22310        ),
22311        (
22312            "hello world",
22313            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22314        ),
22315        (
22316            "hello, world",
22317            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22318        ),
22319        (
22320            "  hello world",
22321            &[
22322                whitespace("  ", 2),
22323                word("hello", 5),
22324                whitespace(" ", 1),
22325                word("world", 5),
22326            ],
22327        ),
22328        (
22329            "这是什么 \n 钢笔",
22330            &[
22331                word("", 1),
22332                word("", 1),
22333                word("", 1),
22334                word("", 1),
22335                whitespace(" ", 1),
22336                newline(),
22337                whitespace(" ", 1),
22338                word("", 1),
22339                word("", 1),
22340            ],
22341        ),
22342        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22343    ];
22344
22345    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22346        WordBreakToken::Word {
22347            token,
22348            grapheme_len,
22349        }
22350    }
22351
22352    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22353        WordBreakToken::InlineWhitespace {
22354            token,
22355            grapheme_len,
22356        }
22357    }
22358
22359    fn newline() -> WordBreakToken<'static> {
22360        WordBreakToken::Newline
22361    }
22362
22363    for (input, result) in tests {
22364        assert_eq!(
22365            WordBreakingTokenizer::new(input)
22366                .collect::<Vec<_>>()
22367                .as_slice(),
22368            *result,
22369        );
22370    }
22371}
22372
22373fn wrap_with_prefix(
22374    first_line_prefix: String,
22375    subsequent_lines_prefix: String,
22376    unwrapped_text: String,
22377    wrap_column: usize,
22378    tab_size: NonZeroU32,
22379    preserve_existing_whitespace: bool,
22380) -> String {
22381    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22382    let subsequent_lines_prefix_len =
22383        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22384    let mut wrapped_text = String::new();
22385    let mut current_line = first_line_prefix;
22386    let mut is_first_line = true;
22387
22388    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22389    let mut current_line_len = first_line_prefix_len;
22390    let mut in_whitespace = false;
22391    for token in tokenizer {
22392        let have_preceding_whitespace = in_whitespace;
22393        match token {
22394            WordBreakToken::Word {
22395                token,
22396                grapheme_len,
22397            } => {
22398                in_whitespace = false;
22399                let current_prefix_len = if is_first_line {
22400                    first_line_prefix_len
22401                } else {
22402                    subsequent_lines_prefix_len
22403                };
22404                if current_line_len + grapheme_len > wrap_column
22405                    && current_line_len != current_prefix_len
22406                {
22407                    wrapped_text.push_str(current_line.trim_end());
22408                    wrapped_text.push('\n');
22409                    is_first_line = false;
22410                    current_line = subsequent_lines_prefix.clone();
22411                    current_line_len = subsequent_lines_prefix_len;
22412                }
22413                current_line.push_str(token);
22414                current_line_len += grapheme_len;
22415            }
22416            WordBreakToken::InlineWhitespace {
22417                mut token,
22418                mut grapheme_len,
22419            } => {
22420                in_whitespace = true;
22421                if have_preceding_whitespace && !preserve_existing_whitespace {
22422                    continue;
22423                }
22424                if !preserve_existing_whitespace {
22425                    // Keep a single whitespace grapheme as-is
22426                    if let Some(first) =
22427                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22428                    {
22429                        token = first;
22430                    } else {
22431                        token = " ";
22432                    }
22433                    grapheme_len = 1;
22434                }
22435                let current_prefix_len = if is_first_line {
22436                    first_line_prefix_len
22437                } else {
22438                    subsequent_lines_prefix_len
22439                };
22440                if current_line_len + grapheme_len > wrap_column {
22441                    wrapped_text.push_str(current_line.trim_end());
22442                    wrapped_text.push('\n');
22443                    is_first_line = false;
22444                    current_line = subsequent_lines_prefix.clone();
22445                    current_line_len = subsequent_lines_prefix_len;
22446                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22447                    current_line.push_str(token);
22448                    current_line_len += grapheme_len;
22449                }
22450            }
22451            WordBreakToken::Newline => {
22452                in_whitespace = true;
22453                let current_prefix_len = if is_first_line {
22454                    first_line_prefix_len
22455                } else {
22456                    subsequent_lines_prefix_len
22457                };
22458                if preserve_existing_whitespace {
22459                    wrapped_text.push_str(current_line.trim_end());
22460                    wrapped_text.push('\n');
22461                    is_first_line = false;
22462                    current_line = subsequent_lines_prefix.clone();
22463                    current_line_len = subsequent_lines_prefix_len;
22464                } else if have_preceding_whitespace {
22465                    continue;
22466                } else if current_line_len + 1 > wrap_column
22467                    && current_line_len != current_prefix_len
22468                {
22469                    wrapped_text.push_str(current_line.trim_end());
22470                    wrapped_text.push('\n');
22471                    is_first_line = false;
22472                    current_line = subsequent_lines_prefix.clone();
22473                    current_line_len = subsequent_lines_prefix_len;
22474                } else if current_line_len != current_prefix_len {
22475                    current_line.push(' ');
22476                    current_line_len += 1;
22477                }
22478            }
22479        }
22480    }
22481
22482    if !current_line.is_empty() {
22483        wrapped_text.push_str(&current_line);
22484    }
22485    wrapped_text
22486}
22487
22488#[test]
22489fn test_wrap_with_prefix() {
22490    assert_eq!(
22491        wrap_with_prefix(
22492            "# ".to_string(),
22493            "# ".to_string(),
22494            "abcdefg".to_string(),
22495            4,
22496            NonZeroU32::new(4).unwrap(),
22497            false,
22498        ),
22499        "# abcdefg"
22500    );
22501    assert_eq!(
22502        wrap_with_prefix(
22503            "".to_string(),
22504            "".to_string(),
22505            "\thello world".to_string(),
22506            8,
22507            NonZeroU32::new(4).unwrap(),
22508            false,
22509        ),
22510        "hello\nworld"
22511    );
22512    assert_eq!(
22513        wrap_with_prefix(
22514            "// ".to_string(),
22515            "// ".to_string(),
22516            "xx \nyy zz aa bb cc".to_string(),
22517            12,
22518            NonZeroU32::new(4).unwrap(),
22519            false,
22520        ),
22521        "// xx yy zz\n// aa bb cc"
22522    );
22523    assert_eq!(
22524        wrap_with_prefix(
22525            String::new(),
22526            String::new(),
22527            "这是什么 \n 钢笔".to_string(),
22528            3,
22529            NonZeroU32::new(4).unwrap(),
22530            false,
22531        ),
22532        "这是什\n么 钢\n"
22533    );
22534    assert_eq!(
22535        wrap_with_prefix(
22536            String::new(),
22537            String::new(),
22538            format!("foo{}bar", '\u{2009}'), // thin space
22539            80,
22540            NonZeroU32::new(4).unwrap(),
22541            false,
22542        ),
22543        format!("foo{}bar", '\u{2009}')
22544    );
22545}
22546
22547pub trait CollaborationHub {
22548    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22549    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22550    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22551}
22552
22553impl CollaborationHub for Entity<Project> {
22554    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22555        self.read(cx).collaborators()
22556    }
22557
22558    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22559        self.read(cx).user_store().read(cx).participant_indices()
22560    }
22561
22562    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22563        let this = self.read(cx);
22564        let user_ids = this.collaborators().values().map(|c| c.user_id);
22565        this.user_store().read(cx).participant_names(user_ids, cx)
22566    }
22567}
22568
22569pub trait SemanticsProvider {
22570    fn hover(
22571        &self,
22572        buffer: &Entity<Buffer>,
22573        position: text::Anchor,
22574        cx: &mut App,
22575    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22576
22577    fn inline_values(
22578        &self,
22579        buffer_handle: Entity<Buffer>,
22580        range: Range<text::Anchor>,
22581        cx: &mut App,
22582    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22583
22584    fn inlay_hints(
22585        &self,
22586        buffer_handle: Entity<Buffer>,
22587        range: Range<text::Anchor>,
22588        cx: &mut App,
22589    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22590
22591    fn resolve_inlay_hint(
22592        &self,
22593        hint: InlayHint,
22594        buffer_handle: Entity<Buffer>,
22595        server_id: LanguageServerId,
22596        cx: &mut App,
22597    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22598
22599    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22600
22601    fn document_highlights(
22602        &self,
22603        buffer: &Entity<Buffer>,
22604        position: text::Anchor,
22605        cx: &mut App,
22606    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22607
22608    fn definitions(
22609        &self,
22610        buffer: &Entity<Buffer>,
22611        position: text::Anchor,
22612        kind: GotoDefinitionKind,
22613        cx: &mut App,
22614    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22615
22616    fn range_for_rename(
22617        &self,
22618        buffer: &Entity<Buffer>,
22619        position: text::Anchor,
22620        cx: &mut App,
22621    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22622
22623    fn perform_rename(
22624        &self,
22625        buffer: &Entity<Buffer>,
22626        position: text::Anchor,
22627        new_name: String,
22628        cx: &mut App,
22629    ) -> Option<Task<Result<ProjectTransaction>>>;
22630}
22631
22632pub trait CompletionProvider {
22633    fn completions(
22634        &self,
22635        excerpt_id: ExcerptId,
22636        buffer: &Entity<Buffer>,
22637        buffer_position: text::Anchor,
22638        trigger: CompletionContext,
22639        window: &mut Window,
22640        cx: &mut Context<Editor>,
22641    ) -> Task<Result<Vec<CompletionResponse>>>;
22642
22643    fn resolve_completions(
22644        &self,
22645        _buffer: Entity<Buffer>,
22646        _completion_indices: Vec<usize>,
22647        _completions: Rc<RefCell<Box<[Completion]>>>,
22648        _cx: &mut Context<Editor>,
22649    ) -> Task<Result<bool>> {
22650        Task::ready(Ok(false))
22651    }
22652
22653    fn apply_additional_edits_for_completion(
22654        &self,
22655        _buffer: Entity<Buffer>,
22656        _completions: Rc<RefCell<Box<[Completion]>>>,
22657        _completion_index: usize,
22658        _push_to_history: bool,
22659        _cx: &mut Context<Editor>,
22660    ) -> Task<Result<Option<language::Transaction>>> {
22661        Task::ready(Ok(None))
22662    }
22663
22664    fn is_completion_trigger(
22665        &self,
22666        buffer: &Entity<Buffer>,
22667        position: language::Anchor,
22668        text: &str,
22669        trigger_in_words: bool,
22670        menu_is_open: bool,
22671        cx: &mut Context<Editor>,
22672    ) -> bool;
22673
22674    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22675
22676    fn sort_completions(&self) -> bool {
22677        true
22678    }
22679
22680    fn filter_completions(&self) -> bool {
22681        true
22682    }
22683}
22684
22685pub trait CodeActionProvider {
22686    fn id(&self) -> Arc<str>;
22687
22688    fn code_actions(
22689        &self,
22690        buffer: &Entity<Buffer>,
22691        range: Range<text::Anchor>,
22692        window: &mut Window,
22693        cx: &mut App,
22694    ) -> Task<Result<Vec<CodeAction>>>;
22695
22696    fn apply_code_action(
22697        &self,
22698        buffer_handle: Entity<Buffer>,
22699        action: CodeAction,
22700        excerpt_id: ExcerptId,
22701        push_to_history: bool,
22702        window: &mut Window,
22703        cx: &mut App,
22704    ) -> Task<Result<ProjectTransaction>>;
22705}
22706
22707impl CodeActionProvider for Entity<Project> {
22708    fn id(&self) -> Arc<str> {
22709        "project".into()
22710    }
22711
22712    fn code_actions(
22713        &self,
22714        buffer: &Entity<Buffer>,
22715        range: Range<text::Anchor>,
22716        _window: &mut Window,
22717        cx: &mut App,
22718    ) -> Task<Result<Vec<CodeAction>>> {
22719        self.update(cx, |project, cx| {
22720            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22721            let code_actions = project.code_actions(buffer, range, None, cx);
22722            cx.background_spawn(async move {
22723                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22724                Ok(code_lens_actions
22725                    .context("code lens fetch")?
22726                    .into_iter()
22727                    .flatten()
22728                    .chain(
22729                        code_actions
22730                            .context("code action fetch")?
22731                            .into_iter()
22732                            .flatten(),
22733                    )
22734                    .collect())
22735            })
22736        })
22737    }
22738
22739    fn apply_code_action(
22740        &self,
22741        buffer_handle: Entity<Buffer>,
22742        action: CodeAction,
22743        _excerpt_id: ExcerptId,
22744        push_to_history: bool,
22745        _window: &mut Window,
22746        cx: &mut App,
22747    ) -> Task<Result<ProjectTransaction>> {
22748        self.update(cx, |project, cx| {
22749            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22750        })
22751    }
22752}
22753
22754fn snippet_completions(
22755    project: &Project,
22756    buffer: &Entity<Buffer>,
22757    buffer_position: text::Anchor,
22758    cx: &mut App,
22759) -> Task<Result<CompletionResponse>> {
22760    let languages = buffer.read(cx).languages_at(buffer_position);
22761    let snippet_store = project.snippets().read(cx);
22762
22763    let scopes: Vec<_> = languages
22764        .iter()
22765        .filter_map(|language| {
22766            let language_name = language.lsp_id();
22767            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22768
22769            if snippets.is_empty() {
22770                None
22771            } else {
22772                Some((language.default_scope(), snippets))
22773            }
22774        })
22775        .collect();
22776
22777    if scopes.is_empty() {
22778        return Task::ready(Ok(CompletionResponse {
22779            completions: vec![],
22780            display_options: CompletionDisplayOptions::default(),
22781            is_incomplete: false,
22782        }));
22783    }
22784
22785    let snapshot = buffer.read(cx).text_snapshot();
22786    let chars: String = snapshot
22787        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22788        .collect();
22789    let executor = cx.background_executor().clone();
22790
22791    cx.background_spawn(async move {
22792        let mut is_incomplete = false;
22793        let mut completions: Vec<Completion> = Vec::new();
22794        for (scope, snippets) in scopes.into_iter() {
22795            let classifier =
22796                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22797            let mut last_word = chars
22798                .chars()
22799                .take_while(|c| classifier.is_word(*c))
22800                .collect::<String>();
22801            last_word = last_word.chars().rev().collect();
22802
22803            if last_word.is_empty() {
22804                return Ok(CompletionResponse {
22805                    completions: vec![],
22806                    display_options: CompletionDisplayOptions::default(),
22807                    is_incomplete: true,
22808                });
22809            }
22810
22811            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22812            let to_lsp = |point: &text::Anchor| {
22813                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22814                point_to_lsp(end)
22815            };
22816            let lsp_end = to_lsp(&buffer_position);
22817
22818            let candidates = snippets
22819                .iter()
22820                .enumerate()
22821                .flat_map(|(ix, snippet)| {
22822                    snippet
22823                        .prefix
22824                        .iter()
22825                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22826                })
22827                .collect::<Vec<StringMatchCandidate>>();
22828
22829            const MAX_RESULTS: usize = 100;
22830            let mut matches = fuzzy::match_strings(
22831                &candidates,
22832                &last_word,
22833                last_word.chars().any(|c| c.is_uppercase()),
22834                true,
22835                MAX_RESULTS,
22836                &Default::default(),
22837                executor.clone(),
22838            )
22839            .await;
22840
22841            if matches.len() >= MAX_RESULTS {
22842                is_incomplete = true;
22843            }
22844
22845            // Remove all candidates where the query's start does not match the start of any word in the candidate
22846            if let Some(query_start) = last_word.chars().next() {
22847                matches.retain(|string_match| {
22848                    split_words(&string_match.string).any(|word| {
22849                        // Check that the first codepoint of the word as lowercase matches the first
22850                        // codepoint of the query as lowercase
22851                        word.chars()
22852                            .flat_map(|codepoint| codepoint.to_lowercase())
22853                            .zip(query_start.to_lowercase())
22854                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22855                    })
22856                });
22857            }
22858
22859            let matched_strings = matches
22860                .into_iter()
22861                .map(|m| m.string)
22862                .collect::<HashSet<_>>();
22863
22864            completions.extend(snippets.iter().filter_map(|snippet| {
22865                let matching_prefix = snippet
22866                    .prefix
22867                    .iter()
22868                    .find(|prefix| matched_strings.contains(*prefix))?;
22869                let start = as_offset - last_word.len();
22870                let start = snapshot.anchor_before(start);
22871                let range = start..buffer_position;
22872                let lsp_start = to_lsp(&start);
22873                let lsp_range = lsp::Range {
22874                    start: lsp_start,
22875                    end: lsp_end,
22876                };
22877                Some(Completion {
22878                    replace_range: range,
22879                    new_text: snippet.body.clone(),
22880                    source: CompletionSource::Lsp {
22881                        insert_range: None,
22882                        server_id: LanguageServerId(usize::MAX),
22883                        resolved: true,
22884                        lsp_completion: Box::new(lsp::CompletionItem {
22885                            label: snippet.prefix.first().unwrap().clone(),
22886                            kind: Some(CompletionItemKind::SNIPPET),
22887                            label_details: snippet.description.as_ref().map(|description| {
22888                                lsp::CompletionItemLabelDetails {
22889                                    detail: Some(description.clone()),
22890                                    description: None,
22891                                }
22892                            }),
22893                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22894                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22895                                lsp::InsertReplaceEdit {
22896                                    new_text: snippet.body.clone(),
22897                                    insert: lsp_range,
22898                                    replace: lsp_range,
22899                                },
22900                            )),
22901                            filter_text: Some(snippet.body.clone()),
22902                            sort_text: Some(char::MAX.to_string()),
22903                            ..lsp::CompletionItem::default()
22904                        }),
22905                        lsp_defaults: None,
22906                    },
22907                    label: CodeLabel {
22908                        text: matching_prefix.clone(),
22909                        runs: Vec::new(),
22910                        filter_range: 0..matching_prefix.len(),
22911                    },
22912                    icon_path: None,
22913                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22914                        single_line: snippet.name.clone().into(),
22915                        plain_text: snippet
22916                            .description
22917                            .clone()
22918                            .map(|description| description.into()),
22919                    }),
22920                    insert_text_mode: None,
22921                    confirm: None,
22922                })
22923            }))
22924        }
22925
22926        Ok(CompletionResponse {
22927            completions,
22928            display_options: CompletionDisplayOptions::default(),
22929            is_incomplete,
22930        })
22931    })
22932}
22933
22934impl CompletionProvider for Entity<Project> {
22935    fn completions(
22936        &self,
22937        _excerpt_id: ExcerptId,
22938        buffer: &Entity<Buffer>,
22939        buffer_position: text::Anchor,
22940        options: CompletionContext,
22941        _window: &mut Window,
22942        cx: &mut Context<Editor>,
22943    ) -> Task<Result<Vec<CompletionResponse>>> {
22944        self.update(cx, |project, cx| {
22945            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22946            let project_completions = project.completions(buffer, buffer_position, options, cx);
22947            cx.background_spawn(async move {
22948                let mut responses = project_completions.await?;
22949                let snippets = snippets.await?;
22950                if !snippets.completions.is_empty() {
22951                    responses.push(snippets);
22952                }
22953                Ok(responses)
22954            })
22955        })
22956    }
22957
22958    fn resolve_completions(
22959        &self,
22960        buffer: Entity<Buffer>,
22961        completion_indices: Vec<usize>,
22962        completions: Rc<RefCell<Box<[Completion]>>>,
22963        cx: &mut Context<Editor>,
22964    ) -> Task<Result<bool>> {
22965        self.update(cx, |project, cx| {
22966            project.lsp_store().update(cx, |lsp_store, cx| {
22967                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22968            })
22969        })
22970    }
22971
22972    fn apply_additional_edits_for_completion(
22973        &self,
22974        buffer: Entity<Buffer>,
22975        completions: Rc<RefCell<Box<[Completion]>>>,
22976        completion_index: usize,
22977        push_to_history: bool,
22978        cx: &mut Context<Editor>,
22979    ) -> Task<Result<Option<language::Transaction>>> {
22980        self.update(cx, |project, cx| {
22981            project.lsp_store().update(cx, |lsp_store, cx| {
22982                lsp_store.apply_additional_edits_for_completion(
22983                    buffer,
22984                    completions,
22985                    completion_index,
22986                    push_to_history,
22987                    cx,
22988                )
22989            })
22990        })
22991    }
22992
22993    fn is_completion_trigger(
22994        &self,
22995        buffer: &Entity<Buffer>,
22996        position: language::Anchor,
22997        text: &str,
22998        trigger_in_words: bool,
22999        menu_is_open: bool,
23000        cx: &mut Context<Editor>,
23001    ) -> bool {
23002        let mut chars = text.chars();
23003        let char = if let Some(char) = chars.next() {
23004            char
23005        } else {
23006            return false;
23007        };
23008        if chars.next().is_some() {
23009            return false;
23010        }
23011
23012        let buffer = buffer.read(cx);
23013        let snapshot = buffer.snapshot();
23014        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23015            return false;
23016        }
23017        let classifier = snapshot
23018            .char_classifier_at(position)
23019            .scope_context(Some(CharScopeContext::Completion));
23020        if trigger_in_words && classifier.is_word(char) {
23021            return true;
23022        }
23023
23024        buffer.completion_triggers().contains(text)
23025    }
23026}
23027
23028impl SemanticsProvider for Entity<Project> {
23029    fn hover(
23030        &self,
23031        buffer: &Entity<Buffer>,
23032        position: text::Anchor,
23033        cx: &mut App,
23034    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23035        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23036    }
23037
23038    fn document_highlights(
23039        &self,
23040        buffer: &Entity<Buffer>,
23041        position: text::Anchor,
23042        cx: &mut App,
23043    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23044        Some(self.update(cx, |project, cx| {
23045            project.document_highlights(buffer, position, cx)
23046        }))
23047    }
23048
23049    fn definitions(
23050        &self,
23051        buffer: &Entity<Buffer>,
23052        position: text::Anchor,
23053        kind: GotoDefinitionKind,
23054        cx: &mut App,
23055    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23056        Some(self.update(cx, |project, cx| match kind {
23057            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23058            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23059            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23060            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23061        }))
23062    }
23063
23064    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23065        self.update(cx, |project, cx| {
23066            if project
23067                .active_debug_session(cx)
23068                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23069            {
23070                return true;
23071            }
23072
23073            buffer.update(cx, |buffer, cx| {
23074                project.any_language_server_supports_inlay_hints(buffer, cx)
23075            })
23076        })
23077    }
23078
23079    fn inline_values(
23080        &self,
23081        buffer_handle: Entity<Buffer>,
23082        range: Range<text::Anchor>,
23083        cx: &mut App,
23084    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23085        self.update(cx, |project, cx| {
23086            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23087
23088            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23089        })
23090    }
23091
23092    fn inlay_hints(
23093        &self,
23094        buffer_handle: Entity<Buffer>,
23095        range: Range<text::Anchor>,
23096        cx: &mut App,
23097    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23098        Some(self.update(cx, |project, cx| {
23099            project.inlay_hints(buffer_handle, range, cx)
23100        }))
23101    }
23102
23103    fn resolve_inlay_hint(
23104        &self,
23105        hint: InlayHint,
23106        buffer_handle: Entity<Buffer>,
23107        server_id: LanguageServerId,
23108        cx: &mut App,
23109    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23110        Some(self.update(cx, |project, cx| {
23111            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23112        }))
23113    }
23114
23115    fn range_for_rename(
23116        &self,
23117        buffer: &Entity<Buffer>,
23118        position: text::Anchor,
23119        cx: &mut App,
23120    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23121        Some(self.update(cx, |project, cx| {
23122            let buffer = buffer.clone();
23123            let task = project.prepare_rename(buffer.clone(), position, cx);
23124            cx.spawn(async move |_, cx| {
23125                Ok(match task.await? {
23126                    PrepareRenameResponse::Success(range) => Some(range),
23127                    PrepareRenameResponse::InvalidPosition => None,
23128                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23129                        // Fallback on using TreeSitter info to determine identifier range
23130                        buffer.read_with(cx, |buffer, _| {
23131                            let snapshot = buffer.snapshot();
23132                            let (range, kind) = snapshot.surrounding_word(position, None);
23133                            if kind != Some(CharKind::Word) {
23134                                return None;
23135                            }
23136                            Some(
23137                                snapshot.anchor_before(range.start)
23138                                    ..snapshot.anchor_after(range.end),
23139                            )
23140                        })?
23141                    }
23142                })
23143            })
23144        }))
23145    }
23146
23147    fn perform_rename(
23148        &self,
23149        buffer: &Entity<Buffer>,
23150        position: text::Anchor,
23151        new_name: String,
23152        cx: &mut App,
23153    ) -> Option<Task<Result<ProjectTransaction>>> {
23154        Some(self.update(cx, |project, cx| {
23155            project.perform_rename(buffer.clone(), position, new_name, cx)
23156        }))
23157    }
23158}
23159
23160fn inlay_hint_settings(
23161    location: Anchor,
23162    snapshot: &MultiBufferSnapshot,
23163    cx: &mut Context<Editor>,
23164) -> InlayHintSettings {
23165    let file = snapshot.file_at(location);
23166    let language = snapshot.language_at(location).map(|l| l.name());
23167    language_settings(language, file, cx).inlay_hints
23168}
23169
23170fn consume_contiguous_rows(
23171    contiguous_row_selections: &mut Vec<Selection<Point>>,
23172    selection: &Selection<Point>,
23173    display_map: &DisplaySnapshot,
23174    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23175) -> (MultiBufferRow, MultiBufferRow) {
23176    contiguous_row_selections.push(selection.clone());
23177    let start_row = starting_row(selection, display_map);
23178    let mut end_row = ending_row(selection, display_map);
23179
23180    while let Some(next_selection) = selections.peek() {
23181        if next_selection.start.row <= end_row.0 {
23182            end_row = ending_row(next_selection, display_map);
23183            contiguous_row_selections.push(selections.next().unwrap().clone());
23184        } else {
23185            break;
23186        }
23187    }
23188    (start_row, end_row)
23189}
23190
23191fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23192    if selection.start.column > 0 {
23193        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23194    } else {
23195        MultiBufferRow(selection.start.row)
23196    }
23197}
23198
23199fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23200    if next_selection.end.column > 0 || next_selection.is_empty() {
23201        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23202    } else {
23203        MultiBufferRow(next_selection.end.row)
23204    }
23205}
23206
23207impl EditorSnapshot {
23208    pub fn remote_selections_in_range<'a>(
23209        &'a self,
23210        range: &'a Range<Anchor>,
23211        collaboration_hub: &dyn CollaborationHub,
23212        cx: &'a App,
23213    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23214        let participant_names = collaboration_hub.user_names(cx);
23215        let participant_indices = collaboration_hub.user_participant_indices(cx);
23216        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23217        let collaborators_by_replica_id = collaborators_by_peer_id
23218            .values()
23219            .map(|collaborator| (collaborator.replica_id, collaborator))
23220            .collect::<HashMap<_, _>>();
23221        self.buffer_snapshot
23222            .selections_in_range(range, false)
23223            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23224                if replica_id == AGENT_REPLICA_ID {
23225                    Some(RemoteSelection {
23226                        replica_id,
23227                        selection,
23228                        cursor_shape,
23229                        line_mode,
23230                        collaborator_id: CollaboratorId::Agent,
23231                        user_name: Some("Agent".into()),
23232                        color: cx.theme().players().agent(),
23233                    })
23234                } else {
23235                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23236                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23237                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23238                    Some(RemoteSelection {
23239                        replica_id,
23240                        selection,
23241                        cursor_shape,
23242                        line_mode,
23243                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23244                        user_name,
23245                        color: if let Some(index) = participant_index {
23246                            cx.theme().players().color_for_participant(index.0)
23247                        } else {
23248                            cx.theme().players().absent()
23249                        },
23250                    })
23251                }
23252            })
23253    }
23254
23255    pub fn hunks_for_ranges(
23256        &self,
23257        ranges: impl IntoIterator<Item = Range<Point>>,
23258    ) -> Vec<MultiBufferDiffHunk> {
23259        let mut hunks = Vec::new();
23260        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23261            HashMap::default();
23262        for query_range in ranges {
23263            let query_rows =
23264                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23265            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23266                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23267            ) {
23268                // Include deleted hunks that are adjacent to the query range, because
23269                // otherwise they would be missed.
23270                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23271                if hunk.status().is_deleted() {
23272                    intersects_range |= hunk.row_range.start == query_rows.end;
23273                    intersects_range |= hunk.row_range.end == query_rows.start;
23274                }
23275                if intersects_range {
23276                    if !processed_buffer_rows
23277                        .entry(hunk.buffer_id)
23278                        .or_default()
23279                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23280                    {
23281                        continue;
23282                    }
23283                    hunks.push(hunk);
23284                }
23285            }
23286        }
23287
23288        hunks
23289    }
23290
23291    fn display_diff_hunks_for_rows<'a>(
23292        &'a self,
23293        display_rows: Range<DisplayRow>,
23294        folded_buffers: &'a HashSet<BufferId>,
23295    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23296        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23297        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23298
23299        self.buffer_snapshot
23300            .diff_hunks_in_range(buffer_start..buffer_end)
23301            .filter_map(|hunk| {
23302                if folded_buffers.contains(&hunk.buffer_id) {
23303                    return None;
23304                }
23305
23306                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23307                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23308
23309                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23310                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23311
23312                let display_hunk = if hunk_display_start.column() != 0 {
23313                    DisplayDiffHunk::Folded {
23314                        display_row: hunk_display_start.row(),
23315                    }
23316                } else {
23317                    let mut end_row = hunk_display_end.row();
23318                    if hunk_display_end.column() > 0 {
23319                        end_row.0 += 1;
23320                    }
23321                    let is_created_file = hunk.is_created_file();
23322                    DisplayDiffHunk::Unfolded {
23323                        status: hunk.status(),
23324                        diff_base_byte_range: hunk.diff_base_byte_range,
23325                        display_row_range: hunk_display_start.row()..end_row,
23326                        multi_buffer_range: Anchor::range_in_buffer(
23327                            hunk.excerpt_id,
23328                            hunk.buffer_id,
23329                            hunk.buffer_range,
23330                        ),
23331                        is_created_file,
23332                    }
23333                };
23334
23335                Some(display_hunk)
23336            })
23337    }
23338
23339    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23340        self.display_snapshot.buffer_snapshot.language_at(position)
23341    }
23342
23343    pub fn is_focused(&self) -> bool {
23344        self.is_focused
23345    }
23346
23347    pub fn placeholder_text(&self) -> Option<String> {
23348        self.placeholder_display_snapshot
23349            .as_ref()
23350            .map(|display_map| display_map.text())
23351    }
23352
23353    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23354        self.scroll_anchor.scroll_position(&self.display_snapshot)
23355    }
23356
23357    fn gutter_dimensions(
23358        &self,
23359        font_id: FontId,
23360        font_size: Pixels,
23361        max_line_number_width: Pixels,
23362        cx: &App,
23363    ) -> Option<GutterDimensions> {
23364        if !self.show_gutter {
23365            return None;
23366        }
23367
23368        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23369        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23370
23371        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23372            matches!(
23373                ProjectSettings::get_global(cx).git.git_gutter,
23374                GitGutterSetting::TrackedFiles
23375            )
23376        });
23377        let gutter_settings = EditorSettings::get_global(cx).gutter;
23378        let show_line_numbers = self
23379            .show_line_numbers
23380            .unwrap_or(gutter_settings.line_numbers);
23381        let line_gutter_width = if show_line_numbers {
23382            // Avoid flicker-like gutter resizes when the line number gains another digit by
23383            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23384            let min_width_for_number_on_gutter =
23385                ch_advance * gutter_settings.min_line_number_digits as f32;
23386            max_line_number_width.max(min_width_for_number_on_gutter)
23387        } else {
23388            0.0.into()
23389        };
23390
23391        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23392        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23393
23394        let git_blame_entries_width =
23395            self.git_blame_gutter_max_author_length
23396                .map(|max_author_length| {
23397                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23398                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23399
23400                    /// The number of characters to dedicate to gaps and margins.
23401                    const SPACING_WIDTH: usize = 4;
23402
23403                    let max_char_count = max_author_length.min(renderer.max_author_length())
23404                        + ::git::SHORT_SHA_LENGTH
23405                        + MAX_RELATIVE_TIMESTAMP.len()
23406                        + SPACING_WIDTH;
23407
23408                    ch_advance * max_char_count
23409                });
23410
23411        let is_singleton = self.buffer_snapshot.is_singleton();
23412
23413        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23414        left_padding += if !is_singleton {
23415            ch_width * 4.0
23416        } else if show_runnables || show_breakpoints {
23417            ch_width * 3.0
23418        } else if show_git_gutter && show_line_numbers {
23419            ch_width * 2.0
23420        } else if show_git_gutter || show_line_numbers {
23421            ch_width
23422        } else {
23423            px(0.)
23424        };
23425
23426        let shows_folds = is_singleton && gutter_settings.folds;
23427
23428        let right_padding = if shows_folds && show_line_numbers {
23429            ch_width * 4.0
23430        } else if shows_folds || (!is_singleton && show_line_numbers) {
23431            ch_width * 3.0
23432        } else if show_line_numbers {
23433            ch_width
23434        } else {
23435            px(0.)
23436        };
23437
23438        Some(GutterDimensions {
23439            left_padding,
23440            right_padding,
23441            width: line_gutter_width + left_padding + right_padding,
23442            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23443            git_blame_entries_width,
23444        })
23445    }
23446
23447    pub fn render_crease_toggle(
23448        &self,
23449        buffer_row: MultiBufferRow,
23450        row_contains_cursor: bool,
23451        editor: Entity<Editor>,
23452        window: &mut Window,
23453        cx: &mut App,
23454    ) -> Option<AnyElement> {
23455        let folded = self.is_line_folded(buffer_row);
23456        let mut is_foldable = false;
23457
23458        if let Some(crease) = self
23459            .crease_snapshot
23460            .query_row(buffer_row, &self.buffer_snapshot)
23461        {
23462            is_foldable = true;
23463            match crease {
23464                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23465                    if let Some(render_toggle) = render_toggle {
23466                        let toggle_callback =
23467                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23468                                if folded {
23469                                    editor.update(cx, |editor, cx| {
23470                                        editor.fold_at(buffer_row, window, cx)
23471                                    });
23472                                } else {
23473                                    editor.update(cx, |editor, cx| {
23474                                        editor.unfold_at(buffer_row, window, cx)
23475                                    });
23476                                }
23477                            });
23478                        return Some((render_toggle)(
23479                            buffer_row,
23480                            folded,
23481                            toggle_callback,
23482                            window,
23483                            cx,
23484                        ));
23485                    }
23486                }
23487            }
23488        }
23489
23490        is_foldable |= self.starts_indent(buffer_row);
23491
23492        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23493            Some(
23494                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23495                    .toggle_state(folded)
23496                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23497                        if folded {
23498                            this.unfold_at(buffer_row, window, cx);
23499                        } else {
23500                            this.fold_at(buffer_row, window, cx);
23501                        }
23502                    }))
23503                    .into_any_element(),
23504            )
23505        } else {
23506            None
23507        }
23508    }
23509
23510    pub fn render_crease_trailer(
23511        &self,
23512        buffer_row: MultiBufferRow,
23513        window: &mut Window,
23514        cx: &mut App,
23515    ) -> Option<AnyElement> {
23516        let folded = self.is_line_folded(buffer_row);
23517        if let Crease::Inline { render_trailer, .. } = self
23518            .crease_snapshot
23519            .query_row(buffer_row, &self.buffer_snapshot)?
23520        {
23521            let render_trailer = render_trailer.as_ref()?;
23522            Some(render_trailer(buffer_row, folded, window, cx))
23523        } else {
23524            None
23525        }
23526    }
23527}
23528
23529impl Deref for EditorSnapshot {
23530    type Target = DisplaySnapshot;
23531
23532    fn deref(&self) -> &Self::Target {
23533        &self.display_snapshot
23534    }
23535}
23536
23537#[derive(Clone, Debug, PartialEq, Eq)]
23538pub enum EditorEvent {
23539    InputIgnored {
23540        text: Arc<str>,
23541    },
23542    InputHandled {
23543        utf16_range_to_replace: Option<Range<isize>>,
23544        text: Arc<str>,
23545    },
23546    ExcerptsAdded {
23547        buffer: Entity<Buffer>,
23548        predecessor: ExcerptId,
23549        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23550    },
23551    ExcerptsRemoved {
23552        ids: Vec<ExcerptId>,
23553        removed_buffer_ids: Vec<BufferId>,
23554    },
23555    BufferFoldToggled {
23556        ids: Vec<ExcerptId>,
23557        folded: bool,
23558    },
23559    ExcerptsEdited {
23560        ids: Vec<ExcerptId>,
23561    },
23562    ExcerptsExpanded {
23563        ids: Vec<ExcerptId>,
23564    },
23565    BufferEdited,
23566    Edited {
23567        transaction_id: clock::Lamport,
23568    },
23569    Reparsed(BufferId),
23570    Focused,
23571    FocusedIn,
23572    Blurred,
23573    DirtyChanged,
23574    Saved,
23575    TitleChanged,
23576    SelectionsChanged {
23577        local: bool,
23578    },
23579    ScrollPositionChanged {
23580        local: bool,
23581        autoscroll: bool,
23582    },
23583    TransactionUndone {
23584        transaction_id: clock::Lamport,
23585    },
23586    TransactionBegun {
23587        transaction_id: clock::Lamport,
23588    },
23589    CursorShapeChanged,
23590    BreadcrumbsChanged,
23591    PushedToNavHistory {
23592        anchor: Anchor,
23593        is_deactivate: bool,
23594    },
23595}
23596
23597impl EventEmitter<EditorEvent> for Editor {}
23598
23599impl Focusable for Editor {
23600    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23601        self.focus_handle.clone()
23602    }
23603}
23604
23605impl Render for Editor {
23606    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23607        let settings = ThemeSettings::get_global(cx);
23608
23609        let mut text_style = match self.mode {
23610            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23611                color: cx.theme().colors().editor_foreground,
23612                font_family: settings.ui_font.family.clone(),
23613                font_features: settings.ui_font.features.clone(),
23614                font_fallbacks: settings.ui_font.fallbacks.clone(),
23615                font_size: rems(0.875).into(),
23616                font_weight: settings.ui_font.weight,
23617                line_height: relative(settings.buffer_line_height.value()),
23618                ..Default::default()
23619            },
23620            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23621                color: cx.theme().colors().editor_foreground,
23622                font_family: settings.buffer_font.family.clone(),
23623                font_features: settings.buffer_font.features.clone(),
23624                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23625                font_size: settings.buffer_font_size(cx).into(),
23626                font_weight: settings.buffer_font.weight,
23627                line_height: relative(settings.buffer_line_height.value()),
23628                ..Default::default()
23629            },
23630        };
23631        if let Some(text_style_refinement) = &self.text_style_refinement {
23632            text_style.refine(text_style_refinement)
23633        }
23634
23635        let background = match self.mode {
23636            EditorMode::SingleLine => cx.theme().system().transparent,
23637            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23638            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23639            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23640        };
23641
23642        EditorElement::new(
23643            &cx.entity(),
23644            EditorStyle {
23645                background,
23646                border: cx.theme().colors().border,
23647                local_player: cx.theme().players().local(),
23648                text: text_style,
23649                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23650                syntax: cx.theme().syntax().clone(),
23651                status: cx.theme().status().clone(),
23652                inlay_hints_style: make_inlay_hints_style(cx),
23653                edit_prediction_styles: make_suggestion_styles(cx),
23654                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23655                show_underlines: self.diagnostics_enabled(),
23656            },
23657        )
23658    }
23659}
23660
23661impl EntityInputHandler for Editor {
23662    fn text_for_range(
23663        &mut self,
23664        range_utf16: Range<usize>,
23665        adjusted_range: &mut Option<Range<usize>>,
23666        _: &mut Window,
23667        cx: &mut Context<Self>,
23668    ) -> Option<String> {
23669        let snapshot = self.buffer.read(cx).read(cx);
23670        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23671        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23672        if (start.0..end.0) != range_utf16 {
23673            adjusted_range.replace(start.0..end.0);
23674        }
23675        Some(snapshot.text_for_range(start..end).collect())
23676    }
23677
23678    fn selected_text_range(
23679        &mut self,
23680        ignore_disabled_input: bool,
23681        _: &mut Window,
23682        cx: &mut Context<Self>,
23683    ) -> Option<UTF16Selection> {
23684        // Prevent the IME menu from appearing when holding down an alphabetic key
23685        // while input is disabled.
23686        if !ignore_disabled_input && !self.input_enabled {
23687            return None;
23688        }
23689
23690        let selection = self.selections.newest::<OffsetUtf16>(cx);
23691        let range = selection.range();
23692
23693        Some(UTF16Selection {
23694            range: range.start.0..range.end.0,
23695            reversed: selection.reversed,
23696        })
23697    }
23698
23699    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23700        let snapshot = self.buffer.read(cx).read(cx);
23701        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23702        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23703    }
23704
23705    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23706        self.clear_highlights::<InputComposition>(cx);
23707        self.ime_transaction.take();
23708    }
23709
23710    fn replace_text_in_range(
23711        &mut self,
23712        range_utf16: Option<Range<usize>>,
23713        text: &str,
23714        window: &mut Window,
23715        cx: &mut Context<Self>,
23716    ) {
23717        if !self.input_enabled {
23718            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23719            return;
23720        }
23721
23722        self.transact(window, cx, |this, window, cx| {
23723            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23724                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23725                Some(this.selection_replacement_ranges(range_utf16, cx))
23726            } else {
23727                this.marked_text_ranges(cx)
23728            };
23729
23730            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23731                let newest_selection_id = this.selections.newest_anchor().id;
23732                this.selections
23733                    .all::<OffsetUtf16>(cx)
23734                    .iter()
23735                    .zip(ranges_to_replace.iter())
23736                    .find_map(|(selection, range)| {
23737                        if selection.id == newest_selection_id {
23738                            Some(
23739                                (range.start.0 as isize - selection.head().0 as isize)
23740                                    ..(range.end.0 as isize - selection.head().0 as isize),
23741                            )
23742                        } else {
23743                            None
23744                        }
23745                    })
23746            });
23747
23748            cx.emit(EditorEvent::InputHandled {
23749                utf16_range_to_replace: range_to_replace,
23750                text: text.into(),
23751            });
23752
23753            if let Some(new_selected_ranges) = new_selected_ranges {
23754                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23755                    selections.select_ranges(new_selected_ranges)
23756                });
23757                this.backspace(&Default::default(), window, cx);
23758            }
23759
23760            this.handle_input(text, window, cx);
23761        });
23762
23763        if let Some(transaction) = self.ime_transaction {
23764            self.buffer.update(cx, |buffer, cx| {
23765                buffer.group_until_transaction(transaction, cx);
23766            });
23767        }
23768
23769        self.unmark_text(window, cx);
23770    }
23771
23772    fn replace_and_mark_text_in_range(
23773        &mut self,
23774        range_utf16: Option<Range<usize>>,
23775        text: &str,
23776        new_selected_range_utf16: Option<Range<usize>>,
23777        window: &mut Window,
23778        cx: &mut Context<Self>,
23779    ) {
23780        if !self.input_enabled {
23781            return;
23782        }
23783
23784        let transaction = self.transact(window, cx, |this, window, cx| {
23785            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23786                let snapshot = this.buffer.read(cx).read(cx);
23787                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23788                    for marked_range in &mut marked_ranges {
23789                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23790                        marked_range.start.0 += relative_range_utf16.start;
23791                        marked_range.start =
23792                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23793                        marked_range.end =
23794                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23795                    }
23796                }
23797                Some(marked_ranges)
23798            } else if let Some(range_utf16) = range_utf16 {
23799                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23800                Some(this.selection_replacement_ranges(range_utf16, cx))
23801            } else {
23802                None
23803            };
23804
23805            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23806                let newest_selection_id = this.selections.newest_anchor().id;
23807                this.selections
23808                    .all::<OffsetUtf16>(cx)
23809                    .iter()
23810                    .zip(ranges_to_replace.iter())
23811                    .find_map(|(selection, range)| {
23812                        if selection.id == newest_selection_id {
23813                            Some(
23814                                (range.start.0 as isize - selection.head().0 as isize)
23815                                    ..(range.end.0 as isize - selection.head().0 as isize),
23816                            )
23817                        } else {
23818                            None
23819                        }
23820                    })
23821            });
23822
23823            cx.emit(EditorEvent::InputHandled {
23824                utf16_range_to_replace: range_to_replace,
23825                text: text.into(),
23826            });
23827
23828            if let Some(ranges) = ranges_to_replace {
23829                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23830                    s.select_ranges(ranges)
23831                });
23832            }
23833
23834            let marked_ranges = {
23835                let snapshot = this.buffer.read(cx).read(cx);
23836                this.selections
23837                    .disjoint_anchors_arc()
23838                    .iter()
23839                    .map(|selection| {
23840                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23841                    })
23842                    .collect::<Vec<_>>()
23843            };
23844
23845            if text.is_empty() {
23846                this.unmark_text(window, cx);
23847            } else {
23848                this.highlight_text::<InputComposition>(
23849                    marked_ranges.clone(),
23850                    HighlightStyle {
23851                        underline: Some(UnderlineStyle {
23852                            thickness: px(1.),
23853                            color: None,
23854                            wavy: false,
23855                        }),
23856                        ..Default::default()
23857                    },
23858                    cx,
23859                );
23860            }
23861
23862            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23863            let use_autoclose = this.use_autoclose;
23864            let use_auto_surround = this.use_auto_surround;
23865            this.set_use_autoclose(false);
23866            this.set_use_auto_surround(false);
23867            this.handle_input(text, window, cx);
23868            this.set_use_autoclose(use_autoclose);
23869            this.set_use_auto_surround(use_auto_surround);
23870
23871            if let Some(new_selected_range) = new_selected_range_utf16 {
23872                let snapshot = this.buffer.read(cx).read(cx);
23873                let new_selected_ranges = marked_ranges
23874                    .into_iter()
23875                    .map(|marked_range| {
23876                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23877                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23878                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23879                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23880                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23881                    })
23882                    .collect::<Vec<_>>();
23883
23884                drop(snapshot);
23885                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23886                    selections.select_ranges(new_selected_ranges)
23887                });
23888            }
23889        });
23890
23891        self.ime_transaction = self.ime_transaction.or(transaction);
23892        if let Some(transaction) = self.ime_transaction {
23893            self.buffer.update(cx, |buffer, cx| {
23894                buffer.group_until_transaction(transaction, cx);
23895            });
23896        }
23897
23898        if self.text_highlights::<InputComposition>(cx).is_none() {
23899            self.ime_transaction.take();
23900        }
23901    }
23902
23903    fn bounds_for_range(
23904        &mut self,
23905        range_utf16: Range<usize>,
23906        element_bounds: gpui::Bounds<Pixels>,
23907        window: &mut Window,
23908        cx: &mut Context<Self>,
23909    ) -> Option<gpui::Bounds<Pixels>> {
23910        let text_layout_details = self.text_layout_details(window);
23911        let CharacterDimensions {
23912            em_width,
23913            em_advance,
23914            line_height,
23915        } = self.character_dimensions(window);
23916
23917        let snapshot = self.snapshot(window, cx);
23918        let scroll_position = snapshot.scroll_position();
23919        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
23920
23921        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23922        let x = Pixels::from(
23923            ScrollOffset::from(
23924                snapshot.x_for_display_point(start, &text_layout_details)
23925                    + self.gutter_dimensions.full_width(),
23926            ) - scroll_left,
23927        );
23928        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
23929
23930        Some(Bounds {
23931            origin: element_bounds.origin + point(x, y),
23932            size: size(em_width, line_height),
23933        })
23934    }
23935
23936    fn character_index_for_point(
23937        &mut self,
23938        point: gpui::Point<Pixels>,
23939        _window: &mut Window,
23940        _cx: &mut Context<Self>,
23941    ) -> Option<usize> {
23942        let position_map = self.last_position_map.as_ref()?;
23943        if !position_map.text_hitbox.contains(&point) {
23944            return None;
23945        }
23946        let display_point = position_map.point_for_position(point).previous_valid;
23947        let anchor = position_map
23948            .snapshot
23949            .display_point_to_anchor(display_point, Bias::Left);
23950        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23951        Some(utf16_offset.0)
23952    }
23953}
23954
23955trait SelectionExt {
23956    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23957    fn spanned_rows(
23958        &self,
23959        include_end_if_at_line_start: bool,
23960        map: &DisplaySnapshot,
23961    ) -> Range<MultiBufferRow>;
23962}
23963
23964impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23965    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23966        let start = self
23967            .start
23968            .to_point(&map.buffer_snapshot)
23969            .to_display_point(map);
23970        let end = self
23971            .end
23972            .to_point(&map.buffer_snapshot)
23973            .to_display_point(map);
23974        if self.reversed {
23975            end..start
23976        } else {
23977            start..end
23978        }
23979    }
23980
23981    fn spanned_rows(
23982        &self,
23983        include_end_if_at_line_start: bool,
23984        map: &DisplaySnapshot,
23985    ) -> Range<MultiBufferRow> {
23986        let start = self.start.to_point(&map.buffer_snapshot);
23987        let mut end = self.end.to_point(&map.buffer_snapshot);
23988        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23989            end.row -= 1;
23990        }
23991
23992        let buffer_start = map.prev_line_boundary(start).0;
23993        let buffer_end = map.next_line_boundary(end).0;
23994        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23995    }
23996}
23997
23998impl<T: InvalidationRegion> InvalidationStack<T> {
23999    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24000    where
24001        S: Clone + ToOffset,
24002    {
24003        while let Some(region) = self.last() {
24004            let all_selections_inside_invalidation_ranges =
24005                if selections.len() == region.ranges().len() {
24006                    selections
24007                        .iter()
24008                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24009                        .all(|(selection, invalidation_range)| {
24010                            let head = selection.head().to_offset(buffer);
24011                            invalidation_range.start <= head && invalidation_range.end >= head
24012                        })
24013                } else {
24014                    false
24015                };
24016
24017            if all_selections_inside_invalidation_ranges {
24018                break;
24019            } else {
24020                self.pop();
24021            }
24022        }
24023    }
24024}
24025
24026impl<T> Default for InvalidationStack<T> {
24027    fn default() -> Self {
24028        Self(Default::default())
24029    }
24030}
24031
24032impl<T> Deref for InvalidationStack<T> {
24033    type Target = Vec<T>;
24034
24035    fn deref(&self) -> &Self::Target {
24036        &self.0
24037    }
24038}
24039
24040impl<T> DerefMut for InvalidationStack<T> {
24041    fn deref_mut(&mut self) -> &mut Self::Target {
24042        &mut self.0
24043    }
24044}
24045
24046impl InvalidationRegion for SnippetState {
24047    fn ranges(&self) -> &[Range<Anchor>] {
24048        &self.ranges[self.active_index]
24049    }
24050}
24051
24052fn edit_prediction_edit_text(
24053    current_snapshot: &BufferSnapshot,
24054    edits: &[(Range<Anchor>, String)],
24055    edit_preview: &EditPreview,
24056    include_deletions: bool,
24057    cx: &App,
24058) -> HighlightedText {
24059    let edits = edits
24060        .iter()
24061        .map(|(anchor, text)| {
24062            (
24063                anchor.start.text_anchor..anchor.end.text_anchor,
24064                text.clone(),
24065            )
24066        })
24067        .collect::<Vec<_>>();
24068
24069    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24070}
24071
24072fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24073    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24074    // Just show the raw edit text with basic styling
24075    let mut text = String::new();
24076    let mut highlights = Vec::new();
24077
24078    let insertion_highlight_style = HighlightStyle {
24079        color: Some(cx.theme().colors().text),
24080        ..Default::default()
24081    };
24082
24083    for (_, edit_text) in edits {
24084        let start_offset = text.len();
24085        text.push_str(edit_text);
24086        let end_offset = text.len();
24087
24088        if start_offset < end_offset {
24089            highlights.push((start_offset..end_offset, insertion_highlight_style));
24090        }
24091    }
24092
24093    HighlightedText {
24094        text: text.into(),
24095        highlights,
24096    }
24097}
24098
24099pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24100    match severity {
24101        lsp::DiagnosticSeverity::ERROR => colors.error,
24102        lsp::DiagnosticSeverity::WARNING => colors.warning,
24103        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24104        lsp::DiagnosticSeverity::HINT => colors.info,
24105        _ => colors.ignored,
24106    }
24107}
24108
24109pub fn styled_runs_for_code_label<'a>(
24110    label: &'a CodeLabel,
24111    syntax_theme: &'a theme::SyntaxTheme,
24112) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24113    let fade_out = HighlightStyle {
24114        fade_out: Some(0.35),
24115        ..Default::default()
24116    };
24117
24118    let mut prev_end = label.filter_range.end;
24119    label
24120        .runs
24121        .iter()
24122        .enumerate()
24123        .flat_map(move |(ix, (range, highlight_id))| {
24124            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24125                style
24126            } else {
24127                return Default::default();
24128            };
24129            let muted_style = style.highlight(fade_out);
24130
24131            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24132            if range.start >= label.filter_range.end {
24133                if range.start > prev_end {
24134                    runs.push((prev_end..range.start, fade_out));
24135                }
24136                runs.push((range.clone(), muted_style));
24137            } else if range.end <= label.filter_range.end {
24138                runs.push((range.clone(), style));
24139            } else {
24140                runs.push((range.start..label.filter_range.end, style));
24141                runs.push((label.filter_range.end..range.end, muted_style));
24142            }
24143            prev_end = cmp::max(prev_end, range.end);
24144
24145            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24146                runs.push((prev_end..label.text.len(), fade_out));
24147            }
24148
24149            runs
24150        })
24151}
24152
24153pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24154    let mut prev_index = 0;
24155    let mut prev_codepoint: Option<char> = None;
24156    text.char_indices()
24157        .chain([(text.len(), '\0')])
24158        .filter_map(move |(index, codepoint)| {
24159            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24160            let is_boundary = index == text.len()
24161                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24162                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24163            if is_boundary {
24164                let chunk = &text[prev_index..index];
24165                prev_index = index;
24166                Some(chunk)
24167            } else {
24168                None
24169            }
24170        })
24171}
24172
24173pub trait RangeToAnchorExt: Sized {
24174    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24175
24176    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24177        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
24178        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24179    }
24180}
24181
24182impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24183    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24184        let start_offset = self.start.to_offset(snapshot);
24185        let end_offset = self.end.to_offset(snapshot);
24186        if start_offset == end_offset {
24187            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24188        } else {
24189            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24190        }
24191    }
24192}
24193
24194pub trait RowExt {
24195    fn as_f64(&self) -> f64;
24196
24197    fn next_row(&self) -> Self;
24198
24199    fn previous_row(&self) -> Self;
24200
24201    fn minus(&self, other: Self) -> u32;
24202}
24203
24204impl RowExt for DisplayRow {
24205    fn as_f64(&self) -> f64 {
24206        self.0 as _
24207    }
24208
24209    fn next_row(&self) -> Self {
24210        Self(self.0 + 1)
24211    }
24212
24213    fn previous_row(&self) -> Self {
24214        Self(self.0.saturating_sub(1))
24215    }
24216
24217    fn minus(&self, other: Self) -> u32 {
24218        self.0 - other.0
24219    }
24220}
24221
24222impl RowExt for MultiBufferRow {
24223    fn as_f64(&self) -> f64 {
24224        self.0 as _
24225    }
24226
24227    fn next_row(&self) -> Self {
24228        Self(self.0 + 1)
24229    }
24230
24231    fn previous_row(&self) -> Self {
24232        Self(self.0.saturating_sub(1))
24233    }
24234
24235    fn minus(&self, other: Self) -> u32 {
24236        self.0 - other.0
24237    }
24238}
24239
24240trait RowRangeExt {
24241    type Row;
24242
24243    fn len(&self) -> usize;
24244
24245    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24246}
24247
24248impl RowRangeExt for Range<MultiBufferRow> {
24249    type Row = MultiBufferRow;
24250
24251    fn len(&self) -> usize {
24252        (self.end.0 - self.start.0) as usize
24253    }
24254
24255    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24256        (self.start.0..self.end.0).map(MultiBufferRow)
24257    }
24258}
24259
24260impl RowRangeExt for Range<DisplayRow> {
24261    type Row = DisplayRow;
24262
24263    fn len(&self) -> usize {
24264        (self.end.0 - self.start.0) as usize
24265    }
24266
24267    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24268        (self.start.0..self.end.0).map(DisplayRow)
24269    }
24270}
24271
24272/// If select range has more than one line, we
24273/// just point the cursor to range.start.
24274fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24275    if range.start.row == range.end.row {
24276        range
24277    } else {
24278        range.start..range.start
24279    }
24280}
24281pub struct KillRing(ClipboardItem);
24282impl Global for KillRing {}
24283
24284const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24285
24286enum BreakpointPromptEditAction {
24287    Log,
24288    Condition,
24289    HitCondition,
24290}
24291
24292struct BreakpointPromptEditor {
24293    pub(crate) prompt: Entity<Editor>,
24294    editor: WeakEntity<Editor>,
24295    breakpoint_anchor: Anchor,
24296    breakpoint: Breakpoint,
24297    edit_action: BreakpointPromptEditAction,
24298    block_ids: HashSet<CustomBlockId>,
24299    editor_margins: Arc<Mutex<EditorMargins>>,
24300    _subscriptions: Vec<Subscription>,
24301}
24302
24303impl BreakpointPromptEditor {
24304    const MAX_LINES: u8 = 4;
24305
24306    fn new(
24307        editor: WeakEntity<Editor>,
24308        breakpoint_anchor: Anchor,
24309        breakpoint: Breakpoint,
24310        edit_action: BreakpointPromptEditAction,
24311        window: &mut Window,
24312        cx: &mut Context<Self>,
24313    ) -> Self {
24314        let base_text = match edit_action {
24315            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24316            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24317            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24318        }
24319        .map(|msg| msg.to_string())
24320        .unwrap_or_default();
24321
24322        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24323        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24324
24325        let prompt = cx.new(|cx| {
24326            let mut prompt = Editor::new(
24327                EditorMode::AutoHeight {
24328                    min_lines: 1,
24329                    max_lines: Some(Self::MAX_LINES as usize),
24330                },
24331                buffer,
24332                None,
24333                window,
24334                cx,
24335            );
24336            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24337            prompt.set_show_cursor_when_unfocused(false, cx);
24338            prompt.set_placeholder_text(
24339                match edit_action {
24340                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24341                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24342                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24343                },
24344                window,
24345                cx,
24346            );
24347
24348            prompt
24349        });
24350
24351        Self {
24352            prompt,
24353            editor,
24354            breakpoint_anchor,
24355            breakpoint,
24356            edit_action,
24357            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24358            block_ids: Default::default(),
24359            _subscriptions: vec![],
24360        }
24361    }
24362
24363    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24364        self.block_ids.extend(block_ids)
24365    }
24366
24367    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24368        if let Some(editor) = self.editor.upgrade() {
24369            let message = self
24370                .prompt
24371                .read(cx)
24372                .buffer
24373                .read(cx)
24374                .as_singleton()
24375                .expect("A multi buffer in breakpoint prompt isn't possible")
24376                .read(cx)
24377                .as_rope()
24378                .to_string();
24379
24380            editor.update(cx, |editor, cx| {
24381                editor.edit_breakpoint_at_anchor(
24382                    self.breakpoint_anchor,
24383                    self.breakpoint.clone(),
24384                    match self.edit_action {
24385                        BreakpointPromptEditAction::Log => {
24386                            BreakpointEditAction::EditLogMessage(message.into())
24387                        }
24388                        BreakpointPromptEditAction::Condition => {
24389                            BreakpointEditAction::EditCondition(message.into())
24390                        }
24391                        BreakpointPromptEditAction::HitCondition => {
24392                            BreakpointEditAction::EditHitCondition(message.into())
24393                        }
24394                    },
24395                    cx,
24396                );
24397
24398                editor.remove_blocks(self.block_ids.clone(), None, cx);
24399                cx.focus_self(window);
24400            });
24401        }
24402    }
24403
24404    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24405        self.editor
24406            .update(cx, |editor, cx| {
24407                editor.remove_blocks(self.block_ids.clone(), None, cx);
24408                window.focus(&editor.focus_handle);
24409            })
24410            .log_err();
24411    }
24412
24413    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24414        let settings = ThemeSettings::get_global(cx);
24415        let text_style = TextStyle {
24416            color: if self.prompt.read(cx).read_only(cx) {
24417                cx.theme().colors().text_disabled
24418            } else {
24419                cx.theme().colors().text
24420            },
24421            font_family: settings.buffer_font.family.clone(),
24422            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24423            font_size: settings.buffer_font_size(cx).into(),
24424            font_weight: settings.buffer_font.weight,
24425            line_height: relative(settings.buffer_line_height.value()),
24426            ..Default::default()
24427        };
24428        EditorElement::new(
24429            &self.prompt,
24430            EditorStyle {
24431                background: cx.theme().colors().editor_background,
24432                local_player: cx.theme().players().local(),
24433                text: text_style,
24434                ..Default::default()
24435            },
24436        )
24437    }
24438}
24439
24440impl Render for BreakpointPromptEditor {
24441    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24442        let editor_margins = *self.editor_margins.lock();
24443        let gutter_dimensions = editor_margins.gutter;
24444        h_flex()
24445            .key_context("Editor")
24446            .bg(cx.theme().colors().editor_background)
24447            .border_y_1()
24448            .border_color(cx.theme().status().info_border)
24449            .size_full()
24450            .py(window.line_height() / 2.5)
24451            .on_action(cx.listener(Self::confirm))
24452            .on_action(cx.listener(Self::cancel))
24453            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24454            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24455    }
24456}
24457
24458impl Focusable for BreakpointPromptEditor {
24459    fn focus_handle(&self, cx: &App) -> FocusHandle {
24460        self.prompt.focus_handle(cx)
24461    }
24462}
24463
24464fn all_edits_insertions_or_deletions(
24465    edits: &Vec<(Range<Anchor>, String)>,
24466    snapshot: &MultiBufferSnapshot,
24467) -> bool {
24468    let mut all_insertions = true;
24469    let mut all_deletions = true;
24470
24471    for (range, new_text) in edits.iter() {
24472        let range_is_empty = range.to_offset(snapshot).is_empty();
24473        let text_is_empty = new_text.is_empty();
24474
24475        if range_is_empty != text_is_empty {
24476            if range_is_empty {
24477                all_deletions = false;
24478            } else {
24479                all_insertions = false;
24480            }
24481        } else {
24482            return false;
24483        }
24484
24485        if !all_insertions && !all_deletions {
24486            return false;
24487        }
24488    }
24489    all_insertions || all_deletions
24490}
24491
24492struct MissingEditPredictionKeybindingTooltip;
24493
24494impl Render for MissingEditPredictionKeybindingTooltip {
24495    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24496        ui::tooltip_container(cx, |container, cx| {
24497            container
24498                .flex_shrink_0()
24499                .max_w_80()
24500                .min_h(rems_from_px(124.))
24501                .justify_between()
24502                .child(
24503                    v_flex()
24504                        .flex_1()
24505                        .text_ui_sm(cx)
24506                        .child(Label::new("Conflict with Accept Keybinding"))
24507                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24508                )
24509                .child(
24510                    h_flex()
24511                        .pb_1()
24512                        .gap_1()
24513                        .items_end()
24514                        .w_full()
24515                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24516                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24517                        }))
24518                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24519                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24520                        })),
24521                )
24522        })
24523    }
24524}
24525
24526#[derive(Debug, Clone, Copy, PartialEq)]
24527pub struct LineHighlight {
24528    pub background: Background,
24529    pub border: Option<gpui::Hsla>,
24530    pub include_gutter: bool,
24531    pub type_id: Option<TypeId>,
24532}
24533
24534struct LineManipulationResult {
24535    pub new_text: String,
24536    pub line_count_before: usize,
24537    pub line_count_after: usize,
24538}
24539
24540fn render_diff_hunk_controls(
24541    row: u32,
24542    status: &DiffHunkStatus,
24543    hunk_range: Range<Anchor>,
24544    is_created_file: bool,
24545    line_height: Pixels,
24546    editor: &Entity<Editor>,
24547    _window: &mut Window,
24548    cx: &mut App,
24549) -> AnyElement {
24550    h_flex()
24551        .h(line_height)
24552        .mr_1()
24553        .gap_1()
24554        .px_0p5()
24555        .pb_1()
24556        .border_x_1()
24557        .border_b_1()
24558        .border_color(cx.theme().colors().border_variant)
24559        .rounded_b_lg()
24560        .bg(cx.theme().colors().editor_background)
24561        .gap_1()
24562        .block_mouse_except_scroll()
24563        .shadow_md()
24564        .child(if status.has_secondary_hunk() {
24565            Button::new(("stage", row as u64), "Stage")
24566                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24567                .tooltip({
24568                    let focus_handle = editor.focus_handle(cx);
24569                    move |window, cx| {
24570                        Tooltip::for_action_in(
24571                            "Stage Hunk",
24572                            &::git::ToggleStaged,
24573                            &focus_handle,
24574                            window,
24575                            cx,
24576                        )
24577                    }
24578                })
24579                .on_click({
24580                    let editor = editor.clone();
24581                    move |_event, _window, cx| {
24582                        editor.update(cx, |editor, cx| {
24583                            editor.stage_or_unstage_diff_hunks(
24584                                true,
24585                                vec![hunk_range.start..hunk_range.start],
24586                                cx,
24587                            );
24588                        });
24589                    }
24590                })
24591        } else {
24592            Button::new(("unstage", row as u64), "Unstage")
24593                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24594                .tooltip({
24595                    let focus_handle = editor.focus_handle(cx);
24596                    move |window, cx| {
24597                        Tooltip::for_action_in(
24598                            "Unstage Hunk",
24599                            &::git::ToggleStaged,
24600                            &focus_handle,
24601                            window,
24602                            cx,
24603                        )
24604                    }
24605                })
24606                .on_click({
24607                    let editor = editor.clone();
24608                    move |_event, _window, cx| {
24609                        editor.update(cx, |editor, cx| {
24610                            editor.stage_or_unstage_diff_hunks(
24611                                false,
24612                                vec![hunk_range.start..hunk_range.start],
24613                                cx,
24614                            );
24615                        });
24616                    }
24617                })
24618        })
24619        .child(
24620            Button::new(("restore", row as u64), "Restore")
24621                .tooltip({
24622                    let focus_handle = editor.focus_handle(cx);
24623                    move |window, cx| {
24624                        Tooltip::for_action_in(
24625                            "Restore Hunk",
24626                            &::git::Restore,
24627                            &focus_handle,
24628                            window,
24629                            cx,
24630                        )
24631                    }
24632                })
24633                .on_click({
24634                    let editor = editor.clone();
24635                    move |_event, window, cx| {
24636                        editor.update(cx, |editor, cx| {
24637                            let snapshot = editor.snapshot(window, cx);
24638                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24639                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24640                        });
24641                    }
24642                })
24643                .disabled(is_created_file),
24644        )
24645        .when(
24646            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24647            |el| {
24648                el.child(
24649                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24650                        .shape(IconButtonShape::Square)
24651                        .icon_size(IconSize::Small)
24652                        // .disabled(!has_multiple_hunks)
24653                        .tooltip({
24654                            let focus_handle = editor.focus_handle(cx);
24655                            move |window, cx| {
24656                                Tooltip::for_action_in(
24657                                    "Next Hunk",
24658                                    &GoToHunk,
24659                                    &focus_handle,
24660                                    window,
24661                                    cx,
24662                                )
24663                            }
24664                        })
24665                        .on_click({
24666                            let editor = editor.clone();
24667                            move |_event, window, cx| {
24668                                editor.update(cx, |editor, cx| {
24669                                    let snapshot = editor.snapshot(window, cx);
24670                                    let position =
24671                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24672                                    editor.go_to_hunk_before_or_after_position(
24673                                        &snapshot,
24674                                        position,
24675                                        Direction::Next,
24676                                        window,
24677                                        cx,
24678                                    );
24679                                    editor.expand_selected_diff_hunks(cx);
24680                                });
24681                            }
24682                        }),
24683                )
24684                .child(
24685                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24686                        .shape(IconButtonShape::Square)
24687                        .icon_size(IconSize::Small)
24688                        // .disabled(!has_multiple_hunks)
24689                        .tooltip({
24690                            let focus_handle = editor.focus_handle(cx);
24691                            move |window, cx| {
24692                                Tooltip::for_action_in(
24693                                    "Previous Hunk",
24694                                    &GoToPreviousHunk,
24695                                    &focus_handle,
24696                                    window,
24697                                    cx,
24698                                )
24699                            }
24700                        })
24701                        .on_click({
24702                            let editor = editor.clone();
24703                            move |_event, window, cx| {
24704                                editor.update(cx, |editor, cx| {
24705                                    let snapshot = editor.snapshot(window, cx);
24706                                    let point =
24707                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24708                                    editor.go_to_hunk_before_or_after_position(
24709                                        &snapshot,
24710                                        point,
24711                                        Direction::Prev,
24712                                        window,
24713                                        cx,
24714                                    );
24715                                    editor.expand_selected_diff_hunks(cx);
24716                                });
24717                            }
24718                        }),
24719                )
24720            },
24721        )
24722        .into_any_element()
24723}
24724
24725pub fn multibuffer_context_lines(cx: &App) -> u32 {
24726    EditorSettings::try_get(cx)
24727        .map(|settings| settings.excerpt_context_lines)
24728        .unwrap_or(2)
24729        .min(32)
24730}