editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex, parse_zed_link};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  125    DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  126    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  127    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  164};
  165use rand::seq::SliceRandom;
  166use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  167use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  168use selections_collection::{
  169    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  170};
  171use serde::{Deserialize, Serialize};
  172use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  173use smallvec::{SmallVec, smallvec};
  174use snippet::Snippet;
  175use std::{
  176    any::{Any, TypeId},
  177    borrow::Cow,
  178    cell::{OnceCell, RefCell},
  179    cmp::{self, Ordering, Reverse},
  180    iter::{self, Peekable},
  181    mem,
  182    num::NonZeroU32,
  183    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  184    path::{Path, PathBuf},
  185    rc::Rc,
  186    sync::Arc,
  187    time::{Duration, Instant},
  188};
  189use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  190use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  191use theme::{
  192    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  193    observe_buffer_font_size_adjustment,
  194};
  195use ui::{
  196    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  197    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  198};
  199use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  200use workspace::{
  201    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  202    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  203    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  204    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  205    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  206    searchable::SearchEvent,
  207};
  208
  209use crate::{
  210    code_context_menus::CompletionsMenuSource,
  211    editor_settings::MultiCursorModifier,
  212    hover_links::{find_url, find_url_from_range},
  213    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  214};
  215
  216pub const FILE_HEADER_HEIGHT: u32 = 2;
  217pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  218const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  219const MAX_LINE_LEN: usize = 1024;
  220const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  221const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  222pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  223#[doc(hidden)]
  224pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  225pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  226
  227pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  230
  231pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  232pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  233pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  234
  235pub type RenderDiffHunkControlsFn = Arc<
  236    dyn Fn(
  237        u32,
  238        &DiffHunkStatus,
  239        Range<Anchor>,
  240        bool,
  241        Pixels,
  242        &Entity<Editor>,
  243        &mut Window,
  244        &mut App,
  245    ) -> AnyElement,
  246>;
  247
  248enum ReportEditorEvent {
  249    Saved { auto_saved: bool },
  250    EditorOpened,
  251    Closed,
  252}
  253
  254impl ReportEditorEvent {
  255    pub fn event_type(&self) -> &'static str {
  256        match self {
  257            Self::Saved { .. } => "Editor Saved",
  258            Self::EditorOpened => "Editor Opened",
  259            Self::Closed => "Editor Closed",
  260        }
  261    }
  262}
  263
  264struct InlineValueCache {
  265    enabled: bool,
  266    inlays: Vec<InlayId>,
  267    refresh_task: Task<Option<()>>,
  268}
  269
  270impl InlineValueCache {
  271    fn new(enabled: bool) -> Self {
  272        Self {
  273            enabled,
  274            inlays: Vec::new(),
  275            refresh_task: Task::ready(None),
  276        }
  277    }
  278}
  279
  280#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  281pub enum InlayId {
  282    EditPrediction(u32),
  283    DebuggerValue(u32),
  284    // LSP
  285    Hint(u32),
  286    Color(u32),
  287}
  288
  289impl InlayId {
  290    fn id(&self) -> u32 {
  291        match self {
  292            Self::EditPrediction(id) => *id,
  293            Self::DebuggerValue(id) => *id,
  294            Self::Hint(id) => *id,
  295            Self::Color(id) => *id,
  296        }
  297    }
  298}
  299
  300pub enum ActiveDebugLine {}
  301pub enum DebugStackFrameLine {}
  302enum DocumentHighlightRead {}
  303enum DocumentHighlightWrite {}
  304enum InputComposition {}
  305pub enum PendingInput {}
  306enum SelectedTextHighlight {}
  307
  308pub enum ConflictsOuter {}
  309pub enum ConflictsOurs {}
  310pub enum ConflictsTheirs {}
  311pub enum ConflictsOursMarker {}
  312pub enum ConflictsTheirsMarker {}
  313
  314#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  315pub enum Navigated {
  316    Yes,
  317    No,
  318}
  319
  320impl Navigated {
  321    pub fn from_bool(yes: bool) -> Navigated {
  322        if yes { Navigated::Yes } else { Navigated::No }
  323    }
  324}
  325
  326#[derive(Debug, Clone, PartialEq, Eq)]
  327enum DisplayDiffHunk {
  328    Folded {
  329        display_row: DisplayRow,
  330    },
  331    Unfolded {
  332        is_created_file: bool,
  333        diff_base_byte_range: Range<usize>,
  334        display_row_range: Range<DisplayRow>,
  335        multi_buffer_range: Range<Anchor>,
  336        status: DiffHunkStatus,
  337    },
  338}
  339
  340pub enum HideMouseCursorOrigin {
  341    TypingAction,
  342    MovementAction,
  343}
  344
  345pub fn init_settings(cx: &mut App) {
  346    EditorSettings::register(cx);
  347}
  348
  349pub fn init(cx: &mut App) {
  350    init_settings(cx);
  351
  352    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  353
  354    workspace::register_project_item::<Editor>(cx);
  355    workspace::FollowableViewRegistry::register::<Editor>(cx);
  356    workspace::register_serializable_item::<Editor>(cx);
  357
  358    cx.observe_new(
  359        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  360            workspace.register_action(Editor::new_file);
  361            workspace.register_action(Editor::new_file_vertical);
  362            workspace.register_action(Editor::new_file_horizontal);
  363            workspace.register_action(Editor::cancel_language_server_work);
  364            workspace.register_action(Editor::toggle_focus);
  365        },
  366    )
  367    .detach();
  368
  369    cx.on_action(move |_: &workspace::NewFile, cx| {
  370        let app_state = workspace::AppState::global(cx);
  371        if let Some(app_state) = app_state.upgrade() {
  372            workspace::open_new(
  373                Default::default(),
  374                app_state,
  375                cx,
  376                |workspace, window, cx| {
  377                    Editor::new_file(workspace, &Default::default(), window, cx)
  378                },
  379            )
  380            .detach();
  381        }
  382    });
  383    cx.on_action(move |_: &workspace::NewWindow, cx| {
  384        let app_state = workspace::AppState::global(cx);
  385        if let Some(app_state) = app_state.upgrade() {
  386            workspace::open_new(
  387                Default::default(),
  388                app_state,
  389                cx,
  390                |workspace, window, cx| {
  391                    cx.activate(true);
  392                    Editor::new_file(workspace, &Default::default(), window, cx)
  393                },
  394            )
  395            .detach();
  396        }
  397    });
  398}
  399
  400pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  401    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  402}
  403
  404pub trait DiagnosticRenderer {
  405    fn render_group(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  408        buffer_id: BufferId,
  409        snapshot: EditorSnapshot,
  410        editor: WeakEntity<Editor>,
  411        cx: &mut App,
  412    ) -> Vec<BlockProperties<Anchor>>;
  413
  414    fn render_hover(
  415        &self,
  416        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  417        range: Range<Point>,
  418        buffer_id: BufferId,
  419        cx: &mut App,
  420    ) -> Option<Entity<markdown::Markdown>>;
  421
  422    fn open_link(
  423        &self,
  424        editor: &mut Editor,
  425        link: SharedString,
  426        window: &mut Window,
  427        cx: &mut Context<Editor>,
  428    );
  429}
  430
  431pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  432
  433impl GlobalDiagnosticRenderer {
  434    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  435        cx.try_global::<Self>().map(|g| g.0.clone())
  436    }
  437}
  438
  439impl gpui::Global for GlobalDiagnosticRenderer {}
  440pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  441    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  442}
  443
  444pub struct SearchWithinRange;
  445
  446trait InvalidationRegion {
  447    fn ranges(&self) -> &[Range<Anchor>];
  448}
  449
  450#[derive(Clone, Debug, PartialEq)]
  451pub enum SelectPhase {
  452    Begin {
  453        position: DisplayPoint,
  454        add: bool,
  455        click_count: usize,
  456    },
  457    BeginColumnar {
  458        position: DisplayPoint,
  459        reset: bool,
  460        mode: ColumnarMode,
  461        goal_column: u32,
  462    },
  463    Extend {
  464        position: DisplayPoint,
  465        click_count: usize,
  466    },
  467    Update {
  468        position: DisplayPoint,
  469        goal_column: u32,
  470        scroll_delta: gpui::Point<f32>,
  471    },
  472    End,
  473}
  474
  475#[derive(Clone, Debug, PartialEq)]
  476pub enum ColumnarMode {
  477    FromMouse,
  478    FromSelection,
  479}
  480
  481#[derive(Clone, Debug)]
  482pub enum SelectMode {
  483    Character,
  484    Word(Range<Anchor>),
  485    Line(Range<Anchor>),
  486    All,
  487}
  488
  489#[derive(Clone, PartialEq, Eq, Debug)]
  490pub enum EditorMode {
  491    SingleLine,
  492    AutoHeight {
  493        min_lines: usize,
  494        max_lines: Option<usize>,
  495    },
  496    Full {
  497        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  498        scale_ui_elements_with_buffer_font_size: bool,
  499        /// When set to `true`, the editor will render a background for the active line.
  500        show_active_line_background: bool,
  501        /// When set to `true`, the editor's height will be determined by its content.
  502        sized_by_content: bool,
  503    },
  504    Minimap {
  505        parent: WeakEntity<Editor>,
  506    },
  507}
  508
  509impl EditorMode {
  510    pub fn full() -> Self {
  511        Self::Full {
  512            scale_ui_elements_with_buffer_font_size: true,
  513            show_active_line_background: true,
  514            sized_by_content: false,
  515        }
  516    }
  517
  518    #[inline]
  519    pub fn is_full(&self) -> bool {
  520        matches!(self, Self::Full { .. })
  521    }
  522
  523    #[inline]
  524    pub fn is_single_line(&self) -> bool {
  525        matches!(self, Self::SingleLine { .. })
  526    }
  527
  528    #[inline]
  529    fn is_minimap(&self) -> bool {
  530        matches!(self, Self::Minimap { .. })
  531    }
  532}
  533
  534#[derive(Copy, Clone, Debug)]
  535pub enum SoftWrap {
  536    /// Prefer not to wrap at all.
  537    ///
  538    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  539    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  540    GitDiff,
  541    /// Prefer a single line generally, unless an overly long line is encountered.
  542    None,
  543    /// Soft wrap lines that exceed the editor width.
  544    EditorWidth,
  545    /// Soft wrap lines at the preferred line length.
  546    Column(u32),
  547    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  548    Bounded(u32),
  549}
  550
  551#[derive(Clone)]
  552pub struct EditorStyle {
  553    pub background: Hsla,
  554    pub border: Hsla,
  555    pub local_player: PlayerColor,
  556    pub text: TextStyle,
  557    pub scrollbar_width: Pixels,
  558    pub syntax: Arc<SyntaxTheme>,
  559    pub status: StatusColors,
  560    pub inlay_hints_style: HighlightStyle,
  561    pub edit_prediction_styles: EditPredictionStyles,
  562    pub unnecessary_code_fade: f32,
  563    pub show_underlines: bool,
  564}
  565
  566impl Default for EditorStyle {
  567    fn default() -> Self {
  568        Self {
  569            background: Hsla::default(),
  570            border: Hsla::default(),
  571            local_player: PlayerColor::default(),
  572            text: TextStyle::default(),
  573            scrollbar_width: Pixels::default(),
  574            syntax: Default::default(),
  575            // HACK: Status colors don't have a real default.
  576            // We should look into removing the status colors from the editor
  577            // style and retrieve them directly from the theme.
  578            status: StatusColors::dark(),
  579            inlay_hints_style: HighlightStyle::default(),
  580            edit_prediction_styles: EditPredictionStyles {
  581                insertion: HighlightStyle::default(),
  582                whitespace: HighlightStyle::default(),
  583            },
  584            unnecessary_code_fade: Default::default(),
  585            show_underlines: true,
  586        }
  587    }
  588}
  589
  590pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  591    let show_background = language_settings::language_settings(None, None, cx)
  592        .inlay_hints
  593        .show_background;
  594
  595    let mut style = cx.theme().syntax().get("hint");
  596
  597    if style.color.is_none() {
  598        style.color = Some(cx.theme().status().hint);
  599    }
  600
  601    if !show_background {
  602        style.background_color = None;
  603        return style;
  604    }
  605
  606    if style.background_color.is_none() {
  607        style.background_color = Some(cx.theme().status().hint_background);
  608    }
  609
  610    style
  611}
  612
  613pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  614    EditPredictionStyles {
  615        insertion: HighlightStyle {
  616            color: Some(cx.theme().status().predictive),
  617            ..HighlightStyle::default()
  618        },
  619        whitespace: HighlightStyle {
  620            background_color: Some(cx.theme().status().created_background),
  621            ..HighlightStyle::default()
  622        },
  623    }
  624}
  625
  626type CompletionId = usize;
  627
  628pub(crate) enum EditDisplayMode {
  629    TabAccept,
  630    DiffPopover,
  631    Inline,
  632}
  633
  634enum EditPrediction {
  635    Edit {
  636        edits: Vec<(Range<Anchor>, String)>,
  637        edit_preview: Option<EditPreview>,
  638        display_mode: EditDisplayMode,
  639        snapshot: BufferSnapshot,
  640    },
  641    /// Move to a specific location in the active editor
  642    MoveWithin {
  643        target: Anchor,
  644        snapshot: BufferSnapshot,
  645    },
  646    /// Move to a specific location in a different editor (not the active one)
  647    MoveOutside {
  648        target: language::Anchor,
  649        snapshot: BufferSnapshot,
  650    },
  651}
  652
  653struct EditPredictionState {
  654    inlay_ids: Vec<InlayId>,
  655    completion: EditPrediction,
  656    completion_id: Option<SharedString>,
  657    invalidation_range: Option<Range<Anchor>>,
  658}
  659
  660enum EditPredictionSettings {
  661    Disabled,
  662    Enabled {
  663        show_in_menu: bool,
  664        preview_requires_modifier: bool,
  665    },
  666}
  667
  668enum EditPredictionHighlight {}
  669
  670#[derive(Debug, Clone)]
  671struct InlineDiagnostic {
  672    message: SharedString,
  673    group_id: usize,
  674    is_primary: bool,
  675    start: Point,
  676    severity: lsp::DiagnosticSeverity,
  677}
  678
  679pub enum MenuEditPredictionsPolicy {
  680    Never,
  681    ByProvider,
  682}
  683
  684pub enum EditPredictionPreview {
  685    /// Modifier is not pressed
  686    Inactive { released_too_fast: bool },
  687    /// Modifier pressed
  688    Active {
  689        since: Instant,
  690        previous_scroll_position: Option<ScrollAnchor>,
  691    },
  692}
  693
  694impl EditPredictionPreview {
  695    pub fn released_too_fast(&self) -> bool {
  696        match self {
  697            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  698            EditPredictionPreview::Active { .. } => false,
  699        }
  700    }
  701
  702    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  703        if let EditPredictionPreview::Active {
  704            previous_scroll_position,
  705            ..
  706        } = self
  707        {
  708            *previous_scroll_position = scroll_position;
  709        }
  710    }
  711}
  712
  713pub struct ContextMenuOptions {
  714    pub min_entries_visible: usize,
  715    pub max_entries_visible: usize,
  716    pub placement: Option<ContextMenuPlacement>,
  717}
  718
  719#[derive(Debug, Clone, PartialEq, Eq)]
  720pub enum ContextMenuPlacement {
  721    Above,
  722    Below,
  723}
  724
  725#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  726struct EditorActionId(usize);
  727
  728impl EditorActionId {
  729    pub fn post_inc(&mut self) -> Self {
  730        let answer = self.0;
  731
  732        *self = Self(answer + 1);
  733
  734        Self(answer)
  735    }
  736}
  737
  738// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  739// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  740
  741type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  742type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  743
  744#[derive(Default)]
  745struct ScrollbarMarkerState {
  746    scrollbar_size: Size<Pixels>,
  747    dirty: bool,
  748    markers: Arc<[PaintQuad]>,
  749    pending_refresh: Option<Task<Result<()>>>,
  750}
  751
  752impl ScrollbarMarkerState {
  753    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  754        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  755    }
  756}
  757
  758#[derive(Clone, Copy, PartialEq, Eq)]
  759pub enum MinimapVisibility {
  760    Disabled,
  761    Enabled {
  762        /// The configuration currently present in the users settings.
  763        setting_configuration: bool,
  764        /// Whether to override the currently set visibility from the users setting.
  765        toggle_override: bool,
  766    },
  767}
  768
  769impl MinimapVisibility {
  770    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  771        if mode.is_full() {
  772            Self::Enabled {
  773                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  774                toggle_override: false,
  775            }
  776        } else {
  777            Self::Disabled
  778        }
  779    }
  780
  781    fn hidden(&self) -> Self {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => Self::Enabled {
  787                setting_configuration,
  788                toggle_override: setting_configuration,
  789            },
  790            Self::Disabled => Self::Disabled,
  791        }
  792    }
  793
  794    fn disabled(&self) -> bool {
  795        matches!(*self, Self::Disabled)
  796    }
  797
  798    fn settings_visibility(&self) -> bool {
  799        match *self {
  800            Self::Enabled {
  801                setting_configuration,
  802                ..
  803            } => setting_configuration,
  804            _ => false,
  805        }
  806    }
  807
  808    fn visible(&self) -> bool {
  809        match *self {
  810            Self::Enabled {
  811                setting_configuration,
  812                toggle_override,
  813            } => setting_configuration ^ toggle_override,
  814            _ => false,
  815        }
  816    }
  817
  818    fn toggle_visibility(&self) -> Self {
  819        match *self {
  820            Self::Enabled {
  821                toggle_override,
  822                setting_configuration,
  823            } => Self::Enabled {
  824                setting_configuration,
  825                toggle_override: !toggle_override,
  826            },
  827            Self::Disabled => Self::Disabled,
  828        }
  829    }
  830}
  831
  832#[derive(Clone, Debug)]
  833struct RunnableTasks {
  834    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  835    offset: multi_buffer::Anchor,
  836    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  837    column: u32,
  838    // Values of all named captures, including those starting with '_'
  839    extra_variables: HashMap<String, String>,
  840    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  841    context_range: Range<BufferOffset>,
  842}
  843
  844impl RunnableTasks {
  845    fn resolve<'a>(
  846        &'a self,
  847        cx: &'a task::TaskContext,
  848    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  849        self.templates.iter().filter_map(|(kind, template)| {
  850            template
  851                .resolve_task(&kind.to_id_base(), cx)
  852                .map(|task| (kind.clone(), task))
  853        })
  854    }
  855}
  856
  857#[derive(Clone)]
  858pub struct ResolvedTasks {
  859    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  860    position: Anchor,
  861}
  862
  863#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  864struct BufferOffset(usize);
  865
  866/// Addons allow storing per-editor state in other crates (e.g. Vim)
  867pub trait Addon: 'static {
  868    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  869
  870    fn render_buffer_header_controls(
  871        &self,
  872        _: &ExcerptInfo,
  873        _: &Window,
  874        _: &App,
  875    ) -> Option<AnyElement> {
  876        None
  877    }
  878
  879    fn to_any(&self) -> &dyn std::any::Any;
  880
  881    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  882        None
  883    }
  884}
  885
  886struct ChangeLocation {
  887    current: Option<Vec<Anchor>>,
  888    original: Vec<Anchor>,
  889}
  890impl ChangeLocation {
  891    fn locations(&self) -> &[Anchor] {
  892        self.current.as_ref().unwrap_or(&self.original)
  893    }
  894}
  895
  896/// A set of caret positions, registered when the editor was edited.
  897pub struct ChangeList {
  898    changes: Vec<ChangeLocation>,
  899    /// Currently "selected" change.
  900    position: Option<usize>,
  901}
  902
  903impl ChangeList {
  904    pub fn new() -> Self {
  905        Self {
  906            changes: Vec::new(),
  907            position: None,
  908        }
  909    }
  910
  911    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  912    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  913    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  914        if self.changes.is_empty() {
  915            return None;
  916        }
  917
  918        let prev = self.position.unwrap_or(self.changes.len());
  919        let next = if direction == Direction::Prev {
  920            prev.saturating_sub(count)
  921        } else {
  922            (prev + count).min(self.changes.len() - 1)
  923        };
  924        self.position = Some(next);
  925        self.changes.get(next).map(|change| change.locations())
  926    }
  927
  928    /// Adds a new change to the list, resetting the change list position.
  929    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  930        self.position.take();
  931        if let Some(last) = self.changes.last_mut()
  932            && group
  933        {
  934            last.current = Some(new_positions)
  935        } else {
  936            self.changes.push(ChangeLocation {
  937                original: new_positions,
  938                current: None,
  939            });
  940        }
  941    }
  942
  943    pub fn last(&self) -> Option<&[Anchor]> {
  944        self.changes.last().map(|change| change.locations())
  945    }
  946
  947    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  948        self.changes.last().map(|change| change.original.as_slice())
  949    }
  950
  951    pub fn invert_last_group(&mut self) {
  952        if let Some(last) = self.changes.last_mut()
  953            && let Some(current) = last.current.as_mut()
  954        {
  955            mem::swap(&mut last.original, current);
  956        }
  957    }
  958}
  959
  960#[derive(Clone)]
  961struct InlineBlamePopoverState {
  962    scroll_handle: ScrollHandle,
  963    commit_message: Option<ParsedCommitMessage>,
  964    markdown: Entity<Markdown>,
  965}
  966
  967struct InlineBlamePopover {
  968    position: gpui::Point<Pixels>,
  969    hide_task: Option<Task<()>>,
  970    popover_bounds: Option<Bounds<Pixels>>,
  971    popover_state: InlineBlamePopoverState,
  972    keyboard_grace: bool,
  973}
  974
  975enum SelectionDragState {
  976    /// State when no drag related activity is detected.
  977    None,
  978    /// State when the mouse is down on a selection that is about to be dragged.
  979    ReadyToDrag {
  980        selection: Selection<Anchor>,
  981        click_position: gpui::Point<Pixels>,
  982        mouse_down_time: Instant,
  983    },
  984    /// State when the mouse is dragging the selection in the editor.
  985    Dragging {
  986        selection: Selection<Anchor>,
  987        drop_cursor: Selection<Anchor>,
  988        hide_drop_cursor: bool,
  989    },
  990}
  991
  992enum ColumnarSelectionState {
  993    FromMouse {
  994        selection_tail: Anchor,
  995        display_point: Option<DisplayPoint>,
  996    },
  997    FromSelection {
  998        selection_tail: Anchor,
  999    },
 1000}
 1001
 1002/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1003/// a breakpoint on them.
 1004#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1005struct PhantomBreakpointIndicator {
 1006    display_row: DisplayRow,
 1007    /// There's a small debounce between hovering over the line and showing the indicator.
 1008    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1009    is_active: bool,
 1010    collides_with_existing_breakpoint: bool,
 1011}
 1012
 1013/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1014///
 1015/// See the [module level documentation](self) for more information.
 1016pub struct Editor {
 1017    focus_handle: FocusHandle,
 1018    last_focused_descendant: Option<WeakFocusHandle>,
 1019    /// The text buffer being edited
 1020    buffer: Entity<MultiBuffer>,
 1021    /// Map of how text in the buffer should be displayed.
 1022    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1023    pub display_map: Entity<DisplayMap>,
 1024    placeholder_display_map: Option<Entity<DisplayMap>>,
 1025    pub selections: SelectionsCollection,
 1026    pub scroll_manager: ScrollManager,
 1027    /// When inline assist editors are linked, they all render cursors because
 1028    /// typing enters text into each of them, even the ones that aren't focused.
 1029    pub(crate) show_cursor_when_unfocused: bool,
 1030    columnar_selection_state: Option<ColumnarSelectionState>,
 1031    add_selections_state: Option<AddSelectionsState>,
 1032    select_next_state: Option<SelectNextState>,
 1033    select_prev_state: Option<SelectNextState>,
 1034    selection_history: SelectionHistory,
 1035    defer_selection_effects: bool,
 1036    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1037    autoclose_regions: Vec<AutocloseRegion>,
 1038    snippet_stack: InvalidationStack<SnippetState>,
 1039    select_syntax_node_history: SelectSyntaxNodeHistory,
 1040    ime_transaction: Option<TransactionId>,
 1041    pub diagnostics_max_severity: DiagnosticSeverity,
 1042    active_diagnostics: ActiveDiagnostic,
 1043    show_inline_diagnostics: bool,
 1044    inline_diagnostics_update: Task<()>,
 1045    inline_diagnostics_enabled: bool,
 1046    diagnostics_enabled: bool,
 1047    word_completions_enabled: bool,
 1048    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1049    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1050    hard_wrap: Option<usize>,
 1051    project: Option<Entity<Project>>,
 1052    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1053    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1054    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1055    blink_manager: Entity<BlinkManager>,
 1056    show_cursor_names: bool,
 1057    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1058    pub show_local_selections: bool,
 1059    mode: EditorMode,
 1060    show_breadcrumbs: bool,
 1061    show_gutter: bool,
 1062    show_scrollbars: ScrollbarAxes,
 1063    minimap_visibility: MinimapVisibility,
 1064    offset_content: bool,
 1065    disable_expand_excerpt_buttons: bool,
 1066    show_line_numbers: Option<bool>,
 1067    use_relative_line_numbers: Option<bool>,
 1068    show_git_diff_gutter: Option<bool>,
 1069    show_code_actions: Option<bool>,
 1070    show_runnables: Option<bool>,
 1071    show_breakpoints: Option<bool>,
 1072    show_wrap_guides: Option<bool>,
 1073    show_indent_guides: Option<bool>,
 1074    highlight_order: usize,
 1075    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1076    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1077    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1078    scrollbar_marker_state: ScrollbarMarkerState,
 1079    active_indent_guides_state: ActiveIndentGuidesState,
 1080    nav_history: Option<ItemNavHistory>,
 1081    context_menu: RefCell<Option<CodeContextMenu>>,
 1082    context_menu_options: Option<ContextMenuOptions>,
 1083    mouse_context_menu: Option<MouseContextMenu>,
 1084    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1085    inline_blame_popover: Option<InlineBlamePopover>,
 1086    inline_blame_popover_show_task: Option<Task<()>>,
 1087    signature_help_state: SignatureHelpState,
 1088    auto_signature_help: Option<bool>,
 1089    find_all_references_task_sources: Vec<Anchor>,
 1090    next_completion_id: CompletionId,
 1091    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1092    code_actions_task: Option<Task<Result<()>>>,
 1093    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    document_highlights_task: Option<Task<()>>,
 1096    linked_editing_range_task: Option<Task<Option<()>>>,
 1097    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1098    pending_rename: Option<RenameState>,
 1099    searchable: bool,
 1100    cursor_shape: CursorShape,
 1101    current_line_highlight: Option<CurrentLineHighlight>,
 1102    collapse_matches: bool,
 1103    autoindent_mode: Option<AutoindentMode>,
 1104    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1105    input_enabled: bool,
 1106    use_modal_editing: bool,
 1107    read_only: bool,
 1108    leader_id: Option<CollaboratorId>,
 1109    remote_id: Option<ViewId>,
 1110    pub hover_state: HoverState,
 1111    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1112    gutter_hovered: bool,
 1113    hovered_link_state: Option<HoveredLinkState>,
 1114    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1115    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1116    active_edit_prediction: Option<EditPredictionState>,
 1117    /// Used to prevent flickering as the user types while the menu is open
 1118    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1119    edit_prediction_settings: EditPredictionSettings,
 1120    edit_predictions_hidden_for_vim_mode: bool,
 1121    show_edit_predictions_override: Option<bool>,
 1122    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1123    edit_prediction_preview: EditPredictionPreview,
 1124    edit_prediction_indent_conflict: bool,
 1125    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1126    inlay_hint_cache: InlayHintCache,
 1127    next_inlay_id: u32,
 1128    next_color_inlay_id: u32,
 1129    _subscriptions: Vec<Subscription>,
 1130    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1131    gutter_dimensions: GutterDimensions,
 1132    style: Option<EditorStyle>,
 1133    text_style_refinement: Option<TextStyleRefinement>,
 1134    next_editor_action_id: EditorActionId,
 1135    editor_actions: Rc<
 1136        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1137    >,
 1138    use_autoclose: bool,
 1139    use_auto_surround: bool,
 1140    auto_replace_emoji_shortcode: bool,
 1141    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1142    show_git_blame_gutter: bool,
 1143    show_git_blame_inline: bool,
 1144    show_git_blame_inline_delay_task: Option<Task<()>>,
 1145    git_blame_inline_enabled: bool,
 1146    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1147    serialize_dirty_buffers: bool,
 1148    show_selection_menu: Option<bool>,
 1149    blame: Option<Entity<GitBlame>>,
 1150    blame_subscription: Option<Subscription>,
 1151    custom_context_menu: Option<
 1152        Box<
 1153            dyn 'static
 1154                + Fn(
 1155                    &mut Self,
 1156                    DisplayPoint,
 1157                    &mut Window,
 1158                    &mut Context<Self>,
 1159                ) -> Option<Entity<ui::ContextMenu>>,
 1160        >,
 1161    >,
 1162    last_bounds: Option<Bounds<Pixels>>,
 1163    last_position_map: Option<Rc<PositionMap>>,
 1164    expect_bounds_change: Option<Bounds<Pixels>>,
 1165    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1166    tasks_update_task: Option<Task<()>>,
 1167    breakpoint_store: Option<Entity<BreakpointStore>>,
 1168    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1169    hovered_diff_hunk_row: Option<DisplayRow>,
 1170    pull_diagnostics_task: Task<()>,
 1171    in_project_search: bool,
 1172    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1173    breadcrumb_header: Option<String>,
 1174    focused_block: Option<FocusedBlock>,
 1175    next_scroll_position: NextScrollCursorCenterTopBottom,
 1176    addons: HashMap<TypeId, Box<dyn Addon>>,
 1177    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1178    load_diff_task: Option<Shared<Task<()>>>,
 1179    /// Whether we are temporarily displaying a diff other than git's
 1180    temporary_diff_override: bool,
 1181    selection_mark_mode: bool,
 1182    toggle_fold_multiple_buffers: Task<()>,
 1183    _scroll_cursor_center_top_bottom_task: Task<()>,
 1184    serialize_selections: Task<()>,
 1185    serialize_folds: Task<()>,
 1186    mouse_cursor_hidden: bool,
 1187    minimap: Option<Entity<Self>>,
 1188    hide_mouse_mode: HideMouseMode,
 1189    pub change_list: ChangeList,
 1190    inline_value_cache: InlineValueCache,
 1191    selection_drag_state: SelectionDragState,
 1192    colors: Option<LspColorData>,
 1193    folding_newlines: Task<()>,
 1194    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1195}
 1196
 1197#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1198enum NextScrollCursorCenterTopBottom {
 1199    #[default]
 1200    Center,
 1201    Top,
 1202    Bottom,
 1203}
 1204
 1205impl NextScrollCursorCenterTopBottom {
 1206    fn next(&self) -> Self {
 1207        match self {
 1208            Self::Center => Self::Top,
 1209            Self::Top => Self::Bottom,
 1210            Self::Bottom => Self::Center,
 1211        }
 1212    }
 1213}
 1214
 1215#[derive(Clone)]
 1216pub struct EditorSnapshot {
 1217    pub mode: EditorMode,
 1218    show_gutter: bool,
 1219    show_line_numbers: Option<bool>,
 1220    show_git_diff_gutter: Option<bool>,
 1221    show_code_actions: Option<bool>,
 1222    show_runnables: Option<bool>,
 1223    show_breakpoints: Option<bool>,
 1224    git_blame_gutter_max_author_length: Option<usize>,
 1225    pub display_snapshot: DisplaySnapshot,
 1226    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1227    is_focused: bool,
 1228    scroll_anchor: ScrollAnchor,
 1229    ongoing_scroll: OngoingScroll,
 1230    current_line_highlight: CurrentLineHighlight,
 1231    gutter_hovered: bool,
 1232}
 1233
 1234#[derive(Default, Debug, Clone, Copy)]
 1235pub struct GutterDimensions {
 1236    pub left_padding: Pixels,
 1237    pub right_padding: Pixels,
 1238    pub width: Pixels,
 1239    pub margin: Pixels,
 1240    pub git_blame_entries_width: Option<Pixels>,
 1241}
 1242
 1243impl GutterDimensions {
 1244    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1245        Self {
 1246            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1247            ..Default::default()
 1248        }
 1249    }
 1250
 1251    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1252        -cx.text_system().descent(font_id, font_size)
 1253    }
 1254    /// The full width of the space taken up by the gutter.
 1255    pub fn full_width(&self) -> Pixels {
 1256        self.margin + self.width
 1257    }
 1258
 1259    /// The width of the space reserved for the fold indicators,
 1260    /// use alongside 'justify_end' and `gutter_width` to
 1261    /// right align content with the line numbers
 1262    pub fn fold_area_width(&self) -> Pixels {
 1263        self.margin + self.right_padding
 1264    }
 1265}
 1266
 1267struct CharacterDimensions {
 1268    em_width: Pixels,
 1269    em_advance: Pixels,
 1270    line_height: Pixels,
 1271}
 1272
 1273#[derive(Debug)]
 1274pub struct RemoteSelection {
 1275    pub replica_id: ReplicaId,
 1276    pub selection: Selection<Anchor>,
 1277    pub cursor_shape: CursorShape,
 1278    pub collaborator_id: CollaboratorId,
 1279    pub line_mode: bool,
 1280    pub user_name: Option<SharedString>,
 1281    pub color: PlayerColor,
 1282}
 1283
 1284#[derive(Clone, Debug)]
 1285struct SelectionHistoryEntry {
 1286    selections: Arc<[Selection<Anchor>]>,
 1287    select_next_state: Option<SelectNextState>,
 1288    select_prev_state: Option<SelectNextState>,
 1289    add_selections_state: Option<AddSelectionsState>,
 1290}
 1291
 1292#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1293enum SelectionHistoryMode {
 1294    Normal,
 1295    Undoing,
 1296    Redoing,
 1297    Skipping,
 1298}
 1299
 1300#[derive(Clone, PartialEq, Eq, Hash)]
 1301struct HoveredCursor {
 1302    replica_id: u16,
 1303    selection_id: usize,
 1304}
 1305
 1306impl Default for SelectionHistoryMode {
 1307    fn default() -> Self {
 1308        Self::Normal
 1309    }
 1310}
 1311
 1312#[derive(Debug)]
 1313/// SelectionEffects controls the side-effects of updating the selection.
 1314///
 1315/// The default behaviour does "what you mostly want":
 1316/// - it pushes to the nav history if the cursor moved by >10 lines
 1317/// - it re-triggers completion requests
 1318/// - it scrolls to fit
 1319///
 1320/// You might want to modify these behaviours. For example when doing a "jump"
 1321/// like go to definition, we always want to add to nav history; but when scrolling
 1322/// in vim mode we never do.
 1323///
 1324/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1325/// move.
 1326#[derive(Clone)]
 1327pub struct SelectionEffects {
 1328    nav_history: Option<bool>,
 1329    completions: bool,
 1330    scroll: Option<Autoscroll>,
 1331}
 1332
 1333impl Default for SelectionEffects {
 1334    fn default() -> Self {
 1335        Self {
 1336            nav_history: None,
 1337            completions: true,
 1338            scroll: Some(Autoscroll::fit()),
 1339        }
 1340    }
 1341}
 1342impl SelectionEffects {
 1343    pub fn scroll(scroll: Autoscroll) -> Self {
 1344        Self {
 1345            scroll: Some(scroll),
 1346            ..Default::default()
 1347        }
 1348    }
 1349
 1350    pub fn no_scroll() -> Self {
 1351        Self {
 1352            scroll: None,
 1353            ..Default::default()
 1354        }
 1355    }
 1356
 1357    pub fn completions(self, completions: bool) -> Self {
 1358        Self {
 1359            completions,
 1360            ..self
 1361        }
 1362    }
 1363
 1364    pub fn nav_history(self, nav_history: bool) -> Self {
 1365        Self {
 1366            nav_history: Some(nav_history),
 1367            ..self
 1368        }
 1369    }
 1370}
 1371
 1372struct DeferredSelectionEffectsState {
 1373    changed: bool,
 1374    effects: SelectionEffects,
 1375    old_cursor_position: Anchor,
 1376    history_entry: SelectionHistoryEntry,
 1377}
 1378
 1379#[derive(Default)]
 1380struct SelectionHistory {
 1381    #[allow(clippy::type_complexity)]
 1382    selections_by_transaction:
 1383        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1384    mode: SelectionHistoryMode,
 1385    undo_stack: VecDeque<SelectionHistoryEntry>,
 1386    redo_stack: VecDeque<SelectionHistoryEntry>,
 1387}
 1388
 1389impl SelectionHistory {
 1390    #[track_caller]
 1391    fn insert_transaction(
 1392        &mut self,
 1393        transaction_id: TransactionId,
 1394        selections: Arc<[Selection<Anchor>]>,
 1395    ) {
 1396        if selections.is_empty() {
 1397            log::error!(
 1398                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1399                std::panic::Location::caller()
 1400            );
 1401            return;
 1402        }
 1403        self.selections_by_transaction
 1404            .insert(transaction_id, (selections, None));
 1405    }
 1406
 1407    #[allow(clippy::type_complexity)]
 1408    fn transaction(
 1409        &self,
 1410        transaction_id: TransactionId,
 1411    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1412        self.selections_by_transaction.get(&transaction_id)
 1413    }
 1414
 1415    #[allow(clippy::type_complexity)]
 1416    fn transaction_mut(
 1417        &mut self,
 1418        transaction_id: TransactionId,
 1419    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1420        self.selections_by_transaction.get_mut(&transaction_id)
 1421    }
 1422
 1423    fn push(&mut self, entry: SelectionHistoryEntry) {
 1424        if !entry.selections.is_empty() {
 1425            match self.mode {
 1426                SelectionHistoryMode::Normal => {
 1427                    self.push_undo(entry);
 1428                    self.redo_stack.clear();
 1429                }
 1430                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1431                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1432                SelectionHistoryMode::Skipping => {}
 1433            }
 1434        }
 1435    }
 1436
 1437    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1438        if self
 1439            .undo_stack
 1440            .back()
 1441            .is_none_or(|e| e.selections != entry.selections)
 1442        {
 1443            self.undo_stack.push_back(entry);
 1444            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1445                self.undo_stack.pop_front();
 1446            }
 1447        }
 1448    }
 1449
 1450    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1451        if self
 1452            .redo_stack
 1453            .back()
 1454            .is_none_or(|e| e.selections != entry.selections)
 1455        {
 1456            self.redo_stack.push_back(entry);
 1457            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1458                self.redo_stack.pop_front();
 1459            }
 1460        }
 1461    }
 1462}
 1463
 1464#[derive(Clone, Copy)]
 1465pub struct RowHighlightOptions {
 1466    pub autoscroll: bool,
 1467    pub include_gutter: bool,
 1468}
 1469
 1470impl Default for RowHighlightOptions {
 1471    fn default() -> Self {
 1472        Self {
 1473            autoscroll: Default::default(),
 1474            include_gutter: true,
 1475        }
 1476    }
 1477}
 1478
 1479struct RowHighlight {
 1480    index: usize,
 1481    range: Range<Anchor>,
 1482    color: Hsla,
 1483    options: RowHighlightOptions,
 1484    type_id: TypeId,
 1485}
 1486
 1487#[derive(Clone, Debug)]
 1488struct AddSelectionsState {
 1489    groups: Vec<AddSelectionsGroup>,
 1490}
 1491
 1492#[derive(Clone, Debug)]
 1493struct AddSelectionsGroup {
 1494    above: bool,
 1495    stack: Vec<usize>,
 1496}
 1497
 1498#[derive(Clone)]
 1499struct SelectNextState {
 1500    query: AhoCorasick,
 1501    wordwise: bool,
 1502    done: bool,
 1503}
 1504
 1505impl std::fmt::Debug for SelectNextState {
 1506    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1507        f.debug_struct(std::any::type_name::<Self>())
 1508            .field("wordwise", &self.wordwise)
 1509            .field("done", &self.done)
 1510            .finish()
 1511    }
 1512}
 1513
 1514#[derive(Debug)]
 1515struct AutocloseRegion {
 1516    selection_id: usize,
 1517    range: Range<Anchor>,
 1518    pair: BracketPair,
 1519}
 1520
 1521#[derive(Debug)]
 1522struct SnippetState {
 1523    ranges: Vec<Vec<Range<Anchor>>>,
 1524    active_index: usize,
 1525    choices: Vec<Option<Vec<String>>>,
 1526}
 1527
 1528#[doc(hidden)]
 1529pub struct RenameState {
 1530    pub range: Range<Anchor>,
 1531    pub old_name: Arc<str>,
 1532    pub editor: Entity<Editor>,
 1533    block_id: CustomBlockId,
 1534}
 1535
 1536struct InvalidationStack<T>(Vec<T>);
 1537
 1538struct RegisteredEditPredictionProvider {
 1539    provider: Arc<dyn EditPredictionProviderHandle>,
 1540    _subscription: Subscription,
 1541}
 1542
 1543#[derive(Debug, PartialEq, Eq)]
 1544pub struct ActiveDiagnosticGroup {
 1545    pub active_range: Range<Anchor>,
 1546    pub active_message: String,
 1547    pub group_id: usize,
 1548    pub blocks: HashSet<CustomBlockId>,
 1549}
 1550
 1551#[derive(Debug, PartialEq, Eq)]
 1552
 1553pub(crate) enum ActiveDiagnostic {
 1554    None,
 1555    All,
 1556    Group(ActiveDiagnosticGroup),
 1557}
 1558
 1559#[derive(Serialize, Deserialize, Clone, Debug)]
 1560pub struct ClipboardSelection {
 1561    /// The number of bytes in this selection.
 1562    pub len: usize,
 1563    /// Whether this was a full-line selection.
 1564    pub is_entire_line: bool,
 1565    /// The indentation of the first line when this content was originally copied.
 1566    pub first_line_indent: u32,
 1567}
 1568
 1569// selections, scroll behavior, was newest selection reversed
 1570type SelectSyntaxNodeHistoryState = (
 1571    Box<[Selection<usize>]>,
 1572    SelectSyntaxNodeScrollBehavior,
 1573    bool,
 1574);
 1575
 1576#[derive(Default)]
 1577struct SelectSyntaxNodeHistory {
 1578    stack: Vec<SelectSyntaxNodeHistoryState>,
 1579    // disable temporarily to allow changing selections without losing the stack
 1580    pub disable_clearing: bool,
 1581}
 1582
 1583impl SelectSyntaxNodeHistory {
 1584    pub fn try_clear(&mut self) {
 1585        if !self.disable_clearing {
 1586            self.stack.clear();
 1587        }
 1588    }
 1589
 1590    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1591        self.stack.push(selection);
 1592    }
 1593
 1594    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1595        self.stack.pop()
 1596    }
 1597}
 1598
 1599enum SelectSyntaxNodeScrollBehavior {
 1600    CursorTop,
 1601    FitSelection,
 1602    CursorBottom,
 1603}
 1604
 1605#[derive(Debug)]
 1606pub(crate) struct NavigationData {
 1607    cursor_anchor: Anchor,
 1608    cursor_position: Point,
 1609    scroll_anchor: ScrollAnchor,
 1610    scroll_top_row: u32,
 1611}
 1612
 1613#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1614pub enum GotoDefinitionKind {
 1615    Symbol,
 1616    Declaration,
 1617    Type,
 1618    Implementation,
 1619}
 1620
 1621#[derive(Debug, Clone)]
 1622enum InlayHintRefreshReason {
 1623    ModifiersChanged(bool),
 1624    Toggle(bool),
 1625    SettingsChange(InlayHintSettings),
 1626    NewLinesShown,
 1627    BufferEdited(HashSet<Arc<Language>>),
 1628    RefreshRequested,
 1629    ExcerptsRemoved(Vec<ExcerptId>),
 1630}
 1631
 1632impl InlayHintRefreshReason {
 1633    fn description(&self) -> &'static str {
 1634        match self {
 1635            Self::ModifiersChanged(_) => "modifiers changed",
 1636            Self::Toggle(_) => "toggle",
 1637            Self::SettingsChange(_) => "settings change",
 1638            Self::NewLinesShown => "new lines shown",
 1639            Self::BufferEdited(_) => "buffer edited",
 1640            Self::RefreshRequested => "refresh requested",
 1641            Self::ExcerptsRemoved(_) => "excerpts removed",
 1642        }
 1643    }
 1644}
 1645
 1646pub enum FormatTarget {
 1647    Buffers(HashSet<Entity<Buffer>>),
 1648    Ranges(Vec<Range<MultiBufferPoint>>),
 1649}
 1650
 1651pub(crate) struct FocusedBlock {
 1652    id: BlockId,
 1653    focus_handle: WeakFocusHandle,
 1654}
 1655
 1656#[derive(Clone)]
 1657enum JumpData {
 1658    MultiBufferRow {
 1659        row: MultiBufferRow,
 1660        line_offset_from_top: u32,
 1661    },
 1662    MultiBufferPoint {
 1663        excerpt_id: ExcerptId,
 1664        position: Point,
 1665        anchor: text::Anchor,
 1666        line_offset_from_top: u32,
 1667    },
 1668}
 1669
 1670pub enum MultibufferSelectionMode {
 1671    First,
 1672    All,
 1673}
 1674
 1675#[derive(Clone, Copy, Debug, Default)]
 1676pub struct RewrapOptions {
 1677    pub override_language_settings: bool,
 1678    pub preserve_existing_whitespace: bool,
 1679}
 1680
 1681impl Editor {
 1682    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1683        let buffer = cx.new(|cx| Buffer::local("", cx));
 1684        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1685        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1686    }
 1687
 1688    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1689        let buffer = cx.new(|cx| Buffer::local("", cx));
 1690        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1691        Self::new(EditorMode::full(), buffer, None, window, cx)
 1692    }
 1693
 1694    pub fn auto_height(
 1695        min_lines: usize,
 1696        max_lines: usize,
 1697        window: &mut Window,
 1698        cx: &mut Context<Self>,
 1699    ) -> Self {
 1700        let buffer = cx.new(|cx| Buffer::local("", cx));
 1701        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1702        Self::new(
 1703            EditorMode::AutoHeight {
 1704                min_lines,
 1705                max_lines: Some(max_lines),
 1706            },
 1707            buffer,
 1708            None,
 1709            window,
 1710            cx,
 1711        )
 1712    }
 1713
 1714    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1715    /// The editor grows as tall as needed to fit its content.
 1716    pub fn auto_height_unbounded(
 1717        min_lines: usize,
 1718        window: &mut Window,
 1719        cx: &mut Context<Self>,
 1720    ) -> Self {
 1721        let buffer = cx.new(|cx| Buffer::local("", cx));
 1722        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1723        Self::new(
 1724            EditorMode::AutoHeight {
 1725                min_lines,
 1726                max_lines: None,
 1727            },
 1728            buffer,
 1729            None,
 1730            window,
 1731            cx,
 1732        )
 1733    }
 1734
 1735    pub fn for_buffer(
 1736        buffer: Entity<Buffer>,
 1737        project: Option<Entity<Project>>,
 1738        window: &mut Window,
 1739        cx: &mut Context<Self>,
 1740    ) -> Self {
 1741        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1742        Self::new(EditorMode::full(), buffer, project, window, cx)
 1743    }
 1744
 1745    pub fn for_multibuffer(
 1746        buffer: Entity<MultiBuffer>,
 1747        project: Option<Entity<Project>>,
 1748        window: &mut Window,
 1749        cx: &mut Context<Self>,
 1750    ) -> Self {
 1751        Self::new(EditorMode::full(), buffer, project, window, cx)
 1752    }
 1753
 1754    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1755        let mut clone = Self::new(
 1756            self.mode.clone(),
 1757            self.buffer.clone(),
 1758            self.project.clone(),
 1759            window,
 1760            cx,
 1761        );
 1762        self.display_map.update(cx, |display_map, cx| {
 1763            let snapshot = display_map.snapshot(cx);
 1764            clone.display_map.update(cx, |display_map, cx| {
 1765                display_map.set_state(&snapshot, cx);
 1766            });
 1767        });
 1768        clone.folds_did_change(cx);
 1769        clone.selections.clone_state(&self.selections);
 1770        clone.scroll_manager.clone_state(&self.scroll_manager);
 1771        clone.searchable = self.searchable;
 1772        clone.read_only = self.read_only;
 1773        clone
 1774    }
 1775
 1776    pub fn new(
 1777        mode: EditorMode,
 1778        buffer: Entity<MultiBuffer>,
 1779        project: Option<Entity<Project>>,
 1780        window: &mut Window,
 1781        cx: &mut Context<Self>,
 1782    ) -> Self {
 1783        Editor::new_internal(mode, buffer, project, None, window, cx)
 1784    }
 1785
 1786    fn new_internal(
 1787        mode: EditorMode,
 1788        buffer: Entity<MultiBuffer>,
 1789        project: Option<Entity<Project>>,
 1790        display_map: Option<Entity<DisplayMap>>,
 1791        window: &mut Window,
 1792        cx: &mut Context<Self>,
 1793    ) -> Self {
 1794        debug_assert!(
 1795            display_map.is_none() || mode.is_minimap(),
 1796            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1797        );
 1798
 1799        let full_mode = mode.is_full();
 1800        let is_minimap = mode.is_minimap();
 1801        let diagnostics_max_severity = if full_mode {
 1802            EditorSettings::get_global(cx)
 1803                .diagnostics_max_severity
 1804                .unwrap_or(DiagnosticSeverity::Hint)
 1805        } else {
 1806            DiagnosticSeverity::Off
 1807        };
 1808        let style = window.text_style();
 1809        let font_size = style.font_size.to_pixels(window.rem_size());
 1810        let editor = cx.entity().downgrade();
 1811        let fold_placeholder = FoldPlaceholder {
 1812            constrain_width: false,
 1813            render: Arc::new(move |fold_id, fold_range, cx| {
 1814                let editor = editor.clone();
 1815                div()
 1816                    .id(fold_id)
 1817                    .bg(cx.theme().colors().ghost_element_background)
 1818                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1819                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1820                    .rounded_xs()
 1821                    .size_full()
 1822                    .cursor_pointer()
 1823                    .child("")
 1824                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1825                    .on_click(move |_, _window, cx| {
 1826                        editor
 1827                            .update(cx, |editor, cx| {
 1828                                editor.unfold_ranges(
 1829                                    &[fold_range.start..fold_range.end],
 1830                                    true,
 1831                                    false,
 1832                                    cx,
 1833                                );
 1834                                cx.stop_propagation();
 1835                            })
 1836                            .ok();
 1837                    })
 1838                    .into_any()
 1839            }),
 1840            merge_adjacent: true,
 1841            ..FoldPlaceholder::default()
 1842        };
 1843        let display_map = display_map.unwrap_or_else(|| {
 1844            cx.new(|cx| {
 1845                DisplayMap::new(
 1846                    buffer.clone(),
 1847                    style.font(),
 1848                    font_size,
 1849                    None,
 1850                    FILE_HEADER_HEIGHT,
 1851                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1852                    fold_placeholder,
 1853                    diagnostics_max_severity,
 1854                    cx,
 1855                )
 1856            })
 1857        });
 1858
 1859        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1860
 1861        let blink_manager = cx.new(|cx| {
 1862            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1863            if is_minimap {
 1864                blink_manager.disable(cx);
 1865            }
 1866            blink_manager
 1867        });
 1868
 1869        let soft_wrap_mode_override =
 1870            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1871
 1872        let mut project_subscriptions = Vec::new();
 1873        if full_mode && let Some(project) = project.as_ref() {
 1874            project_subscriptions.push(cx.subscribe_in(
 1875                project,
 1876                window,
 1877                |editor, _, event, window, cx| match event {
 1878                    project::Event::RefreshCodeLens => {
 1879                        // we always query lens with actions, without storing them, always refreshing them
 1880                    }
 1881                    project::Event::RefreshInlayHints => {
 1882                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1883                    }
 1884                    project::Event::LanguageServerAdded(..)
 1885                    | project::Event::LanguageServerRemoved(..) => {
 1886                        if editor.tasks_update_task.is_none() {
 1887                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1888                        }
 1889                    }
 1890                    project::Event::SnippetEdit(id, snippet_edits) => {
 1891                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1892                            let focus_handle = editor.focus_handle(cx);
 1893                            if focus_handle.is_focused(window) {
 1894                                let snapshot = buffer.read(cx).snapshot();
 1895                                for (range, snippet) in snippet_edits {
 1896                                    let editor_range =
 1897                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1898                                    editor
 1899                                        .insert_snippet(
 1900                                            &[editor_range],
 1901                                            snippet.clone(),
 1902                                            window,
 1903                                            cx,
 1904                                        )
 1905                                        .ok();
 1906                                }
 1907                            }
 1908                        }
 1909                    }
 1910                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1911                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1912                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1913                        }
 1914                    }
 1915
 1916                    project::Event::EntryRenamed(transaction) => {
 1917                        let Some(workspace) = editor.workspace() else {
 1918                            return;
 1919                        };
 1920                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1921                        else {
 1922                            return;
 1923                        };
 1924                        if active_editor.entity_id() == cx.entity_id() {
 1925                            let edited_buffers_already_open = {
 1926                                let other_editors: Vec<Entity<Editor>> = workspace
 1927                                    .read(cx)
 1928                                    .panes()
 1929                                    .iter()
 1930                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1931                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1932                                    .collect();
 1933
 1934                                transaction.0.keys().all(|buffer| {
 1935                                    other_editors.iter().any(|editor| {
 1936                                        let multi_buffer = editor.read(cx).buffer();
 1937                                        multi_buffer.read(cx).is_singleton()
 1938                                            && multi_buffer.read(cx).as_singleton().map_or(
 1939                                                false,
 1940                                                |singleton| {
 1941                                                    singleton.entity_id() == buffer.entity_id()
 1942                                                },
 1943                                            )
 1944                                    })
 1945                                })
 1946                            };
 1947
 1948                            if !edited_buffers_already_open {
 1949                                let workspace = workspace.downgrade();
 1950                                let transaction = transaction.clone();
 1951                                cx.defer_in(window, move |_, window, cx| {
 1952                                    cx.spawn_in(window, async move |editor, cx| {
 1953                                        Self::open_project_transaction(
 1954                                            &editor,
 1955                                            workspace,
 1956                                            transaction,
 1957                                            "Rename".to_string(),
 1958                                            cx,
 1959                                        )
 1960                                        .await
 1961                                        .ok()
 1962                                    })
 1963                                    .detach();
 1964                                });
 1965                            }
 1966                        }
 1967                    }
 1968
 1969                    _ => {}
 1970                },
 1971            ));
 1972            if let Some(task_inventory) = project
 1973                .read(cx)
 1974                .task_store()
 1975                .read(cx)
 1976                .task_inventory()
 1977                .cloned()
 1978            {
 1979                project_subscriptions.push(cx.observe_in(
 1980                    &task_inventory,
 1981                    window,
 1982                    |editor, _, window, cx| {
 1983                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1984                    },
 1985                ));
 1986            };
 1987
 1988            project_subscriptions.push(cx.subscribe_in(
 1989                &project.read(cx).breakpoint_store(),
 1990                window,
 1991                |editor, _, event, window, cx| match event {
 1992                    BreakpointStoreEvent::ClearDebugLines => {
 1993                        editor.clear_row_highlights::<ActiveDebugLine>();
 1994                        editor.refresh_inline_values(cx);
 1995                    }
 1996                    BreakpointStoreEvent::SetDebugLine => {
 1997                        if editor.go_to_active_debug_line(window, cx) {
 1998                            cx.stop_propagation();
 1999                        }
 2000
 2001                        editor.refresh_inline_values(cx);
 2002                    }
 2003                    _ => {}
 2004                },
 2005            ));
 2006            let git_store = project.read(cx).git_store().clone();
 2007            let project = project.clone();
 2008            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2009                if let GitStoreEvent::RepositoryUpdated(
 2010                    _,
 2011                    RepositoryEvent::Updated {
 2012                        new_instance: true, ..
 2013                    },
 2014                    _,
 2015                ) = event
 2016                {
 2017                    this.load_diff_task = Some(
 2018                        update_uncommitted_diff_for_buffer(
 2019                            cx.entity(),
 2020                            &project,
 2021                            this.buffer.read(cx).all_buffers(),
 2022                            this.buffer.clone(),
 2023                            cx,
 2024                        )
 2025                        .shared(),
 2026                    );
 2027                }
 2028            }));
 2029        }
 2030
 2031        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2032
 2033        let inlay_hint_settings =
 2034            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2035        let focus_handle = cx.focus_handle();
 2036        if !is_minimap {
 2037            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2038                .detach();
 2039            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2040                .detach();
 2041            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2042                .detach();
 2043            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2044                .detach();
 2045            cx.observe_pending_input(window, Self::observe_pending_input)
 2046                .detach();
 2047        }
 2048
 2049        let show_indent_guides =
 2050            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2051                Some(false)
 2052            } else {
 2053                None
 2054            };
 2055
 2056        let breakpoint_store = match (&mode, project.as_ref()) {
 2057            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2058            _ => None,
 2059        };
 2060
 2061        let mut code_action_providers = Vec::new();
 2062        let mut load_uncommitted_diff = None;
 2063        if let Some(project) = project.clone() {
 2064            load_uncommitted_diff = Some(
 2065                update_uncommitted_diff_for_buffer(
 2066                    cx.entity(),
 2067                    &project,
 2068                    buffer.read(cx).all_buffers(),
 2069                    buffer.clone(),
 2070                    cx,
 2071                )
 2072                .shared(),
 2073            );
 2074            code_action_providers.push(Rc::new(project) as Rc<_>);
 2075        }
 2076
 2077        let mut editor = Self {
 2078            focus_handle,
 2079            show_cursor_when_unfocused: false,
 2080            last_focused_descendant: None,
 2081            buffer: buffer.clone(),
 2082            display_map: display_map.clone(),
 2083            placeholder_display_map: None,
 2084            selections,
 2085            scroll_manager: ScrollManager::new(cx),
 2086            columnar_selection_state: None,
 2087            add_selections_state: None,
 2088            select_next_state: None,
 2089            select_prev_state: None,
 2090            selection_history: SelectionHistory::default(),
 2091            defer_selection_effects: false,
 2092            deferred_selection_effects_state: None,
 2093            autoclose_regions: Vec::new(),
 2094            snippet_stack: InvalidationStack::default(),
 2095            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2096            ime_transaction: None,
 2097            active_diagnostics: ActiveDiagnostic::None,
 2098            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2099            inline_diagnostics_update: Task::ready(()),
 2100            inline_diagnostics: Vec::new(),
 2101            soft_wrap_mode_override,
 2102            diagnostics_max_severity,
 2103            hard_wrap: None,
 2104            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2105            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2106            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2107            project,
 2108            blink_manager: blink_manager.clone(),
 2109            show_local_selections: true,
 2110            show_scrollbars: ScrollbarAxes {
 2111                horizontal: full_mode,
 2112                vertical: full_mode,
 2113            },
 2114            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2115            offset_content: !matches!(mode, EditorMode::SingleLine),
 2116            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2117            show_gutter: full_mode,
 2118            show_line_numbers: (!full_mode).then_some(false),
 2119            use_relative_line_numbers: None,
 2120            disable_expand_excerpt_buttons: !full_mode,
 2121            show_git_diff_gutter: None,
 2122            show_code_actions: None,
 2123            show_runnables: None,
 2124            show_breakpoints: None,
 2125            show_wrap_guides: None,
 2126            show_indent_guides,
 2127            highlight_order: 0,
 2128            highlighted_rows: HashMap::default(),
 2129            background_highlights: HashMap::default(),
 2130            gutter_highlights: HashMap::default(),
 2131            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2132            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2133            nav_history: None,
 2134            context_menu: RefCell::new(None),
 2135            context_menu_options: None,
 2136            mouse_context_menu: None,
 2137            completion_tasks: Vec::new(),
 2138            inline_blame_popover: None,
 2139            inline_blame_popover_show_task: None,
 2140            signature_help_state: SignatureHelpState::default(),
 2141            auto_signature_help: None,
 2142            find_all_references_task_sources: Vec::new(),
 2143            next_completion_id: 0,
 2144            next_inlay_id: 0,
 2145            code_action_providers,
 2146            available_code_actions: None,
 2147            code_actions_task: None,
 2148            quick_selection_highlight_task: None,
 2149            debounced_selection_highlight_task: None,
 2150            document_highlights_task: None,
 2151            linked_editing_range_task: None,
 2152            pending_rename: None,
 2153            searchable: !is_minimap,
 2154            cursor_shape: EditorSettings::get_global(cx)
 2155                .cursor_shape
 2156                .unwrap_or_default(),
 2157            current_line_highlight: None,
 2158            autoindent_mode: Some(AutoindentMode::EachLine),
 2159            collapse_matches: false,
 2160            workspace: None,
 2161            input_enabled: !is_minimap,
 2162            use_modal_editing: full_mode,
 2163            read_only: is_minimap,
 2164            use_autoclose: true,
 2165            use_auto_surround: true,
 2166            auto_replace_emoji_shortcode: false,
 2167            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2168            leader_id: None,
 2169            remote_id: None,
 2170            hover_state: HoverState::default(),
 2171            pending_mouse_down: None,
 2172            hovered_link_state: None,
 2173            edit_prediction_provider: None,
 2174            active_edit_prediction: None,
 2175            stale_edit_prediction_in_menu: None,
 2176            edit_prediction_preview: EditPredictionPreview::Inactive {
 2177                released_too_fast: false,
 2178            },
 2179            inline_diagnostics_enabled: full_mode,
 2180            diagnostics_enabled: full_mode,
 2181            word_completions_enabled: full_mode,
 2182            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2183            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2184            gutter_hovered: false,
 2185            pixel_position_of_newest_cursor: None,
 2186            last_bounds: None,
 2187            last_position_map: None,
 2188            expect_bounds_change: None,
 2189            gutter_dimensions: GutterDimensions::default(),
 2190            style: None,
 2191            show_cursor_names: false,
 2192            hovered_cursors: HashMap::default(),
 2193            next_editor_action_id: EditorActionId::default(),
 2194            editor_actions: Rc::default(),
 2195            edit_predictions_hidden_for_vim_mode: false,
 2196            show_edit_predictions_override: None,
 2197            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2198            edit_prediction_settings: EditPredictionSettings::Disabled,
 2199            edit_prediction_indent_conflict: false,
 2200            edit_prediction_requires_modifier_in_indent_conflict: true,
 2201            custom_context_menu: None,
 2202            show_git_blame_gutter: false,
 2203            show_git_blame_inline: false,
 2204            show_selection_menu: None,
 2205            show_git_blame_inline_delay_task: None,
 2206            git_blame_inline_enabled: full_mode
 2207                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2208            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2209            serialize_dirty_buffers: !is_minimap
 2210                && ProjectSettings::get_global(cx)
 2211                    .session
 2212                    .restore_unsaved_buffers,
 2213            blame: None,
 2214            blame_subscription: None,
 2215            tasks: BTreeMap::default(),
 2216
 2217            breakpoint_store,
 2218            gutter_breakpoint_indicator: (None, None),
 2219            hovered_diff_hunk_row: None,
 2220            _subscriptions: (!is_minimap)
 2221                .then(|| {
 2222                    vec![
 2223                        cx.observe(&buffer, Self::on_buffer_changed),
 2224                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2225                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2226                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2227                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2228                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2229                        cx.observe_window_activation(window, |editor, window, cx| {
 2230                            let active = window.is_window_active();
 2231                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2232                                if active {
 2233                                    blink_manager.enable(cx);
 2234                                } else {
 2235                                    blink_manager.disable(cx);
 2236                                }
 2237                            });
 2238                            if active {
 2239                                editor.show_mouse_cursor(cx);
 2240                            }
 2241                        }),
 2242                    ]
 2243                })
 2244                .unwrap_or_default(),
 2245            tasks_update_task: None,
 2246            pull_diagnostics_task: Task::ready(()),
 2247            colors: None,
 2248            next_color_inlay_id: 0,
 2249            linked_edit_ranges: Default::default(),
 2250            in_project_search: false,
 2251            previous_search_ranges: None,
 2252            breadcrumb_header: None,
 2253            focused_block: None,
 2254            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2255            addons: HashMap::default(),
 2256            registered_buffers: HashMap::default(),
 2257            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2258            selection_mark_mode: false,
 2259            toggle_fold_multiple_buffers: Task::ready(()),
 2260            serialize_selections: Task::ready(()),
 2261            serialize_folds: Task::ready(()),
 2262            text_style_refinement: None,
 2263            load_diff_task: load_uncommitted_diff,
 2264            temporary_diff_override: false,
 2265            mouse_cursor_hidden: false,
 2266            minimap: None,
 2267            hide_mouse_mode: EditorSettings::get_global(cx)
 2268                .hide_mouse
 2269                .unwrap_or_default(),
 2270            change_list: ChangeList::new(),
 2271            mode,
 2272            selection_drag_state: SelectionDragState::None,
 2273            folding_newlines: Task::ready(()),
 2274            lookup_key: None,
 2275        };
 2276
 2277        if is_minimap {
 2278            return editor;
 2279        }
 2280
 2281        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2282            editor
 2283                ._subscriptions
 2284                .push(cx.observe(breakpoints, |_, _, cx| {
 2285                    cx.notify();
 2286                }));
 2287        }
 2288        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2289        editor._subscriptions.extend(project_subscriptions);
 2290
 2291        editor._subscriptions.push(cx.subscribe_in(
 2292            &cx.entity(),
 2293            window,
 2294            |editor, _, e: &EditorEvent, window, cx| match e {
 2295                EditorEvent::ScrollPositionChanged { local, .. } => {
 2296                    if *local {
 2297                        let new_anchor = editor.scroll_manager.anchor();
 2298                        let snapshot = editor.snapshot(window, cx);
 2299                        editor.update_restoration_data(cx, move |data| {
 2300                            data.scroll_position = (
 2301                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2302                                new_anchor.offset,
 2303                            );
 2304                        });
 2305                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2306                        editor.inline_blame_popover.take();
 2307                    }
 2308                }
 2309                EditorEvent::Edited { .. } => {
 2310                    if !vim_enabled(cx) {
 2311                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2312                        let pop_state = editor
 2313                            .change_list
 2314                            .last()
 2315                            .map(|previous| {
 2316                                previous.len() == selections.len()
 2317                                    && previous.iter().enumerate().all(|(ix, p)| {
 2318                                        p.to_display_point(&map).row()
 2319                                            == selections[ix].head().row()
 2320                                    })
 2321                            })
 2322                            .unwrap_or(false);
 2323                        let new_positions = selections
 2324                            .into_iter()
 2325                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2326                            .collect();
 2327                        editor
 2328                            .change_list
 2329                            .push_to_change_list(pop_state, new_positions);
 2330                    }
 2331                }
 2332                _ => (),
 2333            },
 2334        ));
 2335
 2336        if let Some(dap_store) = editor
 2337            .project
 2338            .as_ref()
 2339            .map(|project| project.read(cx).dap_store())
 2340        {
 2341            let weak_editor = cx.weak_entity();
 2342
 2343            editor
 2344                ._subscriptions
 2345                .push(
 2346                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2347                        let session_entity = cx.entity();
 2348                        weak_editor
 2349                            .update(cx, |editor, cx| {
 2350                                editor._subscriptions.push(
 2351                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2352                                );
 2353                            })
 2354                            .ok();
 2355                    }),
 2356                );
 2357
 2358            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2359                editor
 2360                    ._subscriptions
 2361                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2362            }
 2363        }
 2364
 2365        // skip adding the initial selection to selection history
 2366        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2367        editor.end_selection(window, cx);
 2368        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2369
 2370        editor.scroll_manager.show_scrollbars(window, cx);
 2371        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2372
 2373        if full_mode {
 2374            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2375            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2376
 2377            if editor.git_blame_inline_enabled {
 2378                editor.start_git_blame_inline(false, window, cx);
 2379            }
 2380
 2381            editor.go_to_active_debug_line(window, cx);
 2382
 2383            if let Some(buffer) = buffer.read(cx).as_singleton()
 2384                && let Some(project) = editor.project()
 2385            {
 2386                let handle = project.update(cx, |project, cx| {
 2387                    project.register_buffer_with_language_servers(&buffer, cx)
 2388                });
 2389                editor
 2390                    .registered_buffers
 2391                    .insert(buffer.read(cx).remote_id(), handle);
 2392            }
 2393
 2394            editor.minimap =
 2395                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2396            editor.colors = Some(LspColorData::new(cx));
 2397            editor.update_lsp_data(false, None, window, cx);
 2398        }
 2399
 2400        if editor.mode.is_full() {
 2401            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2402        }
 2403
 2404        editor
 2405    }
 2406
 2407    pub fn deploy_mouse_context_menu(
 2408        &mut self,
 2409        position: gpui::Point<Pixels>,
 2410        context_menu: Entity<ContextMenu>,
 2411        window: &mut Window,
 2412        cx: &mut Context<Self>,
 2413    ) {
 2414        self.mouse_context_menu = Some(MouseContextMenu::new(
 2415            self,
 2416            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2417            context_menu,
 2418            window,
 2419            cx,
 2420        ));
 2421    }
 2422
 2423    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2424        self.mouse_context_menu
 2425            .as_ref()
 2426            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2427    }
 2428
 2429    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2430        if self
 2431            .selections
 2432            .pending_anchor()
 2433            .is_some_and(|pending_selection| {
 2434                let snapshot = self.buffer().read(cx).snapshot(cx);
 2435                pending_selection.range().includes(range, &snapshot)
 2436            })
 2437        {
 2438            return true;
 2439        }
 2440
 2441        self.selections
 2442            .disjoint_in_range::<usize>(range.clone(), cx)
 2443            .into_iter()
 2444            .any(|selection| {
 2445                // This is needed to cover a corner case, if we just check for an existing
 2446                // selection in the fold range, having a cursor at the start of the fold
 2447                // marks it as selected. Non-empty selections don't cause this.
 2448                let length = selection.end - selection.start;
 2449                length > 0
 2450            })
 2451    }
 2452
 2453    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2454        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2455    }
 2456
 2457    fn key_context_internal(
 2458        &self,
 2459        has_active_edit_prediction: bool,
 2460        window: &Window,
 2461        cx: &App,
 2462    ) -> KeyContext {
 2463        let mut key_context = KeyContext::new_with_defaults();
 2464        key_context.add("Editor");
 2465        let mode = match self.mode {
 2466            EditorMode::SingleLine => "single_line",
 2467            EditorMode::AutoHeight { .. } => "auto_height",
 2468            EditorMode::Minimap { .. } => "minimap",
 2469            EditorMode::Full { .. } => "full",
 2470        };
 2471
 2472        if EditorSettings::jupyter_enabled(cx) {
 2473            key_context.add("jupyter");
 2474        }
 2475
 2476        key_context.set("mode", mode);
 2477        if self.pending_rename.is_some() {
 2478            key_context.add("renaming");
 2479        }
 2480
 2481        match self.context_menu.borrow().as_ref() {
 2482            Some(CodeContextMenu::Completions(menu)) => {
 2483                if menu.visible() {
 2484                    key_context.add("menu");
 2485                    key_context.add("showing_completions");
 2486                }
 2487            }
 2488            Some(CodeContextMenu::CodeActions(menu)) => {
 2489                if menu.visible() {
 2490                    key_context.add("menu");
 2491                    key_context.add("showing_code_actions")
 2492                }
 2493            }
 2494            None => {}
 2495        }
 2496
 2497        if self.signature_help_state.has_multiple_signatures() {
 2498            key_context.add("showing_signature_help");
 2499        }
 2500
 2501        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2502        if !self.focus_handle(cx).contains_focused(window, cx)
 2503            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2504        {
 2505            for addon in self.addons.values() {
 2506                addon.extend_key_context(&mut key_context, cx)
 2507            }
 2508        }
 2509
 2510        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2511            if let Some(extension) = singleton_buffer
 2512                .read(cx)
 2513                .file()
 2514                .and_then(|file| file.path().extension())
 2515            {
 2516                key_context.set("extension", extension.to_string());
 2517            }
 2518        } else {
 2519            key_context.add("multibuffer");
 2520        }
 2521
 2522        if has_active_edit_prediction {
 2523            if self.edit_prediction_in_conflict() {
 2524                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2525            } else {
 2526                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2527                key_context.add("copilot_suggestion");
 2528            }
 2529        }
 2530
 2531        if self.selection_mark_mode {
 2532            key_context.add("selection_mode");
 2533        }
 2534
 2535        key_context
 2536    }
 2537
 2538    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2539        self.last_bounds.as_ref()
 2540    }
 2541
 2542    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2543        if self.mouse_cursor_hidden {
 2544            self.mouse_cursor_hidden = false;
 2545            cx.notify();
 2546        }
 2547    }
 2548
 2549    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2550        let hide_mouse_cursor = match origin {
 2551            HideMouseCursorOrigin::TypingAction => {
 2552                matches!(
 2553                    self.hide_mouse_mode,
 2554                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2555                )
 2556            }
 2557            HideMouseCursorOrigin::MovementAction => {
 2558                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2559            }
 2560        };
 2561        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2562            self.mouse_cursor_hidden = hide_mouse_cursor;
 2563            cx.notify();
 2564        }
 2565    }
 2566
 2567    pub fn edit_prediction_in_conflict(&self) -> bool {
 2568        if !self.show_edit_predictions_in_menu() {
 2569            return false;
 2570        }
 2571
 2572        let showing_completions = self
 2573            .context_menu
 2574            .borrow()
 2575            .as_ref()
 2576            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2577
 2578        showing_completions
 2579            || self.edit_prediction_requires_modifier()
 2580            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2581            // bindings to insert tab characters.
 2582            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2583    }
 2584
 2585    pub fn accept_edit_prediction_keybind(
 2586        &self,
 2587        accept_partial: bool,
 2588        window: &Window,
 2589        cx: &App,
 2590    ) -> AcceptEditPredictionBinding {
 2591        let key_context = self.key_context_internal(true, window, cx);
 2592        let in_conflict = self.edit_prediction_in_conflict();
 2593
 2594        let bindings = if accept_partial {
 2595            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2596        } else {
 2597            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2598        };
 2599
 2600        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2601        // just the first one.
 2602        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2603            !in_conflict
 2604                || binding
 2605                    .keystrokes()
 2606                    .first()
 2607                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2608        }))
 2609    }
 2610
 2611    pub fn new_file(
 2612        workspace: &mut Workspace,
 2613        _: &workspace::NewFile,
 2614        window: &mut Window,
 2615        cx: &mut Context<Workspace>,
 2616    ) {
 2617        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2618            "Failed to create buffer",
 2619            window,
 2620            cx,
 2621            |e, _, _| match e.error_code() {
 2622                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2623                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2624                e.error_tag("required").unwrap_or("the latest version")
 2625            )),
 2626                _ => None,
 2627            },
 2628        );
 2629    }
 2630
 2631    pub fn new_in_workspace(
 2632        workspace: &mut Workspace,
 2633        window: &mut Window,
 2634        cx: &mut Context<Workspace>,
 2635    ) -> Task<Result<Entity<Editor>>> {
 2636        let project = workspace.project().clone();
 2637        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2638
 2639        cx.spawn_in(window, async move |workspace, cx| {
 2640            let buffer = create.await?;
 2641            workspace.update_in(cx, |workspace, window, cx| {
 2642                let editor =
 2643                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2644                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2645                editor
 2646            })
 2647        })
 2648    }
 2649
 2650    fn new_file_vertical(
 2651        workspace: &mut Workspace,
 2652        _: &workspace::NewFileSplitVertical,
 2653        window: &mut Window,
 2654        cx: &mut Context<Workspace>,
 2655    ) {
 2656        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2657    }
 2658
 2659    fn new_file_horizontal(
 2660        workspace: &mut Workspace,
 2661        _: &workspace::NewFileSplitHorizontal,
 2662        window: &mut Window,
 2663        cx: &mut Context<Workspace>,
 2664    ) {
 2665        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2666    }
 2667
 2668    fn new_file_in_direction(
 2669        workspace: &mut Workspace,
 2670        direction: SplitDirection,
 2671        window: &mut Window,
 2672        cx: &mut Context<Workspace>,
 2673    ) {
 2674        let project = workspace.project().clone();
 2675        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2676
 2677        cx.spawn_in(window, async move |workspace, cx| {
 2678            let buffer = create.await?;
 2679            workspace.update_in(cx, move |workspace, window, cx| {
 2680                workspace.split_item(
 2681                    direction,
 2682                    Box::new(
 2683                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2684                    ),
 2685                    window,
 2686                    cx,
 2687                )
 2688            })?;
 2689            anyhow::Ok(())
 2690        })
 2691        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2692            match e.error_code() {
 2693                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2694                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2695                e.error_tag("required").unwrap_or("the latest version")
 2696            )),
 2697                _ => None,
 2698            }
 2699        });
 2700    }
 2701
 2702    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2703        self.leader_id
 2704    }
 2705
 2706    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2707        &self.buffer
 2708    }
 2709
 2710    pub fn project(&self) -> Option<&Entity<Project>> {
 2711        self.project.as_ref()
 2712    }
 2713
 2714    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2715        self.workspace.as_ref()?.0.upgrade()
 2716    }
 2717
 2718    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2719        self.buffer().read(cx).title(cx)
 2720    }
 2721
 2722    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2723        let git_blame_gutter_max_author_length = self
 2724            .render_git_blame_gutter(cx)
 2725            .then(|| {
 2726                if let Some(blame) = self.blame.as_ref() {
 2727                    let max_author_length =
 2728                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2729                    Some(max_author_length)
 2730                } else {
 2731                    None
 2732                }
 2733            })
 2734            .flatten();
 2735
 2736        EditorSnapshot {
 2737            mode: self.mode.clone(),
 2738            show_gutter: self.show_gutter,
 2739            show_line_numbers: self.show_line_numbers,
 2740            show_git_diff_gutter: self.show_git_diff_gutter,
 2741            show_code_actions: self.show_code_actions,
 2742            show_runnables: self.show_runnables,
 2743            show_breakpoints: self.show_breakpoints,
 2744            git_blame_gutter_max_author_length,
 2745            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2746            placeholder_display_snapshot: self
 2747                .placeholder_display_map
 2748                .as_ref()
 2749                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2750            scroll_anchor: self.scroll_manager.anchor(),
 2751            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2752            is_focused: self.focus_handle.is_focused(window),
 2753            current_line_highlight: self
 2754                .current_line_highlight
 2755                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2756            gutter_hovered: self.gutter_hovered,
 2757        }
 2758    }
 2759
 2760    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2761        self.buffer.read(cx).language_at(point, cx)
 2762    }
 2763
 2764    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2765        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2766    }
 2767
 2768    pub fn active_excerpt(
 2769        &self,
 2770        cx: &App,
 2771    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2772        self.buffer
 2773            .read(cx)
 2774            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2775    }
 2776
 2777    pub fn mode(&self) -> &EditorMode {
 2778        &self.mode
 2779    }
 2780
 2781    pub fn set_mode(&mut self, mode: EditorMode) {
 2782        self.mode = mode;
 2783    }
 2784
 2785    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2786        self.collaboration_hub.as_deref()
 2787    }
 2788
 2789    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2790        self.collaboration_hub = Some(hub);
 2791    }
 2792
 2793    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2794        self.in_project_search = in_project_search;
 2795    }
 2796
 2797    pub fn set_custom_context_menu(
 2798        &mut self,
 2799        f: impl 'static
 2800        + Fn(
 2801            &mut Self,
 2802            DisplayPoint,
 2803            &mut Window,
 2804            &mut Context<Self>,
 2805        ) -> Option<Entity<ui::ContextMenu>>,
 2806    ) {
 2807        self.custom_context_menu = Some(Box::new(f))
 2808    }
 2809
 2810    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2811        self.completion_provider = provider;
 2812    }
 2813
 2814    #[cfg(any(test, feature = "test-support"))]
 2815    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2816        self.completion_provider.clone()
 2817    }
 2818
 2819    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2820        self.semantics_provider.clone()
 2821    }
 2822
 2823    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2824        self.semantics_provider = provider;
 2825    }
 2826
 2827    pub fn set_edit_prediction_provider<T>(
 2828        &mut self,
 2829        provider: Option<Entity<T>>,
 2830        window: &mut Window,
 2831        cx: &mut Context<Self>,
 2832    ) where
 2833        T: EditPredictionProvider,
 2834    {
 2835        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2836            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2837                if this.focus_handle.is_focused(window) {
 2838                    this.update_visible_edit_prediction(window, cx);
 2839                }
 2840            }),
 2841            provider: Arc::new(provider),
 2842        });
 2843        self.update_edit_prediction_settings(cx);
 2844        self.refresh_edit_prediction(false, false, window, cx);
 2845    }
 2846
 2847    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2848        self.placeholder_display_map
 2849            .as_ref()
 2850            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2851    }
 2852
 2853    pub fn set_placeholder_text(
 2854        &mut self,
 2855        placeholder_text: &str,
 2856        window: &mut Window,
 2857        cx: &mut Context<Self>,
 2858    ) {
 2859        let multibuffer = cx
 2860            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2861
 2862        let style = window.text_style();
 2863
 2864        self.placeholder_display_map = Some(cx.new(|cx| {
 2865            DisplayMap::new(
 2866                multibuffer,
 2867                style.font(),
 2868                style.font_size.to_pixels(window.rem_size()),
 2869                None,
 2870                FILE_HEADER_HEIGHT,
 2871                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2872                Default::default(),
 2873                DiagnosticSeverity::Off,
 2874                cx,
 2875            )
 2876        }));
 2877        cx.notify();
 2878    }
 2879
 2880    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2881        self.cursor_shape = cursor_shape;
 2882
 2883        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2884        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2885
 2886        cx.notify();
 2887    }
 2888
 2889    pub fn set_current_line_highlight(
 2890        &mut self,
 2891        current_line_highlight: Option<CurrentLineHighlight>,
 2892    ) {
 2893        self.current_line_highlight = current_line_highlight;
 2894    }
 2895
 2896    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2897        self.collapse_matches = collapse_matches;
 2898    }
 2899
 2900    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2901        let buffers = self.buffer.read(cx).all_buffers();
 2902        let Some(project) = self.project.as_ref() else {
 2903            return;
 2904        };
 2905        project.update(cx, |project, cx| {
 2906            for buffer in buffers {
 2907                self.registered_buffers
 2908                    .entry(buffer.read(cx).remote_id())
 2909                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2910            }
 2911        })
 2912    }
 2913
 2914    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2915        if self.collapse_matches {
 2916            return range.start..range.start;
 2917        }
 2918        range.clone()
 2919    }
 2920
 2921    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2922        if self.display_map.read(cx).clip_at_line_ends != clip {
 2923            self.display_map
 2924                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2925        }
 2926    }
 2927
 2928    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2929        self.input_enabled = input_enabled;
 2930    }
 2931
 2932    pub fn set_edit_predictions_hidden_for_vim_mode(
 2933        &mut self,
 2934        hidden: bool,
 2935        window: &mut Window,
 2936        cx: &mut Context<Self>,
 2937    ) {
 2938        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2939            self.edit_predictions_hidden_for_vim_mode = hidden;
 2940            if hidden {
 2941                self.update_visible_edit_prediction(window, cx);
 2942            } else {
 2943                self.refresh_edit_prediction(true, false, window, cx);
 2944            }
 2945        }
 2946    }
 2947
 2948    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2949        self.menu_edit_predictions_policy = value;
 2950    }
 2951
 2952    pub fn set_autoindent(&mut self, autoindent: bool) {
 2953        if autoindent {
 2954            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2955        } else {
 2956            self.autoindent_mode = None;
 2957        }
 2958    }
 2959
 2960    pub fn read_only(&self, cx: &App) -> bool {
 2961        self.read_only || self.buffer.read(cx).read_only()
 2962    }
 2963
 2964    pub fn set_read_only(&mut self, read_only: bool) {
 2965        self.read_only = read_only;
 2966    }
 2967
 2968    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2969        self.use_autoclose = autoclose;
 2970    }
 2971
 2972    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2973        self.use_auto_surround = auto_surround;
 2974    }
 2975
 2976    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2977        self.auto_replace_emoji_shortcode = auto_replace;
 2978    }
 2979
 2980    pub fn toggle_edit_predictions(
 2981        &mut self,
 2982        _: &ToggleEditPrediction,
 2983        window: &mut Window,
 2984        cx: &mut Context<Self>,
 2985    ) {
 2986        if self.show_edit_predictions_override.is_some() {
 2987            self.set_show_edit_predictions(None, window, cx);
 2988        } else {
 2989            let show_edit_predictions = !self.edit_predictions_enabled();
 2990            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2991        }
 2992    }
 2993
 2994    pub fn set_show_edit_predictions(
 2995        &mut self,
 2996        show_edit_predictions: Option<bool>,
 2997        window: &mut Window,
 2998        cx: &mut Context<Self>,
 2999    ) {
 3000        self.show_edit_predictions_override = show_edit_predictions;
 3001        self.update_edit_prediction_settings(cx);
 3002
 3003        if let Some(false) = show_edit_predictions {
 3004            self.discard_edit_prediction(false, cx);
 3005        } else {
 3006            self.refresh_edit_prediction(false, true, window, cx);
 3007        }
 3008    }
 3009
 3010    fn edit_predictions_disabled_in_scope(
 3011        &self,
 3012        buffer: &Entity<Buffer>,
 3013        buffer_position: language::Anchor,
 3014        cx: &App,
 3015    ) -> bool {
 3016        let snapshot = buffer.read(cx).snapshot();
 3017        let settings = snapshot.settings_at(buffer_position, cx);
 3018
 3019        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3020            return false;
 3021        };
 3022
 3023        scope.override_name().is_some_and(|scope_name| {
 3024            settings
 3025                .edit_predictions_disabled_in
 3026                .iter()
 3027                .any(|s| s == scope_name)
 3028        })
 3029    }
 3030
 3031    pub fn set_use_modal_editing(&mut self, to: bool) {
 3032        self.use_modal_editing = to;
 3033    }
 3034
 3035    pub fn use_modal_editing(&self) -> bool {
 3036        self.use_modal_editing
 3037    }
 3038
 3039    fn selections_did_change(
 3040        &mut self,
 3041        local: bool,
 3042        old_cursor_position: &Anchor,
 3043        effects: SelectionEffects,
 3044        window: &mut Window,
 3045        cx: &mut Context<Self>,
 3046    ) {
 3047        window.invalidate_character_coordinates();
 3048
 3049        // Copy selections to primary selection buffer
 3050        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3051        if local {
 3052            let selections = self.selections.all::<usize>(cx);
 3053            let buffer_handle = self.buffer.read(cx).read(cx);
 3054
 3055            let mut text = String::new();
 3056            for (index, selection) in selections.iter().enumerate() {
 3057                let text_for_selection = buffer_handle
 3058                    .text_for_range(selection.start..selection.end)
 3059                    .collect::<String>();
 3060
 3061                text.push_str(&text_for_selection);
 3062                if index != selections.len() - 1 {
 3063                    text.push('\n');
 3064                }
 3065            }
 3066
 3067            if !text.is_empty() {
 3068                cx.write_to_primary(ClipboardItem::new_string(text));
 3069            }
 3070        }
 3071
 3072        let selection_anchors = self.selections.disjoint_anchors_arc();
 3073
 3074        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3075            self.buffer.update(cx, |buffer, cx| {
 3076                buffer.set_active_selections(
 3077                    &selection_anchors,
 3078                    self.selections.line_mode(),
 3079                    self.cursor_shape,
 3080                    cx,
 3081                )
 3082            });
 3083        }
 3084        let display_map = self
 3085            .display_map
 3086            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3087        let buffer = &display_map.buffer_snapshot;
 3088        if self.selections.count() == 1 {
 3089            self.add_selections_state = None;
 3090        }
 3091        self.select_next_state = None;
 3092        self.select_prev_state = None;
 3093        self.select_syntax_node_history.try_clear();
 3094        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3095        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3096        self.take_rename(false, window, cx);
 3097
 3098        let newest_selection = self.selections.newest_anchor();
 3099        let new_cursor_position = newest_selection.head();
 3100        let selection_start = newest_selection.start;
 3101
 3102        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3103            self.push_to_nav_history(
 3104                *old_cursor_position,
 3105                Some(new_cursor_position.to_point(buffer)),
 3106                false,
 3107                effects.nav_history == Some(true),
 3108                cx,
 3109            );
 3110        }
 3111
 3112        if local {
 3113            if let Some(buffer_id) = new_cursor_position.buffer_id
 3114                && !self.registered_buffers.contains_key(&buffer_id)
 3115                && let Some(project) = self.project.as_ref()
 3116            {
 3117                project.update(cx, |project, cx| {
 3118                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3119                        return;
 3120                    };
 3121                    self.registered_buffers.insert(
 3122                        buffer_id,
 3123                        project.register_buffer_with_language_servers(&buffer, cx),
 3124                    );
 3125                })
 3126            }
 3127
 3128            let mut context_menu = self.context_menu.borrow_mut();
 3129            let completion_menu = match context_menu.as_ref() {
 3130                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3131                Some(CodeContextMenu::CodeActions(_)) => {
 3132                    *context_menu = None;
 3133                    None
 3134                }
 3135                None => None,
 3136            };
 3137            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3138            drop(context_menu);
 3139
 3140            if effects.completions
 3141                && let Some(completion_position) = completion_position
 3142            {
 3143                let start_offset = selection_start.to_offset(buffer);
 3144                let position_matches = start_offset == completion_position.to_offset(buffer);
 3145                let continue_showing = if position_matches {
 3146                    if self.snippet_stack.is_empty() {
 3147                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3148                            == Some(CharKind::Word)
 3149                    } else {
 3150                        // Snippet choices can be shown even when the cursor is in whitespace.
 3151                        // Dismissing the menu with actions like backspace is handled by
 3152                        // invalidation regions.
 3153                        true
 3154                    }
 3155                } else {
 3156                    false
 3157                };
 3158
 3159                if continue_showing {
 3160                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3161                } else {
 3162                    self.hide_context_menu(window, cx);
 3163                }
 3164            }
 3165
 3166            hide_hover(self, cx);
 3167
 3168            if old_cursor_position.to_display_point(&display_map).row()
 3169                != new_cursor_position.to_display_point(&display_map).row()
 3170            {
 3171                self.available_code_actions.take();
 3172            }
 3173            self.refresh_code_actions(window, cx);
 3174            self.refresh_document_highlights(cx);
 3175            self.refresh_selected_text_highlights(false, window, cx);
 3176            refresh_matching_bracket_highlights(self, window, cx);
 3177            self.update_visible_edit_prediction(window, cx);
 3178            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3179            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3180            self.inline_blame_popover.take();
 3181            if self.git_blame_inline_enabled {
 3182                self.start_inline_blame_timer(window, cx);
 3183            }
 3184        }
 3185
 3186        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3187        cx.emit(EditorEvent::SelectionsChanged { local });
 3188
 3189        let selections = &self.selections.disjoint_anchors_arc();
 3190        if selections.len() == 1 {
 3191            cx.emit(SearchEvent::ActiveMatchChanged)
 3192        }
 3193        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3194            let inmemory_selections = selections
 3195                .iter()
 3196                .map(|s| {
 3197                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3198                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3199                })
 3200                .collect();
 3201            self.update_restoration_data(cx, |data| {
 3202                data.selections = inmemory_selections;
 3203            });
 3204
 3205            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3206                && let Some(workspace_id) =
 3207                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3208            {
 3209                let snapshot = self.buffer().read(cx).snapshot(cx);
 3210                let selections = selections.clone();
 3211                let background_executor = cx.background_executor().clone();
 3212                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3213                self.serialize_selections = cx.background_spawn(async move {
 3214                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3215                            let db_selections = selections
 3216                                .iter()
 3217                                .map(|selection| {
 3218                                    (
 3219                                        selection.start.to_offset(&snapshot),
 3220                                        selection.end.to_offset(&snapshot),
 3221                                    )
 3222                                })
 3223                                .collect();
 3224
 3225                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3226                                .await
 3227                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3228                                .log_err();
 3229                        });
 3230            }
 3231        }
 3232
 3233        cx.notify();
 3234    }
 3235
 3236    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3237        use text::ToOffset as _;
 3238        use text::ToPoint as _;
 3239
 3240        if self.mode.is_minimap()
 3241            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3242        {
 3243            return;
 3244        }
 3245
 3246        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3247            return;
 3248        };
 3249
 3250        let snapshot = singleton.read(cx).snapshot();
 3251        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3252            let display_snapshot = display_map.snapshot(cx);
 3253
 3254            display_snapshot
 3255                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3256                .map(|fold| {
 3257                    fold.range.start.text_anchor.to_point(&snapshot)
 3258                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3259                })
 3260                .collect()
 3261        });
 3262        self.update_restoration_data(cx, |data| {
 3263            data.folds = inmemory_folds;
 3264        });
 3265
 3266        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3267            return;
 3268        };
 3269        let background_executor = cx.background_executor().clone();
 3270        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3271        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3272            display_map
 3273                .snapshot(cx)
 3274                .folds_in_range(0..snapshot.len())
 3275                .map(|fold| {
 3276                    (
 3277                        fold.range.start.text_anchor.to_offset(&snapshot),
 3278                        fold.range.end.text_anchor.to_offset(&snapshot),
 3279                    )
 3280                })
 3281                .collect()
 3282        });
 3283        self.serialize_folds = cx.background_spawn(async move {
 3284            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3285            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3286                .await
 3287                .with_context(|| {
 3288                    format!(
 3289                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3290                    )
 3291                })
 3292                .log_err();
 3293        });
 3294    }
 3295
 3296    pub fn sync_selections(
 3297        &mut self,
 3298        other: Entity<Editor>,
 3299        cx: &mut Context<Self>,
 3300    ) -> gpui::Subscription {
 3301        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3302        if !other_selections.is_empty() {
 3303            self.selections.change_with(cx, |selections| {
 3304                selections.select_anchors(other_selections);
 3305            });
 3306        }
 3307
 3308        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3309            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3310                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3311                if other_selections.is_empty() {
 3312                    return;
 3313                }
 3314                this.selections.change_with(cx, |selections| {
 3315                    selections.select_anchors(other_selections);
 3316                });
 3317            }
 3318        });
 3319
 3320        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3321            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3322                let these_selections = this.selections.disjoint_anchors().to_vec();
 3323                if these_selections.is_empty() {
 3324                    return;
 3325                }
 3326                other.update(cx, |other_editor, cx| {
 3327                    other_editor.selections.change_with(cx, |selections| {
 3328                        selections.select_anchors(these_selections);
 3329                    })
 3330                });
 3331            }
 3332        });
 3333
 3334        Subscription::join(other_subscription, this_subscription)
 3335    }
 3336
 3337    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3338    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3339    /// effects of selection change occur at the end of the transaction.
 3340    pub fn change_selections<R>(
 3341        &mut self,
 3342        effects: SelectionEffects,
 3343        window: &mut Window,
 3344        cx: &mut Context<Self>,
 3345        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3346    ) -> R {
 3347        if let Some(state) = &mut self.deferred_selection_effects_state {
 3348            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3349            state.effects.completions = effects.completions;
 3350            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3351            let (changed, result) = self.selections.change_with(cx, change);
 3352            state.changed |= changed;
 3353            return result;
 3354        }
 3355        let mut state = DeferredSelectionEffectsState {
 3356            changed: false,
 3357            effects,
 3358            old_cursor_position: self.selections.newest_anchor().head(),
 3359            history_entry: SelectionHistoryEntry {
 3360                selections: self.selections.disjoint_anchors_arc(),
 3361                select_next_state: self.select_next_state.clone(),
 3362                select_prev_state: self.select_prev_state.clone(),
 3363                add_selections_state: self.add_selections_state.clone(),
 3364            },
 3365        };
 3366        let (changed, result) = self.selections.change_with(cx, change);
 3367        state.changed = state.changed || changed;
 3368        if self.defer_selection_effects {
 3369            self.deferred_selection_effects_state = Some(state);
 3370        } else {
 3371            self.apply_selection_effects(state, window, cx);
 3372        }
 3373        result
 3374    }
 3375
 3376    /// Defers the effects of selection change, so that the effects of multiple calls to
 3377    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3378    /// to selection history and the state of popovers based on selection position aren't
 3379    /// erroneously updated.
 3380    pub fn with_selection_effects_deferred<R>(
 3381        &mut self,
 3382        window: &mut Window,
 3383        cx: &mut Context<Self>,
 3384        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3385    ) -> R {
 3386        let already_deferred = self.defer_selection_effects;
 3387        self.defer_selection_effects = true;
 3388        let result = update(self, window, cx);
 3389        if !already_deferred {
 3390            self.defer_selection_effects = false;
 3391            if let Some(state) = self.deferred_selection_effects_state.take() {
 3392                self.apply_selection_effects(state, window, cx);
 3393            }
 3394        }
 3395        result
 3396    }
 3397
 3398    fn apply_selection_effects(
 3399        &mut self,
 3400        state: DeferredSelectionEffectsState,
 3401        window: &mut Window,
 3402        cx: &mut Context<Self>,
 3403    ) {
 3404        if state.changed {
 3405            self.selection_history.push(state.history_entry);
 3406
 3407            if let Some(autoscroll) = state.effects.scroll {
 3408                self.request_autoscroll(autoscroll, cx);
 3409            }
 3410
 3411            let old_cursor_position = &state.old_cursor_position;
 3412
 3413            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3414
 3415            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3416                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3417            }
 3418        }
 3419    }
 3420
 3421    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3422    where
 3423        I: IntoIterator<Item = (Range<S>, T)>,
 3424        S: ToOffset,
 3425        T: Into<Arc<str>>,
 3426    {
 3427        if self.read_only(cx) {
 3428            return;
 3429        }
 3430
 3431        self.buffer
 3432            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3433    }
 3434
 3435    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3436    where
 3437        I: IntoIterator<Item = (Range<S>, T)>,
 3438        S: ToOffset,
 3439        T: Into<Arc<str>>,
 3440    {
 3441        if self.read_only(cx) {
 3442            return;
 3443        }
 3444
 3445        self.buffer.update(cx, |buffer, cx| {
 3446            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3447        });
 3448    }
 3449
 3450    pub fn edit_with_block_indent<I, S, T>(
 3451        &mut self,
 3452        edits: I,
 3453        original_indent_columns: Vec<Option<u32>>,
 3454        cx: &mut Context<Self>,
 3455    ) where
 3456        I: IntoIterator<Item = (Range<S>, T)>,
 3457        S: ToOffset,
 3458        T: Into<Arc<str>>,
 3459    {
 3460        if self.read_only(cx) {
 3461            return;
 3462        }
 3463
 3464        self.buffer.update(cx, |buffer, cx| {
 3465            buffer.edit(
 3466                edits,
 3467                Some(AutoindentMode::Block {
 3468                    original_indent_columns,
 3469                }),
 3470                cx,
 3471            )
 3472        });
 3473    }
 3474
 3475    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3476        self.hide_context_menu(window, cx);
 3477
 3478        match phase {
 3479            SelectPhase::Begin {
 3480                position,
 3481                add,
 3482                click_count,
 3483            } => self.begin_selection(position, add, click_count, window, cx),
 3484            SelectPhase::BeginColumnar {
 3485                position,
 3486                goal_column,
 3487                reset,
 3488                mode,
 3489            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3490            SelectPhase::Extend {
 3491                position,
 3492                click_count,
 3493            } => self.extend_selection(position, click_count, window, cx),
 3494            SelectPhase::Update {
 3495                position,
 3496                goal_column,
 3497                scroll_delta,
 3498            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3499            SelectPhase::End => self.end_selection(window, cx),
 3500        }
 3501    }
 3502
 3503    fn extend_selection(
 3504        &mut self,
 3505        position: DisplayPoint,
 3506        click_count: usize,
 3507        window: &mut Window,
 3508        cx: &mut Context<Self>,
 3509    ) {
 3510        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3511        let tail = self.selections.newest::<usize>(cx).tail();
 3512        self.begin_selection(position, false, click_count, window, cx);
 3513
 3514        let position = position.to_offset(&display_map, Bias::Left);
 3515        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3516
 3517        let mut pending_selection = self
 3518            .selections
 3519            .pending_anchor()
 3520            .cloned()
 3521            .expect("extend_selection not called with pending selection");
 3522        if position >= tail {
 3523            pending_selection.start = tail_anchor;
 3524        } else {
 3525            pending_selection.end = tail_anchor;
 3526            pending_selection.reversed = true;
 3527        }
 3528
 3529        let mut pending_mode = self.selections.pending_mode().unwrap();
 3530        match &mut pending_mode {
 3531            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3532            _ => {}
 3533        }
 3534
 3535        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3536            SelectionEffects::scroll(Autoscroll::fit())
 3537        } else {
 3538            SelectionEffects::no_scroll()
 3539        };
 3540
 3541        self.change_selections(effects, window, cx, |s| {
 3542            s.set_pending(pending_selection.clone(), pending_mode)
 3543        });
 3544    }
 3545
 3546    fn begin_selection(
 3547        &mut self,
 3548        position: DisplayPoint,
 3549        add: bool,
 3550        click_count: usize,
 3551        window: &mut Window,
 3552        cx: &mut Context<Self>,
 3553    ) {
 3554        if !self.focus_handle.is_focused(window) {
 3555            self.last_focused_descendant = None;
 3556            window.focus(&self.focus_handle);
 3557        }
 3558
 3559        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3560        let buffer = &display_map.buffer_snapshot;
 3561        let position = display_map.clip_point(position, Bias::Left);
 3562
 3563        let start;
 3564        let end;
 3565        let mode;
 3566        let mut auto_scroll;
 3567        match click_count {
 3568            1 => {
 3569                start = buffer.anchor_before(position.to_point(&display_map));
 3570                end = start;
 3571                mode = SelectMode::Character;
 3572                auto_scroll = true;
 3573            }
 3574            2 => {
 3575                let position = display_map
 3576                    .clip_point(position, Bias::Left)
 3577                    .to_offset(&display_map, Bias::Left);
 3578                let (range, _) = buffer.surrounding_word(position, None);
 3579                start = buffer.anchor_before(range.start);
 3580                end = buffer.anchor_before(range.end);
 3581                mode = SelectMode::Word(start..end);
 3582                auto_scroll = true;
 3583            }
 3584            3 => {
 3585                let position = display_map
 3586                    .clip_point(position, Bias::Left)
 3587                    .to_point(&display_map);
 3588                let line_start = display_map.prev_line_boundary(position).0;
 3589                let next_line_start = buffer.clip_point(
 3590                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3591                    Bias::Left,
 3592                );
 3593                start = buffer.anchor_before(line_start);
 3594                end = buffer.anchor_before(next_line_start);
 3595                mode = SelectMode::Line(start..end);
 3596                auto_scroll = true;
 3597            }
 3598            _ => {
 3599                start = buffer.anchor_before(0);
 3600                end = buffer.anchor_before(buffer.len());
 3601                mode = SelectMode::All;
 3602                auto_scroll = false;
 3603            }
 3604        }
 3605        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3606
 3607        let point_to_delete: Option<usize> = {
 3608            let selected_points: Vec<Selection<Point>> =
 3609                self.selections.disjoint_in_range(start..end, cx);
 3610
 3611            if !add || click_count > 1 {
 3612                None
 3613            } else if !selected_points.is_empty() {
 3614                Some(selected_points[0].id)
 3615            } else {
 3616                let clicked_point_already_selected =
 3617                    self.selections.disjoint_anchors().iter().find(|selection| {
 3618                        selection.start.to_point(buffer) == start.to_point(buffer)
 3619                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3620                    });
 3621
 3622                clicked_point_already_selected.map(|selection| selection.id)
 3623            }
 3624        };
 3625
 3626        let selections_count = self.selections.count();
 3627        let effects = if auto_scroll {
 3628            SelectionEffects::default()
 3629        } else {
 3630            SelectionEffects::no_scroll()
 3631        };
 3632
 3633        self.change_selections(effects, window, cx, |s| {
 3634            if let Some(point_to_delete) = point_to_delete {
 3635                s.delete(point_to_delete);
 3636
 3637                if selections_count == 1 {
 3638                    s.set_pending_anchor_range(start..end, mode);
 3639                }
 3640            } else {
 3641                if !add {
 3642                    s.clear_disjoint();
 3643                }
 3644
 3645                s.set_pending_anchor_range(start..end, mode);
 3646            }
 3647        });
 3648    }
 3649
 3650    fn begin_columnar_selection(
 3651        &mut self,
 3652        position: DisplayPoint,
 3653        goal_column: u32,
 3654        reset: bool,
 3655        mode: ColumnarMode,
 3656        window: &mut Window,
 3657        cx: &mut Context<Self>,
 3658    ) {
 3659        if !self.focus_handle.is_focused(window) {
 3660            self.last_focused_descendant = None;
 3661            window.focus(&self.focus_handle);
 3662        }
 3663
 3664        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3665
 3666        if reset {
 3667            let pointer_position = display_map
 3668                .buffer_snapshot
 3669                .anchor_before(position.to_point(&display_map));
 3670
 3671            self.change_selections(
 3672                SelectionEffects::scroll(Autoscroll::newest()),
 3673                window,
 3674                cx,
 3675                |s| {
 3676                    s.clear_disjoint();
 3677                    s.set_pending_anchor_range(
 3678                        pointer_position..pointer_position,
 3679                        SelectMode::Character,
 3680                    );
 3681                },
 3682            );
 3683        };
 3684
 3685        let tail = self.selections.newest::<Point>(cx).tail();
 3686        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3687        self.columnar_selection_state = match mode {
 3688            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3689                selection_tail: selection_anchor,
 3690                display_point: if reset {
 3691                    if position.column() != goal_column {
 3692                        Some(DisplayPoint::new(position.row(), goal_column))
 3693                    } else {
 3694                        None
 3695                    }
 3696                } else {
 3697                    None
 3698                },
 3699            }),
 3700            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3701                selection_tail: selection_anchor,
 3702            }),
 3703        };
 3704
 3705        if !reset {
 3706            self.select_columns(position, goal_column, &display_map, window, cx);
 3707        }
 3708    }
 3709
 3710    fn update_selection(
 3711        &mut self,
 3712        position: DisplayPoint,
 3713        goal_column: u32,
 3714        scroll_delta: gpui::Point<f32>,
 3715        window: &mut Window,
 3716        cx: &mut Context<Self>,
 3717    ) {
 3718        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3719
 3720        if self.columnar_selection_state.is_some() {
 3721            self.select_columns(position, goal_column, &display_map, window, cx);
 3722        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3723            let buffer = &display_map.buffer_snapshot;
 3724            let head;
 3725            let tail;
 3726            let mode = self.selections.pending_mode().unwrap();
 3727            match &mode {
 3728                SelectMode::Character => {
 3729                    head = position.to_point(&display_map);
 3730                    tail = pending.tail().to_point(buffer);
 3731                }
 3732                SelectMode::Word(original_range) => {
 3733                    let offset = display_map
 3734                        .clip_point(position, Bias::Left)
 3735                        .to_offset(&display_map, Bias::Left);
 3736                    let original_range = original_range.to_offset(buffer);
 3737
 3738                    let head_offset = if buffer.is_inside_word(offset, None)
 3739                        || original_range.contains(&offset)
 3740                    {
 3741                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3742                        if word_range.start < original_range.start {
 3743                            word_range.start
 3744                        } else {
 3745                            word_range.end
 3746                        }
 3747                    } else {
 3748                        offset
 3749                    };
 3750
 3751                    head = head_offset.to_point(buffer);
 3752                    if head_offset <= original_range.start {
 3753                        tail = original_range.end.to_point(buffer);
 3754                    } else {
 3755                        tail = original_range.start.to_point(buffer);
 3756                    }
 3757                }
 3758                SelectMode::Line(original_range) => {
 3759                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3760
 3761                    let position = display_map
 3762                        .clip_point(position, Bias::Left)
 3763                        .to_point(&display_map);
 3764                    let line_start = display_map.prev_line_boundary(position).0;
 3765                    let next_line_start = buffer.clip_point(
 3766                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3767                        Bias::Left,
 3768                    );
 3769
 3770                    if line_start < original_range.start {
 3771                        head = line_start
 3772                    } else {
 3773                        head = next_line_start
 3774                    }
 3775
 3776                    if head <= original_range.start {
 3777                        tail = original_range.end;
 3778                    } else {
 3779                        tail = original_range.start;
 3780                    }
 3781                }
 3782                SelectMode::All => {
 3783                    return;
 3784                }
 3785            };
 3786
 3787            if head < tail {
 3788                pending.start = buffer.anchor_before(head);
 3789                pending.end = buffer.anchor_before(tail);
 3790                pending.reversed = true;
 3791            } else {
 3792                pending.start = buffer.anchor_before(tail);
 3793                pending.end = buffer.anchor_before(head);
 3794                pending.reversed = false;
 3795            }
 3796
 3797            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3798                s.set_pending(pending.clone(), mode);
 3799            });
 3800        } else {
 3801            log::error!("update_selection dispatched with no pending selection");
 3802            return;
 3803        }
 3804
 3805        self.apply_scroll_delta(scroll_delta, window, cx);
 3806        cx.notify();
 3807    }
 3808
 3809    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3810        self.columnar_selection_state.take();
 3811        if self.selections.pending_anchor().is_some() {
 3812            let selections = self.selections.all::<usize>(cx);
 3813            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3814                s.select(selections);
 3815                s.clear_pending();
 3816            });
 3817        }
 3818    }
 3819
 3820    fn select_columns(
 3821        &mut self,
 3822        head: DisplayPoint,
 3823        goal_column: u32,
 3824        display_map: &DisplaySnapshot,
 3825        window: &mut Window,
 3826        cx: &mut Context<Self>,
 3827    ) {
 3828        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3829            return;
 3830        };
 3831
 3832        let tail = match columnar_state {
 3833            ColumnarSelectionState::FromMouse {
 3834                selection_tail,
 3835                display_point,
 3836            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3837            ColumnarSelectionState::FromSelection { selection_tail } => {
 3838                selection_tail.to_display_point(display_map)
 3839            }
 3840        };
 3841
 3842        let start_row = cmp::min(tail.row(), head.row());
 3843        let end_row = cmp::max(tail.row(), head.row());
 3844        let start_column = cmp::min(tail.column(), goal_column);
 3845        let end_column = cmp::max(tail.column(), goal_column);
 3846        let reversed = start_column < tail.column();
 3847
 3848        let selection_ranges = (start_row.0..=end_row.0)
 3849            .map(DisplayRow)
 3850            .filter_map(|row| {
 3851                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3852                    || start_column <= display_map.line_len(row))
 3853                    && !display_map.is_block_line(row)
 3854                {
 3855                    let start = display_map
 3856                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3857                        .to_point(display_map);
 3858                    let end = display_map
 3859                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3860                        .to_point(display_map);
 3861                    if reversed {
 3862                        Some(end..start)
 3863                    } else {
 3864                        Some(start..end)
 3865                    }
 3866                } else {
 3867                    None
 3868                }
 3869            })
 3870            .collect::<Vec<_>>();
 3871
 3872        let ranges = match columnar_state {
 3873            ColumnarSelectionState::FromMouse { .. } => {
 3874                let mut non_empty_ranges = selection_ranges
 3875                    .iter()
 3876                    .filter(|selection_range| selection_range.start != selection_range.end)
 3877                    .peekable();
 3878                if non_empty_ranges.peek().is_some() {
 3879                    non_empty_ranges.cloned().collect()
 3880                } else {
 3881                    selection_ranges
 3882                }
 3883            }
 3884            _ => selection_ranges,
 3885        };
 3886
 3887        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3888            s.select_ranges(ranges);
 3889        });
 3890        cx.notify();
 3891    }
 3892
 3893    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3894        self.selections
 3895            .all_adjusted(cx)
 3896            .iter()
 3897            .any(|selection| !selection.is_empty())
 3898    }
 3899
 3900    pub fn has_pending_nonempty_selection(&self) -> bool {
 3901        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3902            Some(Selection { start, end, .. }) => start != end,
 3903            None => false,
 3904        };
 3905
 3906        pending_nonempty_selection
 3907            || (self.columnar_selection_state.is_some()
 3908                && self.selections.disjoint_anchors().len() > 1)
 3909    }
 3910
 3911    pub fn has_pending_selection(&self) -> bool {
 3912        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3913    }
 3914
 3915    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3916        self.selection_mark_mode = false;
 3917        self.selection_drag_state = SelectionDragState::None;
 3918
 3919        if self.clear_expanded_diff_hunks(cx) {
 3920            cx.notify();
 3921            return;
 3922        }
 3923        if self.dismiss_menus_and_popups(true, window, cx) {
 3924            return;
 3925        }
 3926
 3927        if self.mode.is_full()
 3928            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3929        {
 3930            return;
 3931        }
 3932
 3933        cx.propagate();
 3934    }
 3935
 3936    pub fn dismiss_menus_and_popups(
 3937        &mut self,
 3938        is_user_requested: bool,
 3939        window: &mut Window,
 3940        cx: &mut Context<Self>,
 3941    ) -> bool {
 3942        if self.take_rename(false, window, cx).is_some() {
 3943            return true;
 3944        }
 3945
 3946        if hide_hover(self, cx) {
 3947            return true;
 3948        }
 3949
 3950        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3951            return true;
 3952        }
 3953
 3954        if self.hide_context_menu(window, cx).is_some() {
 3955            return true;
 3956        }
 3957
 3958        if self.mouse_context_menu.take().is_some() {
 3959            return true;
 3960        }
 3961
 3962        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3963            return true;
 3964        }
 3965
 3966        if self.snippet_stack.pop().is_some() {
 3967            return true;
 3968        }
 3969
 3970        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3971            self.dismiss_diagnostics(cx);
 3972            return true;
 3973        }
 3974
 3975        false
 3976    }
 3977
 3978    fn linked_editing_ranges_for(
 3979        &self,
 3980        selection: Range<text::Anchor>,
 3981        cx: &App,
 3982    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3983        if self.linked_edit_ranges.is_empty() {
 3984            return None;
 3985        }
 3986        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3987            selection.end.buffer_id.and_then(|end_buffer_id| {
 3988                if selection.start.buffer_id != Some(end_buffer_id) {
 3989                    return None;
 3990                }
 3991                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3992                let snapshot = buffer.read(cx).snapshot();
 3993                self.linked_edit_ranges
 3994                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3995                    .map(|ranges| (ranges, snapshot, buffer))
 3996            })?;
 3997        use text::ToOffset as TO;
 3998        // find offset from the start of current range to current cursor position
 3999        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4000
 4001        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4002        let start_difference = start_offset - start_byte_offset;
 4003        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4004        let end_difference = end_offset - start_byte_offset;
 4005        // Current range has associated linked ranges.
 4006        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4007        for range in linked_ranges.iter() {
 4008            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4009            let end_offset = start_offset + end_difference;
 4010            let start_offset = start_offset + start_difference;
 4011            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4012                continue;
 4013            }
 4014            if self.selections.disjoint_anchor_ranges().any(|s| {
 4015                if s.start.buffer_id != selection.start.buffer_id
 4016                    || s.end.buffer_id != selection.end.buffer_id
 4017                {
 4018                    return false;
 4019                }
 4020                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4021                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4022            }) {
 4023                continue;
 4024            }
 4025            let start = buffer_snapshot.anchor_after(start_offset);
 4026            let end = buffer_snapshot.anchor_after(end_offset);
 4027            linked_edits
 4028                .entry(buffer.clone())
 4029                .or_default()
 4030                .push(start..end);
 4031        }
 4032        Some(linked_edits)
 4033    }
 4034
 4035    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4036        let text: Arc<str> = text.into();
 4037
 4038        if self.read_only(cx) {
 4039            return;
 4040        }
 4041
 4042        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4043
 4044        let selections = self.selections.all_adjusted(cx);
 4045        let mut bracket_inserted = false;
 4046        let mut edits = Vec::new();
 4047        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4048        let mut new_selections = Vec::with_capacity(selections.len());
 4049        let mut new_autoclose_regions = Vec::new();
 4050        let snapshot = self.buffer.read(cx).read(cx);
 4051        let mut clear_linked_edit_ranges = false;
 4052
 4053        for (selection, autoclose_region) in
 4054            self.selections_with_autoclose_regions(selections, &snapshot)
 4055        {
 4056            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4057                // Determine if the inserted text matches the opening or closing
 4058                // bracket of any of this language's bracket pairs.
 4059                let mut bracket_pair = None;
 4060                let mut is_bracket_pair_start = false;
 4061                let mut is_bracket_pair_end = false;
 4062                if !text.is_empty() {
 4063                    let mut bracket_pair_matching_end = None;
 4064                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4065                    //  and they are removing the character that triggered IME popup.
 4066                    for (pair, enabled) in scope.brackets() {
 4067                        if !pair.close && !pair.surround {
 4068                            continue;
 4069                        }
 4070
 4071                        if enabled && pair.start.ends_with(text.as_ref()) {
 4072                            let prefix_len = pair.start.len() - text.len();
 4073                            let preceding_text_matches_prefix = prefix_len == 0
 4074                                || (selection.start.column >= (prefix_len as u32)
 4075                                    && snapshot.contains_str_at(
 4076                                        Point::new(
 4077                                            selection.start.row,
 4078                                            selection.start.column - (prefix_len as u32),
 4079                                        ),
 4080                                        &pair.start[..prefix_len],
 4081                                    ));
 4082                            if preceding_text_matches_prefix {
 4083                                bracket_pair = Some(pair.clone());
 4084                                is_bracket_pair_start = true;
 4085                                break;
 4086                            }
 4087                        }
 4088                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4089                        {
 4090                            // take first bracket pair matching end, but don't break in case a later bracket
 4091                            // pair matches start
 4092                            bracket_pair_matching_end = Some(pair.clone());
 4093                        }
 4094                    }
 4095                    if let Some(end) = bracket_pair_matching_end
 4096                        && bracket_pair.is_none()
 4097                    {
 4098                        bracket_pair = Some(end);
 4099                        is_bracket_pair_end = true;
 4100                    }
 4101                }
 4102
 4103                if let Some(bracket_pair) = bracket_pair {
 4104                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4105                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4106                    let auto_surround =
 4107                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4108                    if selection.is_empty() {
 4109                        if is_bracket_pair_start {
 4110                            // If the inserted text is a suffix of an opening bracket and the
 4111                            // selection is preceded by the rest of the opening bracket, then
 4112                            // insert the closing bracket.
 4113                            let following_text_allows_autoclose = snapshot
 4114                                .chars_at(selection.start)
 4115                                .next()
 4116                                .is_none_or(|c| scope.should_autoclose_before(c));
 4117
 4118                            let preceding_text_allows_autoclose = selection.start.column == 0
 4119                                || snapshot
 4120                                    .reversed_chars_at(selection.start)
 4121                                    .next()
 4122                                    .is_none_or(|c| {
 4123                                        bracket_pair.start != bracket_pair.end
 4124                                            || !snapshot
 4125                                                .char_classifier_at(selection.start)
 4126                                                .is_word(c)
 4127                                    });
 4128
 4129                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4130                                && bracket_pair.start.len() == 1
 4131                            {
 4132                                let target = bracket_pair.start.chars().next().unwrap();
 4133                                let current_line_count = snapshot
 4134                                    .reversed_chars_at(selection.start)
 4135                                    .take_while(|&c| c != '\n')
 4136                                    .filter(|&c| c == target)
 4137                                    .count();
 4138                                current_line_count % 2 == 1
 4139                            } else {
 4140                                false
 4141                            };
 4142
 4143                            if autoclose
 4144                                && bracket_pair.close
 4145                                && following_text_allows_autoclose
 4146                                && preceding_text_allows_autoclose
 4147                                && !is_closing_quote
 4148                            {
 4149                                let anchor = snapshot.anchor_before(selection.end);
 4150                                new_selections.push((selection.map(|_| anchor), text.len()));
 4151                                new_autoclose_regions.push((
 4152                                    anchor,
 4153                                    text.len(),
 4154                                    selection.id,
 4155                                    bracket_pair.clone(),
 4156                                ));
 4157                                edits.push((
 4158                                    selection.range(),
 4159                                    format!("{}{}", text, bracket_pair.end).into(),
 4160                                ));
 4161                                bracket_inserted = true;
 4162                                continue;
 4163                            }
 4164                        }
 4165
 4166                        if let Some(region) = autoclose_region {
 4167                            // If the selection is followed by an auto-inserted closing bracket,
 4168                            // then don't insert that closing bracket again; just move the selection
 4169                            // past the closing bracket.
 4170                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4171                                && text.as_ref() == region.pair.end.as_str()
 4172                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4173                            if should_skip {
 4174                                let anchor = snapshot.anchor_after(selection.end);
 4175                                new_selections
 4176                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4177                                continue;
 4178                            }
 4179                        }
 4180
 4181                        let always_treat_brackets_as_autoclosed = snapshot
 4182                            .language_settings_at(selection.start, cx)
 4183                            .always_treat_brackets_as_autoclosed;
 4184                        if always_treat_brackets_as_autoclosed
 4185                            && is_bracket_pair_end
 4186                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4187                        {
 4188                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4189                            // and the inserted text is a closing bracket and the selection is followed
 4190                            // by the closing bracket then move the selection past the closing bracket.
 4191                            let anchor = snapshot.anchor_after(selection.end);
 4192                            new_selections.push((selection.map(|_| anchor), text.len()));
 4193                            continue;
 4194                        }
 4195                    }
 4196                    // If an opening bracket is 1 character long and is typed while
 4197                    // text is selected, then surround that text with the bracket pair.
 4198                    else if auto_surround
 4199                        && bracket_pair.surround
 4200                        && is_bracket_pair_start
 4201                        && bracket_pair.start.chars().count() == 1
 4202                    {
 4203                        edits.push((selection.start..selection.start, text.clone()));
 4204                        edits.push((
 4205                            selection.end..selection.end,
 4206                            bracket_pair.end.as_str().into(),
 4207                        ));
 4208                        bracket_inserted = true;
 4209                        new_selections.push((
 4210                            Selection {
 4211                                id: selection.id,
 4212                                start: snapshot.anchor_after(selection.start),
 4213                                end: snapshot.anchor_before(selection.end),
 4214                                reversed: selection.reversed,
 4215                                goal: selection.goal,
 4216                            },
 4217                            0,
 4218                        ));
 4219                        continue;
 4220                    }
 4221                }
 4222            }
 4223
 4224            if self.auto_replace_emoji_shortcode
 4225                && selection.is_empty()
 4226                && text.as_ref().ends_with(':')
 4227                && let Some(possible_emoji_short_code) =
 4228                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4229                && !possible_emoji_short_code.is_empty()
 4230                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4231            {
 4232                let emoji_shortcode_start = Point::new(
 4233                    selection.start.row,
 4234                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4235                );
 4236
 4237                // Remove shortcode from buffer
 4238                edits.push((
 4239                    emoji_shortcode_start..selection.start,
 4240                    "".to_string().into(),
 4241                ));
 4242                new_selections.push((
 4243                    Selection {
 4244                        id: selection.id,
 4245                        start: snapshot.anchor_after(emoji_shortcode_start),
 4246                        end: snapshot.anchor_before(selection.start),
 4247                        reversed: selection.reversed,
 4248                        goal: selection.goal,
 4249                    },
 4250                    0,
 4251                ));
 4252
 4253                // Insert emoji
 4254                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4255                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4256                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4257
 4258                continue;
 4259            }
 4260
 4261            // If not handling any auto-close operation, then just replace the selected
 4262            // text with the given input and move the selection to the end of the
 4263            // newly inserted text.
 4264            let anchor = snapshot.anchor_after(selection.end);
 4265            if !self.linked_edit_ranges.is_empty() {
 4266                let start_anchor = snapshot.anchor_before(selection.start);
 4267
 4268                let is_word_char = text.chars().next().is_none_or(|char| {
 4269                    let classifier = snapshot
 4270                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4271                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4272                    classifier.is_word(char)
 4273                });
 4274
 4275                if is_word_char {
 4276                    if let Some(ranges) = self
 4277                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4278                    {
 4279                        for (buffer, edits) in ranges {
 4280                            linked_edits
 4281                                .entry(buffer.clone())
 4282                                .or_default()
 4283                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4284                        }
 4285                    }
 4286                } else {
 4287                    clear_linked_edit_ranges = true;
 4288                }
 4289            }
 4290
 4291            new_selections.push((selection.map(|_| anchor), 0));
 4292            edits.push((selection.start..selection.end, text.clone()));
 4293        }
 4294
 4295        drop(snapshot);
 4296
 4297        self.transact(window, cx, |this, window, cx| {
 4298            if clear_linked_edit_ranges {
 4299                this.linked_edit_ranges.clear();
 4300            }
 4301            let initial_buffer_versions =
 4302                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4303
 4304            this.buffer.update(cx, |buffer, cx| {
 4305                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4306            });
 4307            for (buffer, edits) in linked_edits {
 4308                buffer.update(cx, |buffer, cx| {
 4309                    let snapshot = buffer.snapshot();
 4310                    let edits = edits
 4311                        .into_iter()
 4312                        .map(|(range, text)| {
 4313                            use text::ToPoint as TP;
 4314                            let end_point = TP::to_point(&range.end, &snapshot);
 4315                            let start_point = TP::to_point(&range.start, &snapshot);
 4316                            (start_point..end_point, text)
 4317                        })
 4318                        .sorted_by_key(|(range, _)| range.start);
 4319                    buffer.edit(edits, None, cx);
 4320                })
 4321            }
 4322            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4323            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4324            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4325            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4326                .zip(new_selection_deltas)
 4327                .map(|(selection, delta)| Selection {
 4328                    id: selection.id,
 4329                    start: selection.start + delta,
 4330                    end: selection.end + delta,
 4331                    reversed: selection.reversed,
 4332                    goal: SelectionGoal::None,
 4333                })
 4334                .collect::<Vec<_>>();
 4335
 4336            let mut i = 0;
 4337            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4338                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4339                let start = map.buffer_snapshot.anchor_before(position);
 4340                let end = map.buffer_snapshot.anchor_after(position);
 4341                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4342                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4343                        Ordering::Less => i += 1,
 4344                        Ordering::Greater => break,
 4345                        Ordering::Equal => {
 4346                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4347                                Ordering::Less => i += 1,
 4348                                Ordering::Equal => break,
 4349                                Ordering::Greater => break,
 4350                            }
 4351                        }
 4352                    }
 4353                }
 4354                this.autoclose_regions.insert(
 4355                    i,
 4356                    AutocloseRegion {
 4357                        selection_id,
 4358                        range: start..end,
 4359                        pair,
 4360                    },
 4361                );
 4362            }
 4363
 4364            let had_active_edit_prediction = this.has_active_edit_prediction();
 4365            this.change_selections(
 4366                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4367                window,
 4368                cx,
 4369                |s| s.select(new_selections),
 4370            );
 4371
 4372            if !bracket_inserted
 4373                && let Some(on_type_format_task) =
 4374                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4375            {
 4376                on_type_format_task.detach_and_log_err(cx);
 4377            }
 4378
 4379            let editor_settings = EditorSettings::get_global(cx);
 4380            if bracket_inserted
 4381                && (editor_settings.auto_signature_help
 4382                    || editor_settings.show_signature_help_after_edits)
 4383            {
 4384                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4385            }
 4386
 4387            let trigger_in_words =
 4388                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4389            if this.hard_wrap.is_some() {
 4390                let latest: Range<Point> = this.selections.newest(cx).range();
 4391                if latest.is_empty()
 4392                    && this
 4393                        .buffer()
 4394                        .read(cx)
 4395                        .snapshot(cx)
 4396                        .line_len(MultiBufferRow(latest.start.row))
 4397                        == latest.start.column
 4398                {
 4399                    this.rewrap_impl(
 4400                        RewrapOptions {
 4401                            override_language_settings: true,
 4402                            preserve_existing_whitespace: true,
 4403                        },
 4404                        cx,
 4405                    )
 4406                }
 4407            }
 4408            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4409            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4410            this.refresh_edit_prediction(true, false, window, cx);
 4411            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4412        });
 4413    }
 4414
 4415    fn find_possible_emoji_shortcode_at_position(
 4416        snapshot: &MultiBufferSnapshot,
 4417        position: Point,
 4418    ) -> Option<String> {
 4419        let mut chars = Vec::new();
 4420        let mut found_colon = false;
 4421        for char in snapshot.reversed_chars_at(position).take(100) {
 4422            // Found a possible emoji shortcode in the middle of the buffer
 4423            if found_colon {
 4424                if char.is_whitespace() {
 4425                    chars.reverse();
 4426                    return Some(chars.iter().collect());
 4427                }
 4428                // If the previous character is not a whitespace, we are in the middle of a word
 4429                // and we only want to complete the shortcode if the word is made up of other emojis
 4430                let mut containing_word = String::new();
 4431                for ch in snapshot
 4432                    .reversed_chars_at(position)
 4433                    .skip(chars.len() + 1)
 4434                    .take(100)
 4435                {
 4436                    if ch.is_whitespace() {
 4437                        break;
 4438                    }
 4439                    containing_word.push(ch);
 4440                }
 4441                let containing_word = containing_word.chars().rev().collect::<String>();
 4442                if util::word_consists_of_emojis(containing_word.as_str()) {
 4443                    chars.reverse();
 4444                    return Some(chars.iter().collect());
 4445                }
 4446            }
 4447
 4448            if char.is_whitespace() || !char.is_ascii() {
 4449                return None;
 4450            }
 4451            if char == ':' {
 4452                found_colon = true;
 4453            } else {
 4454                chars.push(char);
 4455            }
 4456        }
 4457        // Found a possible emoji shortcode at the beginning of the buffer
 4458        chars.reverse();
 4459        Some(chars.iter().collect())
 4460    }
 4461
 4462    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4463        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4464        self.transact(window, cx, |this, window, cx| {
 4465            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4466                let selections = this.selections.all::<usize>(cx);
 4467                let multi_buffer = this.buffer.read(cx);
 4468                let buffer = multi_buffer.snapshot(cx);
 4469                selections
 4470                    .iter()
 4471                    .map(|selection| {
 4472                        let start_point = selection.start.to_point(&buffer);
 4473                        let mut existing_indent =
 4474                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4475                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4476                        let start = selection.start;
 4477                        let end = selection.end;
 4478                        let selection_is_empty = start == end;
 4479                        let language_scope = buffer.language_scope_at(start);
 4480                        let (
 4481                            comment_delimiter,
 4482                            doc_delimiter,
 4483                            insert_extra_newline,
 4484                            indent_on_newline,
 4485                            indent_on_extra_newline,
 4486                        ) = if let Some(language) = &language_scope {
 4487                            let mut insert_extra_newline =
 4488                                insert_extra_newline_brackets(&buffer, start..end, language)
 4489                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4490
 4491                            // Comment extension on newline is allowed only for cursor selections
 4492                            let comment_delimiter = maybe!({
 4493                                if !selection_is_empty {
 4494                                    return None;
 4495                                }
 4496
 4497                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4498                                    return None;
 4499                                }
 4500
 4501                                let delimiters = language.line_comment_prefixes();
 4502                                let max_len_of_delimiter =
 4503                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4504                                let (snapshot, range) =
 4505                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4506
 4507                                let num_of_whitespaces = snapshot
 4508                                    .chars_for_range(range.clone())
 4509                                    .take_while(|c| c.is_whitespace())
 4510                                    .count();
 4511                                let comment_candidate = snapshot
 4512                                    .chars_for_range(range.clone())
 4513                                    .skip(num_of_whitespaces)
 4514                                    .take(max_len_of_delimiter)
 4515                                    .collect::<String>();
 4516                                let (delimiter, trimmed_len) = delimiters
 4517                                    .iter()
 4518                                    .filter_map(|delimiter| {
 4519                                        let prefix = delimiter.trim_end();
 4520                                        if comment_candidate.starts_with(prefix) {
 4521                                            Some((delimiter, prefix.len()))
 4522                                        } else {
 4523                                            None
 4524                                        }
 4525                                    })
 4526                                    .max_by_key(|(_, len)| *len)?;
 4527
 4528                                if let Some(BlockCommentConfig {
 4529                                    start: block_start, ..
 4530                                }) = language.block_comment()
 4531                                {
 4532                                    let block_start_trimmed = block_start.trim_end();
 4533                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4534                                        let line_content = snapshot
 4535                                            .chars_for_range(range)
 4536                                            .skip(num_of_whitespaces)
 4537                                            .take(block_start_trimmed.len())
 4538                                            .collect::<String>();
 4539
 4540                                        if line_content.starts_with(block_start_trimmed) {
 4541                                            return None;
 4542                                        }
 4543                                    }
 4544                                }
 4545
 4546                                let cursor_is_placed_after_comment_marker =
 4547                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4548                                if cursor_is_placed_after_comment_marker {
 4549                                    Some(delimiter.clone())
 4550                                } else {
 4551                                    None
 4552                                }
 4553                            });
 4554
 4555                            let mut indent_on_newline = IndentSize::spaces(0);
 4556                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4557
 4558                            let doc_delimiter = maybe!({
 4559                                if !selection_is_empty {
 4560                                    return None;
 4561                                }
 4562
 4563                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4564                                    return None;
 4565                                }
 4566
 4567                                let BlockCommentConfig {
 4568                                    start: start_tag,
 4569                                    end: end_tag,
 4570                                    prefix: delimiter,
 4571                                    tab_size: len,
 4572                                } = language.documentation_comment()?;
 4573                                let is_within_block_comment = buffer
 4574                                    .language_scope_at(start_point)
 4575                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4576                                if !is_within_block_comment {
 4577                                    return None;
 4578                                }
 4579
 4580                                let (snapshot, range) =
 4581                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4582
 4583                                let num_of_whitespaces = snapshot
 4584                                    .chars_for_range(range.clone())
 4585                                    .take_while(|c| c.is_whitespace())
 4586                                    .count();
 4587
 4588                                // 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.
 4589                                let column = start_point.column;
 4590                                let cursor_is_after_start_tag = {
 4591                                    let start_tag_len = start_tag.len();
 4592                                    let start_tag_line = snapshot
 4593                                        .chars_for_range(range.clone())
 4594                                        .skip(num_of_whitespaces)
 4595                                        .take(start_tag_len)
 4596                                        .collect::<String>();
 4597                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4598                                        num_of_whitespaces + start_tag_len <= column as usize
 4599                                    } else {
 4600                                        false
 4601                                    }
 4602                                };
 4603
 4604                                let cursor_is_after_delimiter = {
 4605                                    let delimiter_trim = delimiter.trim_end();
 4606                                    let delimiter_line = snapshot
 4607                                        .chars_for_range(range.clone())
 4608                                        .skip(num_of_whitespaces)
 4609                                        .take(delimiter_trim.len())
 4610                                        .collect::<String>();
 4611                                    if delimiter_line.starts_with(delimiter_trim) {
 4612                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4613                                    } else {
 4614                                        false
 4615                                    }
 4616                                };
 4617
 4618                                let cursor_is_before_end_tag_if_exists = {
 4619                                    let mut char_position = 0u32;
 4620                                    let mut end_tag_offset = None;
 4621
 4622                                    'outer: for chunk in snapshot.text_for_range(range) {
 4623                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4624                                            let chars_before_match =
 4625                                                chunk[..byte_pos].chars().count() as u32;
 4626                                            end_tag_offset =
 4627                                                Some(char_position + chars_before_match);
 4628                                            break 'outer;
 4629                                        }
 4630                                        char_position += chunk.chars().count() as u32;
 4631                                    }
 4632
 4633                                    if let Some(end_tag_offset) = end_tag_offset {
 4634                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4635                                        if cursor_is_after_start_tag {
 4636                                            if cursor_is_before_end_tag {
 4637                                                insert_extra_newline = true;
 4638                                            }
 4639                                            let cursor_is_at_start_of_end_tag =
 4640                                                column == end_tag_offset;
 4641                                            if cursor_is_at_start_of_end_tag {
 4642                                                indent_on_extra_newline.len = *len;
 4643                                            }
 4644                                        }
 4645                                        cursor_is_before_end_tag
 4646                                    } else {
 4647                                        true
 4648                                    }
 4649                                };
 4650
 4651                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4652                                    && cursor_is_before_end_tag_if_exists
 4653                                {
 4654                                    if cursor_is_after_start_tag {
 4655                                        indent_on_newline.len = *len;
 4656                                    }
 4657                                    Some(delimiter.clone())
 4658                                } else {
 4659                                    None
 4660                                }
 4661                            });
 4662
 4663                            (
 4664                                comment_delimiter,
 4665                                doc_delimiter,
 4666                                insert_extra_newline,
 4667                                indent_on_newline,
 4668                                indent_on_extra_newline,
 4669                            )
 4670                        } else {
 4671                            (
 4672                                None,
 4673                                None,
 4674                                false,
 4675                                IndentSize::default(),
 4676                                IndentSize::default(),
 4677                            )
 4678                        };
 4679
 4680                        let prevent_auto_indent = doc_delimiter.is_some();
 4681                        let delimiter = comment_delimiter.or(doc_delimiter);
 4682
 4683                        let capacity_for_delimiter =
 4684                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4685                        let mut new_text = String::with_capacity(
 4686                            1 + capacity_for_delimiter
 4687                                + existing_indent.len as usize
 4688                                + indent_on_newline.len as usize
 4689                                + indent_on_extra_newline.len as usize,
 4690                        );
 4691                        new_text.push('\n');
 4692                        new_text.extend(existing_indent.chars());
 4693                        new_text.extend(indent_on_newline.chars());
 4694
 4695                        if let Some(delimiter) = &delimiter {
 4696                            new_text.push_str(delimiter);
 4697                        }
 4698
 4699                        if insert_extra_newline {
 4700                            new_text.push('\n');
 4701                            new_text.extend(existing_indent.chars());
 4702                            new_text.extend(indent_on_extra_newline.chars());
 4703                        }
 4704
 4705                        let anchor = buffer.anchor_after(end);
 4706                        let new_selection = selection.map(|_| anchor);
 4707                        (
 4708                            ((start..end, new_text), prevent_auto_indent),
 4709                            (insert_extra_newline, new_selection),
 4710                        )
 4711                    })
 4712                    .unzip()
 4713            };
 4714
 4715            let mut auto_indent_edits = Vec::new();
 4716            let mut edits = Vec::new();
 4717            for (edit, prevent_auto_indent) in edits_with_flags {
 4718                if prevent_auto_indent {
 4719                    edits.push(edit);
 4720                } else {
 4721                    auto_indent_edits.push(edit);
 4722                }
 4723            }
 4724            if !edits.is_empty() {
 4725                this.edit(edits, cx);
 4726            }
 4727            if !auto_indent_edits.is_empty() {
 4728                this.edit_with_autoindent(auto_indent_edits, cx);
 4729            }
 4730
 4731            let buffer = this.buffer.read(cx).snapshot(cx);
 4732            let new_selections = selection_info
 4733                .into_iter()
 4734                .map(|(extra_newline_inserted, new_selection)| {
 4735                    let mut cursor = new_selection.end.to_point(&buffer);
 4736                    if extra_newline_inserted {
 4737                        cursor.row -= 1;
 4738                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4739                    }
 4740                    new_selection.map(|_| cursor)
 4741                })
 4742                .collect();
 4743
 4744            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4745            this.refresh_edit_prediction(true, false, window, cx);
 4746        });
 4747    }
 4748
 4749    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4751
 4752        let buffer = self.buffer.read(cx);
 4753        let snapshot = buffer.snapshot(cx);
 4754
 4755        let mut edits = Vec::new();
 4756        let mut rows = Vec::new();
 4757
 4758        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4759            let cursor = selection.head();
 4760            let row = cursor.row;
 4761
 4762            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4763
 4764            let newline = "\n".to_string();
 4765            edits.push((start_of_line..start_of_line, newline));
 4766
 4767            rows.push(row + rows_inserted as u32);
 4768        }
 4769
 4770        self.transact(window, cx, |editor, window, cx| {
 4771            editor.edit(edits, cx);
 4772
 4773            editor.change_selections(Default::default(), window, cx, |s| {
 4774                let mut index = 0;
 4775                s.move_cursors_with(|map, _, _| {
 4776                    let row = rows[index];
 4777                    index += 1;
 4778
 4779                    let point = Point::new(row, 0);
 4780                    let boundary = map.next_line_boundary(point).1;
 4781                    let clipped = map.clip_point(boundary, Bias::Left);
 4782
 4783                    (clipped, SelectionGoal::None)
 4784                });
 4785            });
 4786
 4787            let mut indent_edits = Vec::new();
 4788            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4789            for row in rows {
 4790                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4791                for (row, indent) in indents {
 4792                    if indent.len == 0 {
 4793                        continue;
 4794                    }
 4795
 4796                    let text = match indent.kind {
 4797                        IndentKind::Space => " ".repeat(indent.len as usize),
 4798                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4799                    };
 4800                    let point = Point::new(row.0, 0);
 4801                    indent_edits.push((point..point, text));
 4802                }
 4803            }
 4804            editor.edit(indent_edits, cx);
 4805        });
 4806    }
 4807
 4808    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4809        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4810
 4811        let buffer = self.buffer.read(cx);
 4812        let snapshot = buffer.snapshot(cx);
 4813
 4814        let mut edits = Vec::new();
 4815        let mut rows = Vec::new();
 4816        let mut rows_inserted = 0;
 4817
 4818        for selection in self.selections.all_adjusted(cx) {
 4819            let cursor = selection.head();
 4820            let row = cursor.row;
 4821
 4822            let point = Point::new(row + 1, 0);
 4823            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4824
 4825            let newline = "\n".to_string();
 4826            edits.push((start_of_line..start_of_line, newline));
 4827
 4828            rows_inserted += 1;
 4829            rows.push(row + rows_inserted);
 4830        }
 4831
 4832        self.transact(window, cx, |editor, window, cx| {
 4833            editor.edit(edits, cx);
 4834
 4835            editor.change_selections(Default::default(), window, cx, |s| {
 4836                let mut index = 0;
 4837                s.move_cursors_with(|map, _, _| {
 4838                    let row = rows[index];
 4839                    index += 1;
 4840
 4841                    let point = Point::new(row, 0);
 4842                    let boundary = map.next_line_boundary(point).1;
 4843                    let clipped = map.clip_point(boundary, Bias::Left);
 4844
 4845                    (clipped, SelectionGoal::None)
 4846                });
 4847            });
 4848
 4849            let mut indent_edits = Vec::new();
 4850            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4851            for row in rows {
 4852                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4853                for (row, indent) in indents {
 4854                    if indent.len == 0 {
 4855                        continue;
 4856                    }
 4857
 4858                    let text = match indent.kind {
 4859                        IndentKind::Space => " ".repeat(indent.len as usize),
 4860                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4861                    };
 4862                    let point = Point::new(row.0, 0);
 4863                    indent_edits.push((point..point, text));
 4864                }
 4865            }
 4866            editor.edit(indent_edits, cx);
 4867        });
 4868    }
 4869
 4870    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4871        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4872            original_indent_columns: Vec::new(),
 4873        });
 4874        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4875    }
 4876
 4877    fn insert_with_autoindent_mode(
 4878        &mut self,
 4879        text: &str,
 4880        autoindent_mode: Option<AutoindentMode>,
 4881        window: &mut Window,
 4882        cx: &mut Context<Self>,
 4883    ) {
 4884        if self.read_only(cx) {
 4885            return;
 4886        }
 4887
 4888        let text: Arc<str> = text.into();
 4889        self.transact(window, cx, |this, window, cx| {
 4890            let old_selections = this.selections.all_adjusted(cx);
 4891            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4892                let anchors = {
 4893                    let snapshot = buffer.read(cx);
 4894                    old_selections
 4895                        .iter()
 4896                        .map(|s| {
 4897                            let anchor = snapshot.anchor_after(s.head());
 4898                            s.map(|_| anchor)
 4899                        })
 4900                        .collect::<Vec<_>>()
 4901                };
 4902                buffer.edit(
 4903                    old_selections
 4904                        .iter()
 4905                        .map(|s| (s.start..s.end, text.clone())),
 4906                    autoindent_mode,
 4907                    cx,
 4908                );
 4909                anchors
 4910            });
 4911
 4912            this.change_selections(Default::default(), window, cx, |s| {
 4913                s.select_anchors(selection_anchors);
 4914            });
 4915
 4916            cx.notify();
 4917        });
 4918    }
 4919
 4920    fn trigger_completion_on_input(
 4921        &mut self,
 4922        text: &str,
 4923        trigger_in_words: bool,
 4924        window: &mut Window,
 4925        cx: &mut Context<Self>,
 4926    ) {
 4927        let completions_source = self
 4928            .context_menu
 4929            .borrow()
 4930            .as_ref()
 4931            .and_then(|menu| match menu {
 4932                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4933                CodeContextMenu::CodeActions(_) => None,
 4934            });
 4935
 4936        match completions_source {
 4937            Some(CompletionsMenuSource::Words { .. }) => {
 4938                self.open_or_update_completions_menu(
 4939                    Some(CompletionsMenuSource::Words {
 4940                        ignore_threshold: false,
 4941                    }),
 4942                    None,
 4943                    window,
 4944                    cx,
 4945                );
 4946            }
 4947            Some(CompletionsMenuSource::Normal)
 4948            | Some(CompletionsMenuSource::SnippetChoices)
 4949            | None
 4950                if self.is_completion_trigger(
 4951                    text,
 4952                    trigger_in_words,
 4953                    completions_source.is_some(),
 4954                    cx,
 4955                ) =>
 4956            {
 4957                self.show_completions(
 4958                    &ShowCompletions {
 4959                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4960                    },
 4961                    window,
 4962                    cx,
 4963                )
 4964            }
 4965            _ => {
 4966                self.hide_context_menu(window, cx);
 4967            }
 4968        }
 4969    }
 4970
 4971    fn is_completion_trigger(
 4972        &self,
 4973        text: &str,
 4974        trigger_in_words: bool,
 4975        menu_is_open: bool,
 4976        cx: &mut Context<Self>,
 4977    ) -> bool {
 4978        let position = self.selections.newest_anchor().head();
 4979        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4980            return false;
 4981        };
 4982
 4983        if let Some(completion_provider) = &self.completion_provider {
 4984            completion_provider.is_completion_trigger(
 4985                &buffer,
 4986                position.text_anchor,
 4987                text,
 4988                trigger_in_words,
 4989                menu_is_open,
 4990                cx,
 4991            )
 4992        } else {
 4993            false
 4994        }
 4995    }
 4996
 4997    /// If any empty selections is touching the start of its innermost containing autoclose
 4998    /// region, expand it to select the brackets.
 4999    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5000        let selections = self.selections.all::<usize>(cx);
 5001        let buffer = self.buffer.read(cx).read(cx);
 5002        let new_selections = self
 5003            .selections_with_autoclose_regions(selections, &buffer)
 5004            .map(|(mut selection, region)| {
 5005                if !selection.is_empty() {
 5006                    return selection;
 5007                }
 5008
 5009                if let Some(region) = region {
 5010                    let mut range = region.range.to_offset(&buffer);
 5011                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5012                        range.start -= region.pair.start.len();
 5013                        if buffer.contains_str_at(range.start, &region.pair.start)
 5014                            && buffer.contains_str_at(range.end, &region.pair.end)
 5015                        {
 5016                            range.end += region.pair.end.len();
 5017                            selection.start = range.start;
 5018                            selection.end = range.end;
 5019
 5020                            return selection;
 5021                        }
 5022                    }
 5023                }
 5024
 5025                let always_treat_brackets_as_autoclosed = buffer
 5026                    .language_settings_at(selection.start, cx)
 5027                    .always_treat_brackets_as_autoclosed;
 5028
 5029                if !always_treat_brackets_as_autoclosed {
 5030                    return selection;
 5031                }
 5032
 5033                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5034                    for (pair, enabled) in scope.brackets() {
 5035                        if !enabled || !pair.close {
 5036                            continue;
 5037                        }
 5038
 5039                        if buffer.contains_str_at(selection.start, &pair.end) {
 5040                            let pair_start_len = pair.start.len();
 5041                            if buffer.contains_str_at(
 5042                                selection.start.saturating_sub(pair_start_len),
 5043                                &pair.start,
 5044                            ) {
 5045                                selection.start -= pair_start_len;
 5046                                selection.end += pair.end.len();
 5047
 5048                                return selection;
 5049                            }
 5050                        }
 5051                    }
 5052                }
 5053
 5054                selection
 5055            })
 5056            .collect();
 5057
 5058        drop(buffer);
 5059        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5060            selections.select(new_selections)
 5061        });
 5062    }
 5063
 5064    /// Iterate the given selections, and for each one, find the smallest surrounding
 5065    /// autoclose region. This uses the ordering of the selections and the autoclose
 5066    /// regions to avoid repeated comparisons.
 5067    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5068        &'a self,
 5069        selections: impl IntoIterator<Item = Selection<D>>,
 5070        buffer: &'a MultiBufferSnapshot,
 5071    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5072        let mut i = 0;
 5073        let mut regions = self.autoclose_regions.as_slice();
 5074        selections.into_iter().map(move |selection| {
 5075            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5076
 5077            let mut enclosing = None;
 5078            while let Some(pair_state) = regions.get(i) {
 5079                if pair_state.range.end.to_offset(buffer) < range.start {
 5080                    regions = &regions[i + 1..];
 5081                    i = 0;
 5082                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5083                    break;
 5084                } else {
 5085                    if pair_state.selection_id == selection.id {
 5086                        enclosing = Some(pair_state);
 5087                    }
 5088                    i += 1;
 5089                }
 5090            }
 5091
 5092            (selection, enclosing)
 5093        })
 5094    }
 5095
 5096    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5097    fn invalidate_autoclose_regions(
 5098        &mut self,
 5099        mut selections: &[Selection<Anchor>],
 5100        buffer: &MultiBufferSnapshot,
 5101    ) {
 5102        self.autoclose_regions.retain(|state| {
 5103            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5104                return false;
 5105            }
 5106
 5107            let mut i = 0;
 5108            while let Some(selection) = selections.get(i) {
 5109                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5110                    selections = &selections[1..];
 5111                    continue;
 5112                }
 5113                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5114                    break;
 5115                }
 5116                if selection.id == state.selection_id {
 5117                    return true;
 5118                } else {
 5119                    i += 1;
 5120                }
 5121            }
 5122            false
 5123        });
 5124    }
 5125
 5126    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5127        let offset = position.to_offset(buffer);
 5128        let (word_range, kind) =
 5129            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5130        if offset > word_range.start && kind == Some(CharKind::Word) {
 5131            Some(
 5132                buffer
 5133                    .text_for_range(word_range.start..offset)
 5134                    .collect::<String>(),
 5135            )
 5136        } else {
 5137            None
 5138        }
 5139    }
 5140
 5141    pub fn toggle_inline_values(
 5142        &mut self,
 5143        _: &ToggleInlineValues,
 5144        _: &mut Window,
 5145        cx: &mut Context<Self>,
 5146    ) {
 5147        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5148
 5149        self.refresh_inline_values(cx);
 5150    }
 5151
 5152    pub fn toggle_inlay_hints(
 5153        &mut self,
 5154        _: &ToggleInlayHints,
 5155        _: &mut Window,
 5156        cx: &mut Context<Self>,
 5157    ) {
 5158        self.refresh_inlay_hints(
 5159            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5160            cx,
 5161        );
 5162    }
 5163
 5164    pub fn inlay_hints_enabled(&self) -> bool {
 5165        self.inlay_hint_cache.enabled
 5166    }
 5167
 5168    pub fn inline_values_enabled(&self) -> bool {
 5169        self.inline_value_cache.enabled
 5170    }
 5171
 5172    #[cfg(any(test, feature = "test-support"))]
 5173    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5174        self.display_map
 5175            .read(cx)
 5176            .current_inlays()
 5177            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5178            .cloned()
 5179            .collect()
 5180    }
 5181
 5182    #[cfg(any(test, feature = "test-support"))]
 5183    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5184        self.display_map
 5185            .read(cx)
 5186            .current_inlays()
 5187            .cloned()
 5188            .collect()
 5189    }
 5190
 5191    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5192        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5193            return;
 5194        }
 5195
 5196        let reason_description = reason.description();
 5197        let ignore_debounce = matches!(
 5198            reason,
 5199            InlayHintRefreshReason::SettingsChange(_)
 5200                | InlayHintRefreshReason::Toggle(_)
 5201                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5202                | InlayHintRefreshReason::ModifiersChanged(_)
 5203        );
 5204        let (invalidate_cache, required_languages) = match reason {
 5205            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5206                match self.inlay_hint_cache.modifiers_override(enabled) {
 5207                    Some(enabled) => {
 5208                        if enabled {
 5209                            (InvalidationStrategy::RefreshRequested, None)
 5210                        } else {
 5211                            self.splice_inlays(
 5212                                &self
 5213                                    .visible_inlay_hints(cx)
 5214                                    .iter()
 5215                                    .map(|inlay| inlay.id)
 5216                                    .collect::<Vec<InlayId>>(),
 5217                                Vec::new(),
 5218                                cx,
 5219                            );
 5220                            return;
 5221                        }
 5222                    }
 5223                    None => return,
 5224                }
 5225            }
 5226            InlayHintRefreshReason::Toggle(enabled) => {
 5227                if self.inlay_hint_cache.toggle(enabled) {
 5228                    if enabled {
 5229                        (InvalidationStrategy::RefreshRequested, None)
 5230                    } else {
 5231                        self.splice_inlays(
 5232                            &self
 5233                                .visible_inlay_hints(cx)
 5234                                .iter()
 5235                                .map(|inlay| inlay.id)
 5236                                .collect::<Vec<InlayId>>(),
 5237                            Vec::new(),
 5238                            cx,
 5239                        );
 5240                        return;
 5241                    }
 5242                } else {
 5243                    return;
 5244                }
 5245            }
 5246            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5247                match self.inlay_hint_cache.update_settings(
 5248                    &self.buffer,
 5249                    new_settings,
 5250                    self.visible_inlay_hints(cx),
 5251                    cx,
 5252                ) {
 5253                    ControlFlow::Break(Some(InlaySplice {
 5254                        to_remove,
 5255                        to_insert,
 5256                    })) => {
 5257                        self.splice_inlays(&to_remove, to_insert, cx);
 5258                        return;
 5259                    }
 5260                    ControlFlow::Break(None) => return,
 5261                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5262                }
 5263            }
 5264            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5265                if let Some(InlaySplice {
 5266                    to_remove,
 5267                    to_insert,
 5268                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5269                {
 5270                    self.splice_inlays(&to_remove, to_insert, cx);
 5271                }
 5272                self.display_map.update(cx, |display_map, _| {
 5273                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5274                });
 5275                return;
 5276            }
 5277            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5278            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5279                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5280            }
 5281            InlayHintRefreshReason::RefreshRequested => {
 5282                (InvalidationStrategy::RefreshRequested, None)
 5283            }
 5284        };
 5285
 5286        if let Some(InlaySplice {
 5287            to_remove,
 5288            to_insert,
 5289        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5290            reason_description,
 5291            self.visible_excerpts(required_languages.as_ref(), cx),
 5292            invalidate_cache,
 5293            ignore_debounce,
 5294            cx,
 5295        ) {
 5296            self.splice_inlays(&to_remove, to_insert, cx);
 5297        }
 5298    }
 5299
 5300    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5301        self.display_map
 5302            .read(cx)
 5303            .current_inlays()
 5304            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5305            .cloned()
 5306            .collect()
 5307    }
 5308
 5309    pub fn visible_excerpts(
 5310        &self,
 5311        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5312        cx: &mut Context<Editor>,
 5313    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5314        let Some(project) = self.project() else {
 5315            return HashMap::default();
 5316        };
 5317        let project = project.read(cx);
 5318        let multi_buffer = self.buffer().read(cx);
 5319        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5320        let multi_buffer_visible_start = self
 5321            .scroll_manager
 5322            .anchor()
 5323            .anchor
 5324            .to_point(&multi_buffer_snapshot);
 5325        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5326            multi_buffer_visible_start
 5327                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5328            Bias::Left,
 5329        );
 5330        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5331        multi_buffer_snapshot
 5332            .range_to_buffer_ranges(multi_buffer_visible_range)
 5333            .into_iter()
 5334            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5335            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5336                let buffer_file = project::File::from_dyn(buffer.file())?;
 5337                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5338                let worktree_entry = buffer_worktree
 5339                    .read(cx)
 5340                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5341                if worktree_entry.is_ignored {
 5342                    return None;
 5343                }
 5344
 5345                let language = buffer.language()?;
 5346                if let Some(restrict_to_languages) = restrict_to_languages
 5347                    && !restrict_to_languages.contains(language)
 5348                {
 5349                    return None;
 5350                }
 5351                Some((
 5352                    excerpt_id,
 5353                    (
 5354                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5355                        buffer.version().clone(),
 5356                        excerpt_visible_range,
 5357                    ),
 5358                ))
 5359            })
 5360            .collect()
 5361    }
 5362
 5363    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5364        TextLayoutDetails {
 5365            text_system: window.text_system().clone(),
 5366            editor_style: self.style.clone().unwrap(),
 5367            rem_size: window.rem_size(),
 5368            scroll_anchor: self.scroll_manager.anchor(),
 5369            visible_rows: self.visible_line_count(),
 5370            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5371        }
 5372    }
 5373
 5374    pub fn splice_inlays(
 5375        &self,
 5376        to_remove: &[InlayId],
 5377        to_insert: Vec<Inlay>,
 5378        cx: &mut Context<Self>,
 5379    ) {
 5380        self.display_map.update(cx, |display_map, cx| {
 5381            display_map.splice_inlays(to_remove, to_insert, cx)
 5382        });
 5383        cx.notify();
 5384    }
 5385
 5386    fn trigger_on_type_formatting(
 5387        &self,
 5388        input: String,
 5389        window: &mut Window,
 5390        cx: &mut Context<Self>,
 5391    ) -> Option<Task<Result<()>>> {
 5392        if input.len() != 1 {
 5393            return None;
 5394        }
 5395
 5396        let project = self.project()?;
 5397        let position = self.selections.newest_anchor().head();
 5398        let (buffer, buffer_position) = self
 5399            .buffer
 5400            .read(cx)
 5401            .text_anchor_for_position(position, cx)?;
 5402
 5403        let settings = language_settings::language_settings(
 5404            buffer
 5405                .read(cx)
 5406                .language_at(buffer_position)
 5407                .map(|l| l.name()),
 5408            buffer.read(cx).file(),
 5409            cx,
 5410        );
 5411        if !settings.use_on_type_format {
 5412            return None;
 5413        }
 5414
 5415        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5416        // hence we do LSP request & edit on host side only — add formats to host's history.
 5417        let push_to_lsp_host_history = true;
 5418        // If this is not the host, append its history with new edits.
 5419        let push_to_client_history = project.read(cx).is_via_collab();
 5420
 5421        let on_type_formatting = project.update(cx, |project, cx| {
 5422            project.on_type_format(
 5423                buffer.clone(),
 5424                buffer_position,
 5425                input,
 5426                push_to_lsp_host_history,
 5427                cx,
 5428            )
 5429        });
 5430        Some(cx.spawn_in(window, async move |editor, cx| {
 5431            if let Some(transaction) = on_type_formatting.await? {
 5432                if push_to_client_history {
 5433                    buffer
 5434                        .update(cx, |buffer, _| {
 5435                            buffer.push_transaction(transaction, Instant::now());
 5436                            buffer.finalize_last_transaction();
 5437                        })
 5438                        .ok();
 5439                }
 5440                editor.update(cx, |editor, cx| {
 5441                    editor.refresh_document_highlights(cx);
 5442                })?;
 5443            }
 5444            Ok(())
 5445        }))
 5446    }
 5447
 5448    pub fn show_word_completions(
 5449        &mut self,
 5450        _: &ShowWordCompletions,
 5451        window: &mut Window,
 5452        cx: &mut Context<Self>,
 5453    ) {
 5454        self.open_or_update_completions_menu(
 5455            Some(CompletionsMenuSource::Words {
 5456                ignore_threshold: true,
 5457            }),
 5458            None,
 5459            window,
 5460            cx,
 5461        );
 5462    }
 5463
 5464    pub fn show_completions(
 5465        &mut self,
 5466        options: &ShowCompletions,
 5467        window: &mut Window,
 5468        cx: &mut Context<Self>,
 5469    ) {
 5470        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5471    }
 5472
 5473    fn open_or_update_completions_menu(
 5474        &mut self,
 5475        requested_source: Option<CompletionsMenuSource>,
 5476        trigger: Option<&str>,
 5477        window: &mut Window,
 5478        cx: &mut Context<Self>,
 5479    ) {
 5480        if self.pending_rename.is_some() {
 5481            return;
 5482        }
 5483
 5484        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5485
 5486        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5487        // inserted and selected. To handle that case, the start of the selection is used so that
 5488        // the menu starts with all choices.
 5489        let position = self
 5490            .selections
 5491            .newest_anchor()
 5492            .start
 5493            .bias_right(&multibuffer_snapshot);
 5494        if position.diff_base_anchor.is_some() {
 5495            return;
 5496        }
 5497        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5498        let Some(buffer) = buffer_position
 5499            .buffer_id
 5500            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5501        else {
 5502            return;
 5503        };
 5504        let buffer_snapshot = buffer.read(cx).snapshot();
 5505
 5506        let query: Option<Arc<String>> =
 5507            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5508                .map(|query| query.into());
 5509
 5510        drop(multibuffer_snapshot);
 5511
 5512        // Hide the current completions menu when query is empty. Without this, cached
 5513        // completions from before the trigger char may be reused (#32774).
 5514        if query.is_none() {
 5515            let menu_is_open = matches!(
 5516                self.context_menu.borrow().as_ref(),
 5517                Some(CodeContextMenu::Completions(_))
 5518            );
 5519            if menu_is_open {
 5520                self.hide_context_menu(window, cx);
 5521            }
 5522        }
 5523
 5524        let mut ignore_word_threshold = false;
 5525        let provider = match requested_source {
 5526            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5527            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5528                ignore_word_threshold = ignore_threshold;
 5529                None
 5530            }
 5531            Some(CompletionsMenuSource::SnippetChoices) => {
 5532                log::error!("bug: SnippetChoices requested_source is not handled");
 5533                None
 5534            }
 5535        };
 5536
 5537        let sort_completions = provider
 5538            .as_ref()
 5539            .is_some_and(|provider| provider.sort_completions());
 5540
 5541        let filter_completions = provider
 5542            .as_ref()
 5543            .is_none_or(|provider| provider.filter_completions());
 5544
 5545        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5546            if filter_completions {
 5547                menu.filter(query.clone(), provider.clone(), window, cx);
 5548            }
 5549            // When `is_incomplete` is false, no need to re-query completions when the current query
 5550            // is a suffix of the initial query.
 5551            if !menu.is_incomplete {
 5552                // If the new query is a suffix of the old query (typing more characters) and
 5553                // the previous result was complete, the existing completions can be filtered.
 5554                //
 5555                // Note that this is always true for snippet completions.
 5556                let query_matches = match (&menu.initial_query, &query) {
 5557                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5558                    (None, _) => true,
 5559                    _ => false,
 5560                };
 5561                if query_matches {
 5562                    let position_matches = if menu.initial_position == position {
 5563                        true
 5564                    } else {
 5565                        let snapshot = self.buffer.read(cx).read(cx);
 5566                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5567                    };
 5568                    if position_matches {
 5569                        return;
 5570                    }
 5571                }
 5572            }
 5573        };
 5574
 5575        let trigger_kind = match trigger {
 5576            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5577                CompletionTriggerKind::TRIGGER_CHARACTER
 5578            }
 5579            _ => CompletionTriggerKind::INVOKED,
 5580        };
 5581        let completion_context = CompletionContext {
 5582            trigger_character: trigger.and_then(|trigger| {
 5583                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5584                    Some(String::from(trigger))
 5585                } else {
 5586                    None
 5587                }
 5588            }),
 5589            trigger_kind,
 5590        };
 5591
 5592        let Anchor {
 5593            excerpt_id: buffer_excerpt_id,
 5594            text_anchor: buffer_position,
 5595            ..
 5596        } = buffer_position;
 5597
 5598        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5599            buffer_snapshot.surrounding_word(buffer_position, None)
 5600        {
 5601            let word_to_exclude = buffer_snapshot
 5602                .text_for_range(word_range.clone())
 5603                .collect::<String>();
 5604            (
 5605                buffer_snapshot.anchor_before(word_range.start)
 5606                    ..buffer_snapshot.anchor_after(buffer_position),
 5607                Some(word_to_exclude),
 5608            )
 5609        } else {
 5610            (buffer_position..buffer_position, None)
 5611        };
 5612
 5613        let language = buffer_snapshot
 5614            .language_at(buffer_position)
 5615            .map(|language| language.name());
 5616
 5617        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5618            .completions
 5619            .clone();
 5620
 5621        let show_completion_documentation = buffer_snapshot
 5622            .settings_at(buffer_position, cx)
 5623            .show_completion_documentation;
 5624
 5625        // The document can be large, so stay in reasonable bounds when searching for words,
 5626        // otherwise completion pop-up might be slow to appear.
 5627        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5628        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5629        let min_word_search = buffer_snapshot.clip_point(
 5630            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5631            Bias::Left,
 5632        );
 5633        let max_word_search = buffer_snapshot.clip_point(
 5634            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5635            Bias::Right,
 5636        );
 5637        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5638            ..buffer_snapshot.point_to_offset(max_word_search);
 5639
 5640        let skip_digits = query
 5641            .as_ref()
 5642            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5643
 5644        let omit_word_completions = !self.word_completions_enabled
 5645            || (!ignore_word_threshold
 5646                && match &query {
 5647                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5648                    None => completion_settings.words_min_length != 0,
 5649                });
 5650
 5651        let (mut words, provider_responses) = match &provider {
 5652            Some(provider) => {
 5653                let provider_responses = provider.completions(
 5654                    buffer_excerpt_id,
 5655                    &buffer,
 5656                    buffer_position,
 5657                    completion_context,
 5658                    window,
 5659                    cx,
 5660                );
 5661
 5662                let words = match (omit_word_completions, completion_settings.words) {
 5663                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5664                        Task::ready(BTreeMap::default())
 5665                    }
 5666                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5667                        .background_spawn(async move {
 5668                            buffer_snapshot.words_in_range(WordsQuery {
 5669                                fuzzy_contents: None,
 5670                                range: word_search_range,
 5671                                skip_digits,
 5672                            })
 5673                        }),
 5674                };
 5675
 5676                (words, provider_responses)
 5677            }
 5678            None => {
 5679                let words = if omit_word_completions {
 5680                    Task::ready(BTreeMap::default())
 5681                } else {
 5682                    cx.background_spawn(async move {
 5683                        buffer_snapshot.words_in_range(WordsQuery {
 5684                            fuzzy_contents: None,
 5685                            range: word_search_range,
 5686                            skip_digits,
 5687                        })
 5688                    })
 5689                };
 5690                (words, Task::ready(Ok(Vec::new())))
 5691            }
 5692        };
 5693
 5694        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5695
 5696        let id = post_inc(&mut self.next_completion_id);
 5697        let task = cx.spawn_in(window, async move |editor, cx| {
 5698            let Ok(()) = editor.update(cx, |this, _| {
 5699                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5700            }) else {
 5701                return;
 5702            };
 5703
 5704            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5705            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5706            let mut completions = Vec::new();
 5707            let mut is_incomplete = false;
 5708            let mut display_options: Option<CompletionDisplayOptions> = None;
 5709            if let Some(provider_responses) = provider_responses.await.log_err()
 5710                && !provider_responses.is_empty()
 5711            {
 5712                for response in provider_responses {
 5713                    completions.extend(response.completions);
 5714                    is_incomplete = is_incomplete || response.is_incomplete;
 5715                    match display_options.as_mut() {
 5716                        None => {
 5717                            display_options = Some(response.display_options);
 5718                        }
 5719                        Some(options) => options.merge(&response.display_options),
 5720                    }
 5721                }
 5722                if completion_settings.words == WordsCompletionMode::Fallback {
 5723                    words = Task::ready(BTreeMap::default());
 5724                }
 5725            }
 5726            let display_options = display_options.unwrap_or_default();
 5727
 5728            let mut words = words.await;
 5729            if let Some(word_to_exclude) = &word_to_exclude {
 5730                words.remove(word_to_exclude);
 5731            }
 5732            for lsp_completion in &completions {
 5733                words.remove(&lsp_completion.new_text);
 5734            }
 5735            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5736                replace_range: word_replace_range.clone(),
 5737                new_text: word.clone(),
 5738                label: CodeLabel::plain(word, None),
 5739                icon_path: None,
 5740                documentation: None,
 5741                source: CompletionSource::BufferWord {
 5742                    word_range,
 5743                    resolved: false,
 5744                },
 5745                insert_text_mode: Some(InsertTextMode::AS_IS),
 5746                confirm: None,
 5747            }));
 5748
 5749            let menu = if completions.is_empty() {
 5750                None
 5751            } else {
 5752                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5753                    let languages = editor
 5754                        .workspace
 5755                        .as_ref()
 5756                        .and_then(|(workspace, _)| workspace.upgrade())
 5757                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5758                    let menu = CompletionsMenu::new(
 5759                        id,
 5760                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5761                        sort_completions,
 5762                        show_completion_documentation,
 5763                        position,
 5764                        query.clone(),
 5765                        is_incomplete,
 5766                        buffer.clone(),
 5767                        completions.into(),
 5768                        display_options,
 5769                        snippet_sort_order,
 5770                        languages,
 5771                        language,
 5772                        cx,
 5773                    );
 5774
 5775                    let query = if filter_completions { query } else { None };
 5776                    let matches_task = if let Some(query) = query {
 5777                        menu.do_async_filtering(query, cx)
 5778                    } else {
 5779                        Task::ready(menu.unfiltered_matches())
 5780                    };
 5781                    (menu, matches_task)
 5782                }) else {
 5783                    return;
 5784                };
 5785
 5786                let matches = matches_task.await;
 5787
 5788                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5789                    // Newer menu already set, so exit.
 5790                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5791                        editor.context_menu.borrow().as_ref()
 5792                        && prev_menu.id > id
 5793                    {
 5794                        return;
 5795                    };
 5796
 5797                    // Only valid to take prev_menu because it the new menu is immediately set
 5798                    // below, or the menu is hidden.
 5799                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5800                        editor.context_menu.borrow_mut().take()
 5801                    {
 5802                        let position_matches =
 5803                            if prev_menu.initial_position == menu.initial_position {
 5804                                true
 5805                            } else {
 5806                                let snapshot = editor.buffer.read(cx).read(cx);
 5807                                prev_menu.initial_position.to_offset(&snapshot)
 5808                                    == menu.initial_position.to_offset(&snapshot)
 5809                            };
 5810                        if position_matches {
 5811                            // Preserve markdown cache before `set_filter_results` because it will
 5812                            // try to populate the documentation cache.
 5813                            menu.preserve_markdown_cache(prev_menu);
 5814                        }
 5815                    };
 5816
 5817                    menu.set_filter_results(matches, provider, window, cx);
 5818                }) else {
 5819                    return;
 5820                };
 5821
 5822                menu.visible().then_some(menu)
 5823            };
 5824
 5825            editor
 5826                .update_in(cx, |editor, window, cx| {
 5827                    if editor.focus_handle.is_focused(window)
 5828                        && let Some(menu) = menu
 5829                    {
 5830                        *editor.context_menu.borrow_mut() =
 5831                            Some(CodeContextMenu::Completions(menu));
 5832
 5833                        crate::hover_popover::hide_hover(editor, cx);
 5834                        if editor.show_edit_predictions_in_menu() {
 5835                            editor.update_visible_edit_prediction(window, cx);
 5836                        } else {
 5837                            editor.discard_edit_prediction(false, cx);
 5838                        }
 5839
 5840                        cx.notify();
 5841                        return;
 5842                    }
 5843
 5844                    if editor.completion_tasks.len() <= 1 {
 5845                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5846                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5847                        // If it was already hidden and we don't show edit predictions in the menu,
 5848                        // we should also show the edit prediction when available.
 5849                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5850                            editor.update_visible_edit_prediction(window, cx);
 5851                        }
 5852                    }
 5853                })
 5854                .ok();
 5855        });
 5856
 5857        self.completion_tasks.push((id, task));
 5858    }
 5859
 5860    #[cfg(feature = "test-support")]
 5861    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5862        let menu = self.context_menu.borrow();
 5863        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5864            let completions = menu.completions.borrow();
 5865            Some(completions.to_vec())
 5866        } else {
 5867            None
 5868        }
 5869    }
 5870
 5871    pub fn with_completions_menu_matching_id<R>(
 5872        &self,
 5873        id: CompletionId,
 5874        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5875    ) -> R {
 5876        let mut context_menu = self.context_menu.borrow_mut();
 5877        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5878            return f(None);
 5879        };
 5880        if completions_menu.id != id {
 5881            return f(None);
 5882        }
 5883        f(Some(completions_menu))
 5884    }
 5885
 5886    pub fn confirm_completion(
 5887        &mut self,
 5888        action: &ConfirmCompletion,
 5889        window: &mut Window,
 5890        cx: &mut Context<Self>,
 5891    ) -> Option<Task<Result<()>>> {
 5892        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5893        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5894    }
 5895
 5896    pub fn confirm_completion_insert(
 5897        &mut self,
 5898        _: &ConfirmCompletionInsert,
 5899        window: &mut Window,
 5900        cx: &mut Context<Self>,
 5901    ) -> Option<Task<Result<()>>> {
 5902        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5903        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5904    }
 5905
 5906    pub fn confirm_completion_replace(
 5907        &mut self,
 5908        _: &ConfirmCompletionReplace,
 5909        window: &mut Window,
 5910        cx: &mut Context<Self>,
 5911    ) -> Option<Task<Result<()>>> {
 5912        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5913        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5914    }
 5915
 5916    pub fn compose_completion(
 5917        &mut self,
 5918        action: &ComposeCompletion,
 5919        window: &mut Window,
 5920        cx: &mut Context<Self>,
 5921    ) -> Option<Task<Result<()>>> {
 5922        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5923        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5924    }
 5925
 5926    fn do_completion(
 5927        &mut self,
 5928        item_ix: Option<usize>,
 5929        intent: CompletionIntent,
 5930        window: &mut Window,
 5931        cx: &mut Context<Editor>,
 5932    ) -> Option<Task<Result<()>>> {
 5933        use language::ToOffset as _;
 5934
 5935        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5936        else {
 5937            return None;
 5938        };
 5939
 5940        let candidate_id = {
 5941            let entries = completions_menu.entries.borrow();
 5942            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5943            if self.show_edit_predictions_in_menu() {
 5944                self.discard_edit_prediction(true, cx);
 5945            }
 5946            mat.candidate_id
 5947        };
 5948
 5949        let completion = completions_menu
 5950            .completions
 5951            .borrow()
 5952            .get(candidate_id)?
 5953            .clone();
 5954        cx.stop_propagation();
 5955
 5956        let buffer_handle = completions_menu.buffer.clone();
 5957
 5958        let CompletionEdit {
 5959            new_text,
 5960            snippet,
 5961            replace_range,
 5962        } = process_completion_for_edit(
 5963            &completion,
 5964            intent,
 5965            &buffer_handle,
 5966            &completions_menu.initial_position.text_anchor,
 5967            cx,
 5968        );
 5969
 5970        let buffer = buffer_handle.read(cx);
 5971        let snapshot = self.buffer.read(cx).snapshot(cx);
 5972        let newest_anchor = self.selections.newest_anchor();
 5973        let replace_range_multibuffer = {
 5974            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5975            let multibuffer_anchor = snapshot
 5976                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5977                .unwrap()
 5978                ..snapshot
 5979                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5980                    .unwrap();
 5981            multibuffer_anchor.start.to_offset(&snapshot)
 5982                ..multibuffer_anchor.end.to_offset(&snapshot)
 5983        };
 5984        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5985            return None;
 5986        }
 5987
 5988        let old_text = buffer
 5989            .text_for_range(replace_range.clone())
 5990            .collect::<String>();
 5991        let lookbehind = newest_anchor
 5992            .start
 5993            .text_anchor
 5994            .to_offset(buffer)
 5995            .saturating_sub(replace_range.start);
 5996        let lookahead = replace_range
 5997            .end
 5998            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5999        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6000        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6001
 6002        let selections = self.selections.all::<usize>(cx);
 6003        let mut ranges = Vec::new();
 6004        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6005
 6006        for selection in &selections {
 6007            let range = if selection.id == newest_anchor.id {
 6008                replace_range_multibuffer.clone()
 6009            } else {
 6010                let mut range = selection.range();
 6011
 6012                // if prefix is present, don't duplicate it
 6013                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6014                    range.start = range.start.saturating_sub(lookbehind);
 6015
 6016                    // if suffix is also present, mimic the newest cursor and replace it
 6017                    if selection.id != newest_anchor.id
 6018                        && snapshot.contains_str_at(range.end, suffix)
 6019                    {
 6020                        range.end += lookahead;
 6021                    }
 6022                }
 6023                range
 6024            };
 6025
 6026            ranges.push(range.clone());
 6027
 6028            if !self.linked_edit_ranges.is_empty() {
 6029                let start_anchor = snapshot.anchor_before(range.start);
 6030                let end_anchor = snapshot.anchor_after(range.end);
 6031                if let Some(ranges) = self
 6032                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6033                {
 6034                    for (buffer, edits) in ranges {
 6035                        linked_edits
 6036                            .entry(buffer.clone())
 6037                            .or_default()
 6038                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6039                    }
 6040                }
 6041            }
 6042        }
 6043
 6044        let common_prefix_len = old_text
 6045            .chars()
 6046            .zip(new_text.chars())
 6047            .take_while(|(a, b)| a == b)
 6048            .map(|(a, _)| a.len_utf8())
 6049            .sum::<usize>();
 6050
 6051        cx.emit(EditorEvent::InputHandled {
 6052            utf16_range_to_replace: None,
 6053            text: new_text[common_prefix_len..].into(),
 6054        });
 6055
 6056        self.transact(window, cx, |editor, window, cx| {
 6057            if let Some(mut snippet) = snippet {
 6058                snippet.text = new_text.to_string();
 6059                editor
 6060                    .insert_snippet(&ranges, snippet, window, cx)
 6061                    .log_err();
 6062            } else {
 6063                editor.buffer.update(cx, |multi_buffer, cx| {
 6064                    let auto_indent = match completion.insert_text_mode {
 6065                        Some(InsertTextMode::AS_IS) => None,
 6066                        _ => editor.autoindent_mode.clone(),
 6067                    };
 6068                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6069                    multi_buffer.edit(edits, auto_indent, cx);
 6070                });
 6071            }
 6072            for (buffer, edits) in linked_edits {
 6073                buffer.update(cx, |buffer, cx| {
 6074                    let snapshot = buffer.snapshot();
 6075                    let edits = edits
 6076                        .into_iter()
 6077                        .map(|(range, text)| {
 6078                            use text::ToPoint as TP;
 6079                            let end_point = TP::to_point(&range.end, &snapshot);
 6080                            let start_point = TP::to_point(&range.start, &snapshot);
 6081                            (start_point..end_point, text)
 6082                        })
 6083                        .sorted_by_key(|(range, _)| range.start);
 6084                    buffer.edit(edits, None, cx);
 6085                })
 6086            }
 6087
 6088            editor.refresh_edit_prediction(true, false, window, cx);
 6089        });
 6090        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6091
 6092        let show_new_completions_on_confirm = completion
 6093            .confirm
 6094            .as_ref()
 6095            .is_some_and(|confirm| confirm(intent, window, cx));
 6096        if show_new_completions_on_confirm {
 6097            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6098        }
 6099
 6100        let provider = self.completion_provider.as_ref()?;
 6101        drop(completion);
 6102        let apply_edits = provider.apply_additional_edits_for_completion(
 6103            buffer_handle,
 6104            completions_menu.completions.clone(),
 6105            candidate_id,
 6106            true,
 6107            cx,
 6108        );
 6109
 6110        let editor_settings = EditorSettings::get_global(cx);
 6111        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6112            // After the code completion is finished, users often want to know what signatures are needed.
 6113            // so we should automatically call signature_help
 6114            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6115        }
 6116
 6117        Some(cx.foreground_executor().spawn(async move {
 6118            apply_edits.await?;
 6119            Ok(())
 6120        }))
 6121    }
 6122
 6123    pub fn toggle_code_actions(
 6124        &mut self,
 6125        action: &ToggleCodeActions,
 6126        window: &mut Window,
 6127        cx: &mut Context<Self>,
 6128    ) {
 6129        let quick_launch = action.quick_launch;
 6130        let mut context_menu = self.context_menu.borrow_mut();
 6131        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6132            if code_actions.deployed_from == action.deployed_from {
 6133                // Toggle if we're selecting the same one
 6134                *context_menu = None;
 6135                cx.notify();
 6136                return;
 6137            } else {
 6138                // Otherwise, clear it and start a new one
 6139                *context_menu = None;
 6140                cx.notify();
 6141            }
 6142        }
 6143        drop(context_menu);
 6144        let snapshot = self.snapshot(window, cx);
 6145        let deployed_from = action.deployed_from.clone();
 6146        let action = action.clone();
 6147        self.completion_tasks.clear();
 6148        self.discard_edit_prediction(false, cx);
 6149
 6150        let multibuffer_point = match &action.deployed_from {
 6151            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6152                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6153            }
 6154            _ => self.selections.newest::<Point>(cx).head(),
 6155        };
 6156        let Some((buffer, buffer_row)) = snapshot
 6157            .buffer_snapshot
 6158            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6159            .and_then(|(buffer_snapshot, range)| {
 6160                self.buffer()
 6161                    .read(cx)
 6162                    .buffer(buffer_snapshot.remote_id())
 6163                    .map(|buffer| (buffer, range.start.row))
 6164            })
 6165        else {
 6166            return;
 6167        };
 6168        let buffer_id = buffer.read(cx).remote_id();
 6169        let tasks = self
 6170            .tasks
 6171            .get(&(buffer_id, buffer_row))
 6172            .map(|t| Arc::new(t.to_owned()));
 6173
 6174        if !self.focus_handle.is_focused(window) {
 6175            return;
 6176        }
 6177        let project = self.project.clone();
 6178
 6179        let code_actions_task = match deployed_from {
 6180            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6181            _ => self.code_actions(buffer_row, window, cx),
 6182        };
 6183
 6184        let runnable_task = match deployed_from {
 6185            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6186            _ => {
 6187                let mut task_context_task = Task::ready(None);
 6188                if let Some(tasks) = &tasks
 6189                    && let Some(project) = project
 6190                {
 6191                    task_context_task =
 6192                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6193                }
 6194
 6195                cx.spawn_in(window, {
 6196                    let buffer = buffer.clone();
 6197                    async move |editor, cx| {
 6198                        let task_context = task_context_task.await;
 6199
 6200                        let resolved_tasks =
 6201                            tasks
 6202                                .zip(task_context.clone())
 6203                                .map(|(tasks, task_context)| ResolvedTasks {
 6204                                    templates: tasks.resolve(&task_context).collect(),
 6205                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6206                                        multibuffer_point.row,
 6207                                        tasks.column,
 6208                                    )),
 6209                                });
 6210                        let debug_scenarios = editor
 6211                            .update(cx, |editor, cx| {
 6212                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6213                            })?
 6214                            .await;
 6215                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6216                    }
 6217                })
 6218            }
 6219        };
 6220
 6221        cx.spawn_in(window, async move |editor, cx| {
 6222            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6223            let code_actions = code_actions_task.await;
 6224            let spawn_straight_away = quick_launch
 6225                && resolved_tasks
 6226                    .as_ref()
 6227                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6228                && code_actions
 6229                    .as_ref()
 6230                    .is_none_or(|actions| actions.is_empty())
 6231                && debug_scenarios.is_empty();
 6232
 6233            editor.update_in(cx, |editor, window, cx| {
 6234                crate::hover_popover::hide_hover(editor, cx);
 6235                let actions = CodeActionContents::new(
 6236                    resolved_tasks,
 6237                    code_actions,
 6238                    debug_scenarios,
 6239                    task_context.unwrap_or_default(),
 6240                );
 6241
 6242                // Don't show the menu if there are no actions available
 6243                if actions.is_empty() {
 6244                    cx.notify();
 6245                    return Task::ready(Ok(()));
 6246                }
 6247
 6248                *editor.context_menu.borrow_mut() =
 6249                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6250                        buffer,
 6251                        actions,
 6252                        selected_item: Default::default(),
 6253                        scroll_handle: UniformListScrollHandle::default(),
 6254                        deployed_from,
 6255                    }));
 6256                cx.notify();
 6257                if spawn_straight_away
 6258                    && let Some(task) = editor.confirm_code_action(
 6259                        &ConfirmCodeAction { item_ix: Some(0) },
 6260                        window,
 6261                        cx,
 6262                    )
 6263                {
 6264                    return task;
 6265                }
 6266
 6267                Task::ready(Ok(()))
 6268            })
 6269        })
 6270        .detach_and_log_err(cx);
 6271    }
 6272
 6273    fn debug_scenarios(
 6274        &mut self,
 6275        resolved_tasks: &Option<ResolvedTasks>,
 6276        buffer: &Entity<Buffer>,
 6277        cx: &mut App,
 6278    ) -> Task<Vec<task::DebugScenario>> {
 6279        maybe!({
 6280            let project = self.project()?;
 6281            let dap_store = project.read(cx).dap_store();
 6282            let mut scenarios = vec![];
 6283            let resolved_tasks = resolved_tasks.as_ref()?;
 6284            let buffer = buffer.read(cx);
 6285            let language = buffer.language()?;
 6286            let file = buffer.file();
 6287            let debug_adapter = language_settings(language.name().into(), file, cx)
 6288                .debuggers
 6289                .first()
 6290                .map(SharedString::from)
 6291                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6292
 6293            dap_store.update(cx, |dap_store, cx| {
 6294                for (_, task) in &resolved_tasks.templates {
 6295                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6296                        task.original_task().clone(),
 6297                        debug_adapter.clone().into(),
 6298                        task.display_label().to_owned().into(),
 6299                        cx,
 6300                    );
 6301                    scenarios.push(maybe_scenario);
 6302                }
 6303            });
 6304            Some(cx.background_spawn(async move {
 6305                futures::future::join_all(scenarios)
 6306                    .await
 6307                    .into_iter()
 6308                    .flatten()
 6309                    .collect::<Vec<_>>()
 6310            }))
 6311        })
 6312        .unwrap_or_else(|| Task::ready(vec![]))
 6313    }
 6314
 6315    fn code_actions(
 6316        &mut self,
 6317        buffer_row: u32,
 6318        window: &mut Window,
 6319        cx: &mut Context<Self>,
 6320    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6321        let mut task = self.code_actions_task.take();
 6322        cx.spawn_in(window, async move |editor, cx| {
 6323            while let Some(prev_task) = task {
 6324                prev_task.await.log_err();
 6325                task = editor
 6326                    .update(cx, |this, _| this.code_actions_task.take())
 6327                    .ok()?;
 6328            }
 6329
 6330            editor
 6331                .update(cx, |editor, cx| {
 6332                    editor
 6333                        .available_code_actions
 6334                        .clone()
 6335                        .and_then(|(location, code_actions)| {
 6336                            let snapshot = location.buffer.read(cx).snapshot();
 6337                            let point_range = location.range.to_point(&snapshot);
 6338                            let point_range = point_range.start.row..=point_range.end.row;
 6339                            if point_range.contains(&buffer_row) {
 6340                                Some(code_actions)
 6341                            } else {
 6342                                None
 6343                            }
 6344                        })
 6345                })
 6346                .ok()
 6347                .flatten()
 6348        })
 6349    }
 6350
 6351    pub fn confirm_code_action(
 6352        &mut self,
 6353        action: &ConfirmCodeAction,
 6354        window: &mut Window,
 6355        cx: &mut Context<Self>,
 6356    ) -> Option<Task<Result<()>>> {
 6357        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6358
 6359        let actions_menu =
 6360            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6361                menu
 6362            } else {
 6363                return None;
 6364            };
 6365
 6366        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6367        let action = actions_menu.actions.get(action_ix)?;
 6368        let title = action.label();
 6369        let buffer = actions_menu.buffer;
 6370        let workspace = self.workspace()?;
 6371
 6372        match action {
 6373            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6374                workspace.update(cx, |workspace, cx| {
 6375                    workspace.schedule_resolved_task(
 6376                        task_source_kind,
 6377                        resolved_task,
 6378                        false,
 6379                        window,
 6380                        cx,
 6381                    );
 6382
 6383                    Some(Task::ready(Ok(())))
 6384                })
 6385            }
 6386            CodeActionsItem::CodeAction {
 6387                excerpt_id,
 6388                action,
 6389                provider,
 6390            } => {
 6391                let apply_code_action =
 6392                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6393                let workspace = workspace.downgrade();
 6394                Some(cx.spawn_in(window, async move |editor, cx| {
 6395                    let project_transaction = apply_code_action.await?;
 6396                    Self::open_project_transaction(
 6397                        &editor,
 6398                        workspace,
 6399                        project_transaction,
 6400                        title,
 6401                        cx,
 6402                    )
 6403                    .await
 6404                }))
 6405            }
 6406            CodeActionsItem::DebugScenario(scenario) => {
 6407                let context = actions_menu.actions.context;
 6408
 6409                workspace.update(cx, |workspace, cx| {
 6410                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6411                    workspace.start_debug_session(
 6412                        scenario,
 6413                        context,
 6414                        Some(buffer),
 6415                        None,
 6416                        window,
 6417                        cx,
 6418                    );
 6419                });
 6420                Some(Task::ready(Ok(())))
 6421            }
 6422        }
 6423    }
 6424
 6425    pub async fn open_project_transaction(
 6426        editor: &WeakEntity<Editor>,
 6427        workspace: WeakEntity<Workspace>,
 6428        transaction: ProjectTransaction,
 6429        title: String,
 6430        cx: &mut AsyncWindowContext,
 6431    ) -> Result<()> {
 6432        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6433        cx.update(|_, cx| {
 6434            entries.sort_unstable_by_key(|(buffer, _)| {
 6435                buffer.read(cx).file().map(|f| f.path().clone())
 6436            });
 6437        })?;
 6438        if entries.is_empty() {
 6439            return Ok(());
 6440        }
 6441
 6442        // If the project transaction's edits are all contained within this editor, then
 6443        // avoid opening a new editor to display them.
 6444
 6445        if let [(buffer, transaction)] = &*entries {
 6446            let excerpt = editor.update(cx, |editor, cx| {
 6447                editor
 6448                    .buffer()
 6449                    .read(cx)
 6450                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6451            })?;
 6452            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6453                && excerpted_buffer == *buffer
 6454            {
 6455                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6456                    let excerpt_range = excerpt_range.to_offset(buffer);
 6457                    buffer
 6458                        .edited_ranges_for_transaction::<usize>(transaction)
 6459                        .all(|range| {
 6460                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6461                        })
 6462                })?;
 6463
 6464                if all_edits_within_excerpt {
 6465                    return Ok(());
 6466                }
 6467            }
 6468        }
 6469
 6470        let mut ranges_to_highlight = Vec::new();
 6471        let excerpt_buffer = cx.new(|cx| {
 6472            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6473            for (buffer_handle, transaction) in &entries {
 6474                let edited_ranges = buffer_handle
 6475                    .read(cx)
 6476                    .edited_ranges_for_transaction::<Point>(transaction)
 6477                    .collect::<Vec<_>>();
 6478                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6479                    PathKey::for_buffer(buffer_handle, cx),
 6480                    buffer_handle.clone(),
 6481                    edited_ranges,
 6482                    multibuffer_context_lines(cx),
 6483                    cx,
 6484                );
 6485
 6486                ranges_to_highlight.extend(ranges);
 6487            }
 6488            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6489            multibuffer
 6490        })?;
 6491
 6492        workspace.update_in(cx, |workspace, window, cx| {
 6493            let project = workspace.project().clone();
 6494            let editor =
 6495                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6496            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6497            editor.update(cx, |editor, cx| {
 6498                editor.highlight_background::<Self>(
 6499                    &ranges_to_highlight,
 6500                    |theme| theme.colors().editor_highlighted_line_background,
 6501                    cx,
 6502                );
 6503            });
 6504        })?;
 6505
 6506        Ok(())
 6507    }
 6508
 6509    pub fn clear_code_action_providers(&mut self) {
 6510        self.code_action_providers.clear();
 6511        self.available_code_actions.take();
 6512    }
 6513
 6514    pub fn add_code_action_provider(
 6515        &mut self,
 6516        provider: Rc<dyn CodeActionProvider>,
 6517        window: &mut Window,
 6518        cx: &mut Context<Self>,
 6519    ) {
 6520        if self
 6521            .code_action_providers
 6522            .iter()
 6523            .any(|existing_provider| existing_provider.id() == provider.id())
 6524        {
 6525            return;
 6526        }
 6527
 6528        self.code_action_providers.push(provider);
 6529        self.refresh_code_actions(window, cx);
 6530    }
 6531
 6532    pub fn remove_code_action_provider(
 6533        &mut self,
 6534        id: Arc<str>,
 6535        window: &mut Window,
 6536        cx: &mut Context<Self>,
 6537    ) {
 6538        self.code_action_providers
 6539            .retain(|provider| provider.id() != id);
 6540        self.refresh_code_actions(window, cx);
 6541    }
 6542
 6543    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6544        !self.code_action_providers.is_empty()
 6545            && EditorSettings::get_global(cx).toolbar.code_actions
 6546    }
 6547
 6548    pub fn has_available_code_actions(&self) -> bool {
 6549        self.available_code_actions
 6550            .as_ref()
 6551            .is_some_and(|(_, actions)| !actions.is_empty())
 6552    }
 6553
 6554    fn render_inline_code_actions(
 6555        &self,
 6556        icon_size: ui::IconSize,
 6557        display_row: DisplayRow,
 6558        is_active: bool,
 6559        cx: &mut Context<Self>,
 6560    ) -> AnyElement {
 6561        let show_tooltip = !self.context_menu_visible();
 6562        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6563            .icon_size(icon_size)
 6564            .shape(ui::IconButtonShape::Square)
 6565            .icon_color(ui::Color::Hidden)
 6566            .toggle_state(is_active)
 6567            .when(show_tooltip, |this| {
 6568                this.tooltip({
 6569                    let focus_handle = self.focus_handle.clone();
 6570                    move |window, cx| {
 6571                        Tooltip::for_action_in(
 6572                            "Toggle Code Actions",
 6573                            &ToggleCodeActions {
 6574                                deployed_from: None,
 6575                                quick_launch: false,
 6576                            },
 6577                            &focus_handle,
 6578                            window,
 6579                            cx,
 6580                        )
 6581                    }
 6582                })
 6583            })
 6584            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6585                window.focus(&editor.focus_handle(cx));
 6586                editor.toggle_code_actions(
 6587                    &crate::actions::ToggleCodeActions {
 6588                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6589                            display_row,
 6590                        )),
 6591                        quick_launch: false,
 6592                    },
 6593                    window,
 6594                    cx,
 6595                );
 6596            }))
 6597            .into_any_element()
 6598    }
 6599
 6600    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6601        &self.context_menu
 6602    }
 6603
 6604    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6605        let newest_selection = self.selections.newest_anchor().clone();
 6606        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6607        let buffer = self.buffer.read(cx);
 6608        if newest_selection.head().diff_base_anchor.is_some() {
 6609            return None;
 6610        }
 6611        let (start_buffer, start) =
 6612            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6613        let (end_buffer, end) =
 6614            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6615        if start_buffer != end_buffer {
 6616            return None;
 6617        }
 6618
 6619        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6620            cx.background_executor()
 6621                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6622                .await;
 6623
 6624            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6625                let providers = this.code_action_providers.clone();
 6626                let tasks = this
 6627                    .code_action_providers
 6628                    .iter()
 6629                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6630                    .collect::<Vec<_>>();
 6631                (providers, tasks)
 6632            })?;
 6633
 6634            let mut actions = Vec::new();
 6635            for (provider, provider_actions) in
 6636                providers.into_iter().zip(future::join_all(tasks).await)
 6637            {
 6638                if let Some(provider_actions) = provider_actions.log_err() {
 6639                    actions.extend(provider_actions.into_iter().map(|action| {
 6640                        AvailableCodeAction {
 6641                            excerpt_id: newest_selection.start.excerpt_id,
 6642                            action,
 6643                            provider: provider.clone(),
 6644                        }
 6645                    }));
 6646                }
 6647            }
 6648
 6649            this.update(cx, |this, cx| {
 6650                this.available_code_actions = if actions.is_empty() {
 6651                    None
 6652                } else {
 6653                    Some((
 6654                        Location {
 6655                            buffer: start_buffer,
 6656                            range: start..end,
 6657                        },
 6658                        actions.into(),
 6659                    ))
 6660                };
 6661                cx.notify();
 6662            })
 6663        }));
 6664        None
 6665    }
 6666
 6667    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6668        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6669            self.show_git_blame_inline = false;
 6670
 6671            self.show_git_blame_inline_delay_task =
 6672                Some(cx.spawn_in(window, async move |this, cx| {
 6673                    cx.background_executor().timer(delay).await;
 6674
 6675                    this.update(cx, |this, cx| {
 6676                        this.show_git_blame_inline = true;
 6677                        cx.notify();
 6678                    })
 6679                    .log_err();
 6680                }));
 6681        }
 6682    }
 6683
 6684    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6685        let snapshot = self.snapshot(window, cx);
 6686        let cursor = self.selections.newest::<Point>(cx).head();
 6687        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6688        else {
 6689            return;
 6690        };
 6691
 6692        let Some(blame) = self.blame.as_ref() else {
 6693            return;
 6694        };
 6695
 6696        let row_info = RowInfo {
 6697            buffer_id: Some(buffer.remote_id()),
 6698            buffer_row: Some(point.row),
 6699            ..Default::default()
 6700        };
 6701        let Some((buffer, blame_entry)) = blame
 6702            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6703            .flatten()
 6704        else {
 6705            return;
 6706        };
 6707
 6708        let anchor = self.selections.newest_anchor().head();
 6709        let position = self.to_pixel_point(anchor, &snapshot, window);
 6710        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6711            self.show_blame_popover(
 6712                buffer,
 6713                &blame_entry,
 6714                position + last_bounds.origin,
 6715                true,
 6716                cx,
 6717            );
 6718        };
 6719    }
 6720
 6721    fn show_blame_popover(
 6722        &mut self,
 6723        buffer: BufferId,
 6724        blame_entry: &BlameEntry,
 6725        position: gpui::Point<Pixels>,
 6726        ignore_timeout: bool,
 6727        cx: &mut Context<Self>,
 6728    ) {
 6729        if let Some(state) = &mut self.inline_blame_popover {
 6730            state.hide_task.take();
 6731        } else {
 6732            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6733            let blame_entry = blame_entry.clone();
 6734            let show_task = cx.spawn(async move |editor, cx| {
 6735                if !ignore_timeout {
 6736                    cx.background_executor()
 6737                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6738                        .await;
 6739                }
 6740                editor
 6741                    .update(cx, |editor, cx| {
 6742                        editor.inline_blame_popover_show_task.take();
 6743                        let Some(blame) = editor.blame.as_ref() else {
 6744                            return;
 6745                        };
 6746                        let blame = blame.read(cx);
 6747                        let details = blame.details_for_entry(buffer, &blame_entry);
 6748                        let markdown = cx.new(|cx| {
 6749                            Markdown::new(
 6750                                details
 6751                                    .as_ref()
 6752                                    .map(|message| message.message.clone())
 6753                                    .unwrap_or_default(),
 6754                                None,
 6755                                None,
 6756                                cx,
 6757                            )
 6758                        });
 6759                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6760                            position,
 6761                            hide_task: None,
 6762                            popover_bounds: None,
 6763                            popover_state: InlineBlamePopoverState {
 6764                                scroll_handle: ScrollHandle::new(),
 6765                                commit_message: details,
 6766                                markdown,
 6767                            },
 6768                            keyboard_grace: ignore_timeout,
 6769                        });
 6770                        cx.notify();
 6771                    })
 6772                    .ok();
 6773            });
 6774            self.inline_blame_popover_show_task = Some(show_task);
 6775        }
 6776    }
 6777
 6778    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6779        self.inline_blame_popover_show_task.take();
 6780        if let Some(state) = &mut self.inline_blame_popover {
 6781            let hide_task = cx.spawn(async move |editor, cx| {
 6782                cx.background_executor()
 6783                    .timer(std::time::Duration::from_millis(100))
 6784                    .await;
 6785                editor
 6786                    .update(cx, |editor, cx| {
 6787                        editor.inline_blame_popover.take();
 6788                        cx.notify();
 6789                    })
 6790                    .ok();
 6791            });
 6792            state.hide_task = Some(hide_task);
 6793        }
 6794    }
 6795
 6796    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6797        if self.pending_rename.is_some() {
 6798            return None;
 6799        }
 6800
 6801        let provider = self.semantics_provider.clone()?;
 6802        let buffer = self.buffer.read(cx);
 6803        let newest_selection = self.selections.newest_anchor().clone();
 6804        let cursor_position = newest_selection.head();
 6805        let (cursor_buffer, cursor_buffer_position) =
 6806            buffer.text_anchor_for_position(cursor_position, cx)?;
 6807        let (tail_buffer, tail_buffer_position) =
 6808            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6809        if cursor_buffer != tail_buffer {
 6810            return None;
 6811        }
 6812
 6813        let snapshot = cursor_buffer.read(cx).snapshot();
 6814        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6815        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6816        if start_word_range != end_word_range {
 6817            self.document_highlights_task.take();
 6818            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6819            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6820            return None;
 6821        }
 6822
 6823        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6824        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6825            cx.background_executor()
 6826                .timer(Duration::from_millis(debounce))
 6827                .await;
 6828
 6829            let highlights = if let Some(highlights) = cx
 6830                .update(|cx| {
 6831                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6832                })
 6833                .ok()
 6834                .flatten()
 6835            {
 6836                highlights.await.log_err()
 6837            } else {
 6838                None
 6839            };
 6840
 6841            if let Some(highlights) = highlights {
 6842                this.update(cx, |this, cx| {
 6843                    if this.pending_rename.is_some() {
 6844                        return;
 6845                    }
 6846
 6847                    let buffer = this.buffer.read(cx);
 6848                    if buffer
 6849                        .text_anchor_for_position(cursor_position, cx)
 6850                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6851                    {
 6852                        return;
 6853                    }
 6854
 6855                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6856                    let mut write_ranges = Vec::new();
 6857                    let mut read_ranges = Vec::new();
 6858                    for highlight in highlights {
 6859                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6860                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6861                        {
 6862                            let start = highlight
 6863                                .range
 6864                                .start
 6865                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6866                            let end = highlight
 6867                                .range
 6868                                .end
 6869                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6870                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6871                                continue;
 6872                            }
 6873
 6874                            let range = Anchor {
 6875                                buffer_id: Some(buffer_id),
 6876                                excerpt_id,
 6877                                text_anchor: start,
 6878                                diff_base_anchor: None,
 6879                            }..Anchor {
 6880                                buffer_id: Some(buffer_id),
 6881                                excerpt_id,
 6882                                text_anchor: end,
 6883                                diff_base_anchor: None,
 6884                            };
 6885                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6886                                write_ranges.push(range);
 6887                            } else {
 6888                                read_ranges.push(range);
 6889                            }
 6890                        }
 6891                    }
 6892
 6893                    this.highlight_background::<DocumentHighlightRead>(
 6894                        &read_ranges,
 6895                        |theme| theme.colors().editor_document_highlight_read_background,
 6896                        cx,
 6897                    );
 6898                    this.highlight_background::<DocumentHighlightWrite>(
 6899                        &write_ranges,
 6900                        |theme| theme.colors().editor_document_highlight_write_background,
 6901                        cx,
 6902                    );
 6903                    cx.notify();
 6904                })
 6905                .log_err();
 6906            }
 6907        }));
 6908        None
 6909    }
 6910
 6911    fn prepare_highlight_query_from_selection(
 6912        &mut self,
 6913        cx: &mut Context<Editor>,
 6914    ) -> Option<(String, Range<Anchor>)> {
 6915        if matches!(self.mode, EditorMode::SingleLine) {
 6916            return None;
 6917        }
 6918        if !EditorSettings::get_global(cx).selection_highlight {
 6919            return None;
 6920        }
 6921        if self.selections.count() != 1 || self.selections.line_mode() {
 6922            return None;
 6923        }
 6924        let selection = self.selections.newest::<Point>(cx);
 6925        if selection.is_empty() || selection.start.row != selection.end.row {
 6926            return None;
 6927        }
 6928        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6929        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6930        let query = multi_buffer_snapshot
 6931            .text_for_range(selection_anchor_range.clone())
 6932            .collect::<String>();
 6933        if query.trim().is_empty() {
 6934            return None;
 6935        }
 6936        Some((query, selection_anchor_range))
 6937    }
 6938
 6939    fn update_selection_occurrence_highlights(
 6940        &mut self,
 6941        query_text: String,
 6942        query_range: Range<Anchor>,
 6943        multi_buffer_range_to_query: Range<Point>,
 6944        use_debounce: bool,
 6945        window: &mut Window,
 6946        cx: &mut Context<Editor>,
 6947    ) -> Task<()> {
 6948        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6949        cx.spawn_in(window, async move |editor, cx| {
 6950            if use_debounce {
 6951                cx.background_executor()
 6952                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6953                    .await;
 6954            }
 6955            let match_task = cx.background_spawn(async move {
 6956                let buffer_ranges = multi_buffer_snapshot
 6957                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6958                    .into_iter()
 6959                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6960                let mut match_ranges = Vec::new();
 6961                let Ok(regex) = project::search::SearchQuery::text(
 6962                    query_text.clone(),
 6963                    false,
 6964                    false,
 6965                    false,
 6966                    Default::default(),
 6967                    Default::default(),
 6968                    false,
 6969                    None,
 6970                ) else {
 6971                    return Vec::default();
 6972                };
 6973                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6974                    match_ranges.extend(
 6975                        regex
 6976                            .search(buffer_snapshot, Some(search_range.clone()))
 6977                            .await
 6978                            .into_iter()
 6979                            .filter_map(|match_range| {
 6980                                let match_start = buffer_snapshot
 6981                                    .anchor_after(search_range.start + match_range.start);
 6982                                let match_end = buffer_snapshot
 6983                                    .anchor_before(search_range.start + match_range.end);
 6984                                let match_anchor_range = Anchor::range_in_buffer(
 6985                                    excerpt_id,
 6986                                    buffer_snapshot.remote_id(),
 6987                                    match_start..match_end,
 6988                                );
 6989                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6990                            }),
 6991                    );
 6992                }
 6993                match_ranges
 6994            });
 6995            let match_ranges = match_task.await;
 6996            editor
 6997                .update_in(cx, |editor, _, cx| {
 6998                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6999                    if !match_ranges.is_empty() {
 7000                        editor.highlight_background::<SelectedTextHighlight>(
 7001                            &match_ranges,
 7002                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7003                            cx,
 7004                        )
 7005                    }
 7006                })
 7007                .log_err();
 7008        })
 7009    }
 7010
 7011    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7012        struct NewlineFold;
 7013        let type_id = std::any::TypeId::of::<NewlineFold>();
 7014        if !self.mode.is_single_line() {
 7015            return;
 7016        }
 7017        let snapshot = self.snapshot(window, cx);
 7018        if snapshot.buffer_snapshot.max_point().row == 0 {
 7019            return;
 7020        }
 7021        let task = cx.background_spawn(async move {
 7022            let new_newlines = snapshot
 7023                .buffer_chars_at(0)
 7024                .filter_map(|(c, i)| {
 7025                    if c == '\n' {
 7026                        Some(
 7027                            snapshot.buffer_snapshot.anchor_after(i)
 7028                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7029                        )
 7030                    } else {
 7031                        None
 7032                    }
 7033                })
 7034                .collect::<Vec<_>>();
 7035            let existing_newlines = snapshot
 7036                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7037                .filter_map(|fold| {
 7038                    if fold.placeholder.type_tag == Some(type_id) {
 7039                        Some(fold.range.start..fold.range.end)
 7040                    } else {
 7041                        None
 7042                    }
 7043                })
 7044                .collect::<Vec<_>>();
 7045
 7046            (new_newlines, existing_newlines)
 7047        });
 7048        self.folding_newlines = cx.spawn(async move |this, cx| {
 7049            let (new_newlines, existing_newlines) = task.await;
 7050            if new_newlines == existing_newlines {
 7051                return;
 7052            }
 7053            let placeholder = FoldPlaceholder {
 7054                render: Arc::new(move |_, _, cx| {
 7055                    div()
 7056                        .bg(cx.theme().status().hint_background)
 7057                        .border_b_1()
 7058                        .size_full()
 7059                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7060                        .border_color(cx.theme().status().hint)
 7061                        .child("\\n")
 7062                        .into_any()
 7063                }),
 7064                constrain_width: false,
 7065                merge_adjacent: false,
 7066                type_tag: Some(type_id),
 7067            };
 7068            let creases = new_newlines
 7069                .into_iter()
 7070                .map(|range| Crease::simple(range, placeholder.clone()))
 7071                .collect();
 7072            this.update(cx, |this, cx| {
 7073                this.display_map.update(cx, |display_map, cx| {
 7074                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7075                    display_map.fold(creases, cx);
 7076                });
 7077            })
 7078            .ok();
 7079        });
 7080    }
 7081
 7082    fn refresh_selected_text_highlights(
 7083        &mut self,
 7084        on_buffer_edit: bool,
 7085        window: &mut Window,
 7086        cx: &mut Context<Editor>,
 7087    ) {
 7088        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7089        else {
 7090            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7091            self.quick_selection_highlight_task.take();
 7092            self.debounced_selection_highlight_task.take();
 7093            return;
 7094        };
 7095        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7096        if on_buffer_edit
 7097            || self
 7098                .quick_selection_highlight_task
 7099                .as_ref()
 7100                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7101        {
 7102            let multi_buffer_visible_start = self
 7103                .scroll_manager
 7104                .anchor()
 7105                .anchor
 7106                .to_point(&multi_buffer_snapshot);
 7107            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7108                multi_buffer_visible_start
 7109                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7110                Bias::Left,
 7111            );
 7112            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7113            self.quick_selection_highlight_task = Some((
 7114                query_range.clone(),
 7115                self.update_selection_occurrence_highlights(
 7116                    query_text.clone(),
 7117                    query_range.clone(),
 7118                    multi_buffer_visible_range,
 7119                    false,
 7120                    window,
 7121                    cx,
 7122                ),
 7123            ));
 7124        }
 7125        if on_buffer_edit
 7126            || self
 7127                .debounced_selection_highlight_task
 7128                .as_ref()
 7129                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7130        {
 7131            let multi_buffer_start = multi_buffer_snapshot
 7132                .anchor_before(0)
 7133                .to_point(&multi_buffer_snapshot);
 7134            let multi_buffer_end = multi_buffer_snapshot
 7135                .anchor_after(multi_buffer_snapshot.len())
 7136                .to_point(&multi_buffer_snapshot);
 7137            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7138            self.debounced_selection_highlight_task = Some((
 7139                query_range.clone(),
 7140                self.update_selection_occurrence_highlights(
 7141                    query_text,
 7142                    query_range,
 7143                    multi_buffer_full_range,
 7144                    true,
 7145                    window,
 7146                    cx,
 7147                ),
 7148            ));
 7149        }
 7150    }
 7151
 7152    pub fn refresh_edit_prediction(
 7153        &mut self,
 7154        debounce: bool,
 7155        user_requested: bool,
 7156        window: &mut Window,
 7157        cx: &mut Context<Self>,
 7158    ) -> Option<()> {
 7159        if DisableAiSettings::get_global(cx).disable_ai {
 7160            return None;
 7161        }
 7162
 7163        let provider = self.edit_prediction_provider()?;
 7164        let cursor = self.selections.newest_anchor().head();
 7165        let (buffer, cursor_buffer_position) =
 7166            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7167
 7168        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7169            self.discard_edit_prediction(false, cx);
 7170            return None;
 7171        }
 7172
 7173        self.update_visible_edit_prediction(window, cx);
 7174
 7175        if !user_requested
 7176            && (!self.should_show_edit_predictions()
 7177                || !self.is_focused(window)
 7178                || buffer.read(cx).is_empty())
 7179        {
 7180            self.discard_edit_prediction(false, cx);
 7181            return None;
 7182        }
 7183
 7184        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7185        Some(())
 7186    }
 7187
 7188    fn show_edit_predictions_in_menu(&self) -> bool {
 7189        match self.edit_prediction_settings {
 7190            EditPredictionSettings::Disabled => false,
 7191            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7192        }
 7193    }
 7194
 7195    pub fn edit_predictions_enabled(&self) -> bool {
 7196        match self.edit_prediction_settings {
 7197            EditPredictionSettings::Disabled => false,
 7198            EditPredictionSettings::Enabled { .. } => true,
 7199        }
 7200    }
 7201
 7202    fn edit_prediction_requires_modifier(&self) -> bool {
 7203        match self.edit_prediction_settings {
 7204            EditPredictionSettings::Disabled => false,
 7205            EditPredictionSettings::Enabled {
 7206                preview_requires_modifier,
 7207                ..
 7208            } => preview_requires_modifier,
 7209        }
 7210    }
 7211
 7212    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7213        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7214            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7215            self.discard_edit_prediction(false, cx);
 7216        } else {
 7217            let selection = self.selections.newest_anchor();
 7218            let cursor = selection.head();
 7219
 7220            if let Some((buffer, cursor_buffer_position)) =
 7221                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7222            {
 7223                self.edit_prediction_settings =
 7224                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7225            }
 7226        }
 7227    }
 7228
 7229    fn edit_prediction_settings_at_position(
 7230        &self,
 7231        buffer: &Entity<Buffer>,
 7232        buffer_position: language::Anchor,
 7233        cx: &App,
 7234    ) -> EditPredictionSettings {
 7235        if !self.mode.is_full()
 7236            || !self.show_edit_predictions_override.unwrap_or(true)
 7237            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7238        {
 7239            return EditPredictionSettings::Disabled;
 7240        }
 7241
 7242        let buffer = buffer.read(cx);
 7243
 7244        let file = buffer.file();
 7245
 7246        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7247            return EditPredictionSettings::Disabled;
 7248        };
 7249
 7250        let by_provider = matches!(
 7251            self.menu_edit_predictions_policy,
 7252            MenuEditPredictionsPolicy::ByProvider
 7253        );
 7254
 7255        let show_in_menu = by_provider
 7256            && self
 7257                .edit_prediction_provider
 7258                .as_ref()
 7259                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7260
 7261        let preview_requires_modifier =
 7262            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7263
 7264        EditPredictionSettings::Enabled {
 7265            show_in_menu,
 7266            preview_requires_modifier,
 7267        }
 7268    }
 7269
 7270    fn should_show_edit_predictions(&self) -> bool {
 7271        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7272    }
 7273
 7274    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7275        matches!(
 7276            self.edit_prediction_preview,
 7277            EditPredictionPreview::Active { .. }
 7278        )
 7279    }
 7280
 7281    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7282        let cursor = self.selections.newest_anchor().head();
 7283        if let Some((buffer, cursor_position)) =
 7284            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7285        {
 7286            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7287        } else {
 7288            false
 7289        }
 7290    }
 7291
 7292    pub fn supports_minimap(&self, cx: &App) -> bool {
 7293        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7294    }
 7295
 7296    fn edit_predictions_enabled_in_buffer(
 7297        &self,
 7298        buffer: &Entity<Buffer>,
 7299        buffer_position: language::Anchor,
 7300        cx: &App,
 7301    ) -> bool {
 7302        maybe!({
 7303            if self.read_only(cx) {
 7304                return Some(false);
 7305            }
 7306            let provider = self.edit_prediction_provider()?;
 7307            if !provider.is_enabled(buffer, buffer_position, cx) {
 7308                return Some(false);
 7309            }
 7310            let buffer = buffer.read(cx);
 7311            let Some(file) = buffer.file() else {
 7312                return Some(true);
 7313            };
 7314            let settings = all_language_settings(Some(file), cx);
 7315            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7316        })
 7317        .unwrap_or(false)
 7318    }
 7319
 7320    fn cycle_edit_prediction(
 7321        &mut self,
 7322        direction: Direction,
 7323        window: &mut Window,
 7324        cx: &mut Context<Self>,
 7325    ) -> Option<()> {
 7326        let provider = self.edit_prediction_provider()?;
 7327        let cursor = self.selections.newest_anchor().head();
 7328        let (buffer, cursor_buffer_position) =
 7329            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7330        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7331            return None;
 7332        }
 7333
 7334        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7335        self.update_visible_edit_prediction(window, cx);
 7336
 7337        Some(())
 7338    }
 7339
 7340    pub fn show_edit_prediction(
 7341        &mut self,
 7342        _: &ShowEditPrediction,
 7343        window: &mut Window,
 7344        cx: &mut Context<Self>,
 7345    ) {
 7346        if !self.has_active_edit_prediction() {
 7347            self.refresh_edit_prediction(false, true, window, cx);
 7348            return;
 7349        }
 7350
 7351        self.update_visible_edit_prediction(window, cx);
 7352    }
 7353
 7354    pub fn display_cursor_names(
 7355        &mut self,
 7356        _: &DisplayCursorNames,
 7357        window: &mut Window,
 7358        cx: &mut Context<Self>,
 7359    ) {
 7360        self.show_cursor_names(window, cx);
 7361    }
 7362
 7363    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7364        self.show_cursor_names = true;
 7365        cx.notify();
 7366        cx.spawn_in(window, async move |this, cx| {
 7367            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7368            this.update(cx, |this, cx| {
 7369                this.show_cursor_names = false;
 7370                cx.notify()
 7371            })
 7372            .ok()
 7373        })
 7374        .detach();
 7375    }
 7376
 7377    pub fn next_edit_prediction(
 7378        &mut self,
 7379        _: &NextEditPrediction,
 7380        window: &mut Window,
 7381        cx: &mut Context<Self>,
 7382    ) {
 7383        if self.has_active_edit_prediction() {
 7384            self.cycle_edit_prediction(Direction::Next, window, cx);
 7385        } else {
 7386            let is_copilot_disabled = self
 7387                .refresh_edit_prediction(false, true, window, cx)
 7388                .is_none();
 7389            if is_copilot_disabled {
 7390                cx.propagate();
 7391            }
 7392        }
 7393    }
 7394
 7395    pub fn previous_edit_prediction(
 7396        &mut self,
 7397        _: &PreviousEditPrediction,
 7398        window: &mut Window,
 7399        cx: &mut Context<Self>,
 7400    ) {
 7401        if self.has_active_edit_prediction() {
 7402            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7403        } else {
 7404            let is_copilot_disabled = self
 7405                .refresh_edit_prediction(false, true, window, cx)
 7406                .is_none();
 7407            if is_copilot_disabled {
 7408                cx.propagate();
 7409            }
 7410        }
 7411    }
 7412
 7413    pub fn accept_edit_prediction(
 7414        &mut self,
 7415        _: &AcceptEditPrediction,
 7416        window: &mut Window,
 7417        cx: &mut Context<Self>,
 7418    ) {
 7419        if self.show_edit_predictions_in_menu() {
 7420            self.hide_context_menu(window, cx);
 7421        }
 7422
 7423        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7424            return;
 7425        };
 7426
 7427        match &active_edit_prediction.completion {
 7428            EditPrediction::MoveWithin { target, .. } => {
 7429                let target = *target;
 7430
 7431                if let Some(position_map) = &self.last_position_map {
 7432                    if position_map
 7433                        .visible_row_range
 7434                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7435                        || !self.edit_prediction_requires_modifier()
 7436                    {
 7437                        self.unfold_ranges(&[target..target], true, false, cx);
 7438                        // Note that this is also done in vim's handler of the Tab action.
 7439                        self.change_selections(
 7440                            SelectionEffects::scroll(Autoscroll::newest()),
 7441                            window,
 7442                            cx,
 7443                            |selections| {
 7444                                selections.select_anchor_ranges([target..target]);
 7445                            },
 7446                        );
 7447                        self.clear_row_highlights::<EditPredictionPreview>();
 7448
 7449                        self.edit_prediction_preview
 7450                            .set_previous_scroll_position(None);
 7451                    } else {
 7452                        self.edit_prediction_preview
 7453                            .set_previous_scroll_position(Some(
 7454                                position_map.snapshot.scroll_anchor,
 7455                            ));
 7456
 7457                        self.highlight_rows::<EditPredictionPreview>(
 7458                            target..target,
 7459                            cx.theme().colors().editor_highlighted_line_background,
 7460                            RowHighlightOptions {
 7461                                autoscroll: true,
 7462                                ..Default::default()
 7463                            },
 7464                            cx,
 7465                        );
 7466                        self.request_autoscroll(Autoscroll::fit(), cx);
 7467                    }
 7468                }
 7469            }
 7470            EditPrediction::MoveOutside { snapshot, target } => {
 7471                if let Some(workspace) = self.workspace() {
 7472                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7473                        .detach_and_log_err(cx);
 7474                }
 7475            }
 7476            EditPrediction::Edit { edits, .. } => {
 7477                self.report_edit_prediction_event(
 7478                    active_edit_prediction.completion_id.clone(),
 7479                    true,
 7480                    cx,
 7481                );
 7482
 7483                if let Some(provider) = self.edit_prediction_provider() {
 7484                    provider.accept(cx);
 7485                }
 7486
 7487                // Store the transaction ID and selections before applying the edit
 7488                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7489
 7490                let snapshot = self.buffer.read(cx).snapshot(cx);
 7491                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7492
 7493                self.buffer.update(cx, |buffer, cx| {
 7494                    buffer.edit(edits.iter().cloned(), None, cx)
 7495                });
 7496
 7497                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7498                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7499                });
 7500
 7501                let selections = self.selections.disjoint_anchors_arc();
 7502                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7503                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7504                    if has_new_transaction {
 7505                        self.selection_history
 7506                            .insert_transaction(transaction_id_now, selections);
 7507                    }
 7508                }
 7509
 7510                self.update_visible_edit_prediction(window, cx);
 7511                if self.active_edit_prediction.is_none() {
 7512                    self.refresh_edit_prediction(true, true, window, cx);
 7513                }
 7514
 7515                cx.notify();
 7516            }
 7517        }
 7518
 7519        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7520    }
 7521
 7522    pub fn accept_partial_edit_prediction(
 7523        &mut self,
 7524        _: &AcceptPartialEditPrediction,
 7525        window: &mut Window,
 7526        cx: &mut Context<Self>,
 7527    ) {
 7528        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7529            return;
 7530        };
 7531        if self.selections.count() != 1 {
 7532            return;
 7533        }
 7534
 7535        match &active_edit_prediction.completion {
 7536            EditPrediction::MoveWithin { target, .. } => {
 7537                let target = *target;
 7538                self.change_selections(
 7539                    SelectionEffects::scroll(Autoscroll::newest()),
 7540                    window,
 7541                    cx,
 7542                    |selections| {
 7543                        selections.select_anchor_ranges([target..target]);
 7544                    },
 7545                );
 7546            }
 7547            EditPrediction::MoveOutside { snapshot, target } => {
 7548                if let Some(workspace) = self.workspace() {
 7549                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7550                        .detach_and_log_err(cx);
 7551                }
 7552            }
 7553            EditPrediction::Edit { edits, .. } => {
 7554                self.report_edit_prediction_event(
 7555                    active_edit_prediction.completion_id.clone(),
 7556                    true,
 7557                    cx,
 7558                );
 7559
 7560                // Find an insertion that starts at the cursor position.
 7561                let snapshot = self.buffer.read(cx).snapshot(cx);
 7562                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7563                let insertion = edits.iter().find_map(|(range, text)| {
 7564                    let range = range.to_offset(&snapshot);
 7565                    if range.is_empty() && range.start == cursor_offset {
 7566                        Some(text)
 7567                    } else {
 7568                        None
 7569                    }
 7570                });
 7571
 7572                if let Some(text) = insertion {
 7573                    let mut partial_completion = text
 7574                        .chars()
 7575                        .by_ref()
 7576                        .take_while(|c| c.is_alphabetic())
 7577                        .collect::<String>();
 7578                    if partial_completion.is_empty() {
 7579                        partial_completion = text
 7580                            .chars()
 7581                            .by_ref()
 7582                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7583                            .collect::<String>();
 7584                    }
 7585
 7586                    cx.emit(EditorEvent::InputHandled {
 7587                        utf16_range_to_replace: None,
 7588                        text: partial_completion.clone().into(),
 7589                    });
 7590
 7591                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7592
 7593                    self.refresh_edit_prediction(true, true, window, cx);
 7594                    cx.notify();
 7595                } else {
 7596                    self.accept_edit_prediction(&Default::default(), window, cx);
 7597                }
 7598            }
 7599        }
 7600    }
 7601
 7602    fn discard_edit_prediction(
 7603        &mut self,
 7604        should_report_edit_prediction_event: bool,
 7605        cx: &mut Context<Self>,
 7606    ) -> bool {
 7607        if should_report_edit_prediction_event {
 7608            let completion_id = self
 7609                .active_edit_prediction
 7610                .as_ref()
 7611                .and_then(|active_completion| active_completion.completion_id.clone());
 7612
 7613            self.report_edit_prediction_event(completion_id, false, cx);
 7614        }
 7615
 7616        if let Some(provider) = self.edit_prediction_provider() {
 7617            provider.discard(cx);
 7618        }
 7619
 7620        self.take_active_edit_prediction(cx)
 7621    }
 7622
 7623    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7624        let Some(provider) = self.edit_prediction_provider() else {
 7625            return;
 7626        };
 7627
 7628        let Some((_, buffer, _)) = self
 7629            .buffer
 7630            .read(cx)
 7631            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7632        else {
 7633            return;
 7634        };
 7635
 7636        let extension = buffer
 7637            .read(cx)
 7638            .file()
 7639            .and_then(|file| Some(file.path().extension()?.to_string()));
 7640
 7641        let event_type = match accepted {
 7642            true => "Edit Prediction Accepted",
 7643            false => "Edit Prediction Discarded",
 7644        };
 7645        telemetry::event!(
 7646            event_type,
 7647            provider = provider.name(),
 7648            prediction_id = id,
 7649            suggestion_accepted = accepted,
 7650            file_extension = extension,
 7651        );
 7652    }
 7653
 7654    fn open_editor_at_anchor(
 7655        snapshot: &language::BufferSnapshot,
 7656        target: language::Anchor,
 7657        workspace: &Entity<Workspace>,
 7658        window: &mut Window,
 7659        cx: &mut App,
 7660    ) -> Task<Result<()>> {
 7661        workspace.update(cx, |workspace, cx| {
 7662            let path = snapshot.file().map(|file| file.full_path(cx));
 7663            let Some(path) =
 7664                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7665            else {
 7666                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7667            };
 7668            let target = text::ToPoint::to_point(&target, snapshot);
 7669            let item = workspace.open_path(path, None, true, window, cx);
 7670            window.spawn(cx, async move |cx| {
 7671                let Some(editor) = item.await?.downcast::<Editor>() else {
 7672                    return Ok(());
 7673                };
 7674                editor
 7675                    .update_in(cx, |editor, window, cx| {
 7676                        editor.go_to_singleton_buffer_point(target, window, cx);
 7677                    })
 7678                    .ok();
 7679                anyhow::Ok(())
 7680            })
 7681        })
 7682    }
 7683
 7684    pub fn has_active_edit_prediction(&self) -> bool {
 7685        self.active_edit_prediction.is_some()
 7686    }
 7687
 7688    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7689        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7690            return false;
 7691        };
 7692
 7693        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7694        self.clear_highlights::<EditPredictionHighlight>(cx);
 7695        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7696        true
 7697    }
 7698
 7699    /// Returns true when we're displaying the edit prediction popover below the cursor
 7700    /// like we are not previewing and the LSP autocomplete menu is visible
 7701    /// or we are in `when_holding_modifier` mode.
 7702    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7703        if self.edit_prediction_preview_is_active()
 7704            || !self.show_edit_predictions_in_menu()
 7705            || !self.edit_predictions_enabled()
 7706        {
 7707            return false;
 7708        }
 7709
 7710        if self.has_visible_completions_menu() {
 7711            return true;
 7712        }
 7713
 7714        has_completion && self.edit_prediction_requires_modifier()
 7715    }
 7716
 7717    fn handle_modifiers_changed(
 7718        &mut self,
 7719        modifiers: Modifiers,
 7720        position_map: &PositionMap,
 7721        window: &mut Window,
 7722        cx: &mut Context<Self>,
 7723    ) {
 7724        if self.show_edit_predictions_in_menu() {
 7725            self.update_edit_prediction_preview(&modifiers, window, cx);
 7726        }
 7727
 7728        self.update_selection_mode(&modifiers, position_map, window, cx);
 7729
 7730        let mouse_position = window.mouse_position();
 7731        if !position_map.text_hitbox.is_hovered(window) {
 7732            return;
 7733        }
 7734
 7735        self.update_hovered_link(
 7736            position_map.point_for_position(mouse_position),
 7737            &position_map.snapshot,
 7738            modifiers,
 7739            window,
 7740            cx,
 7741        )
 7742    }
 7743
 7744    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7745        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7746        if invert {
 7747            match multi_cursor_setting {
 7748                MultiCursorModifier::Alt => modifiers.alt,
 7749                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7750            }
 7751        } else {
 7752            match multi_cursor_setting {
 7753                MultiCursorModifier::Alt => modifiers.secondary(),
 7754                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7755            }
 7756        }
 7757    }
 7758
 7759    fn columnar_selection_mode(
 7760        modifiers: &Modifiers,
 7761        cx: &mut Context<Self>,
 7762    ) -> Option<ColumnarMode> {
 7763        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7764            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7765                Some(ColumnarMode::FromMouse)
 7766            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7767                Some(ColumnarMode::FromSelection)
 7768            } else {
 7769                None
 7770            }
 7771        } else {
 7772            None
 7773        }
 7774    }
 7775
 7776    fn update_selection_mode(
 7777        &mut self,
 7778        modifiers: &Modifiers,
 7779        position_map: &PositionMap,
 7780        window: &mut Window,
 7781        cx: &mut Context<Self>,
 7782    ) {
 7783        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7784            return;
 7785        };
 7786        if self.selections.pending_anchor().is_none() {
 7787            return;
 7788        }
 7789
 7790        let mouse_position = window.mouse_position();
 7791        let point_for_position = position_map.point_for_position(mouse_position);
 7792        let position = point_for_position.previous_valid;
 7793
 7794        self.select(
 7795            SelectPhase::BeginColumnar {
 7796                position,
 7797                reset: false,
 7798                mode,
 7799                goal_column: point_for_position.exact_unclipped.column(),
 7800            },
 7801            window,
 7802            cx,
 7803        );
 7804    }
 7805
 7806    fn update_edit_prediction_preview(
 7807        &mut self,
 7808        modifiers: &Modifiers,
 7809        window: &mut Window,
 7810        cx: &mut Context<Self>,
 7811    ) {
 7812        let mut modifiers_held = false;
 7813        if let Some(accept_keystroke) = self
 7814            .accept_edit_prediction_keybind(false, window, cx)
 7815            .keystroke()
 7816        {
 7817            modifiers_held = modifiers_held
 7818                || (accept_keystroke.modifiers() == modifiers
 7819                    && accept_keystroke.modifiers().modified());
 7820        };
 7821        if let Some(accept_partial_keystroke) = self
 7822            .accept_edit_prediction_keybind(true, window, cx)
 7823            .keystroke()
 7824        {
 7825            modifiers_held = modifiers_held
 7826                || (accept_partial_keystroke.modifiers() == modifiers
 7827                    && accept_partial_keystroke.modifiers().modified());
 7828        }
 7829
 7830        if modifiers_held {
 7831            if matches!(
 7832                self.edit_prediction_preview,
 7833                EditPredictionPreview::Inactive { .. }
 7834            ) {
 7835                self.edit_prediction_preview = EditPredictionPreview::Active {
 7836                    previous_scroll_position: None,
 7837                    since: Instant::now(),
 7838                };
 7839
 7840                self.update_visible_edit_prediction(window, cx);
 7841                cx.notify();
 7842            }
 7843        } else if let EditPredictionPreview::Active {
 7844            previous_scroll_position,
 7845            since,
 7846        } = self.edit_prediction_preview
 7847        {
 7848            if let (Some(previous_scroll_position), Some(position_map)) =
 7849                (previous_scroll_position, self.last_position_map.as_ref())
 7850            {
 7851                self.set_scroll_position(
 7852                    previous_scroll_position
 7853                        .scroll_position(&position_map.snapshot.display_snapshot),
 7854                    window,
 7855                    cx,
 7856                );
 7857            }
 7858
 7859            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7860                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7861            };
 7862            self.clear_row_highlights::<EditPredictionPreview>();
 7863            self.update_visible_edit_prediction(window, cx);
 7864            cx.notify();
 7865        }
 7866    }
 7867
 7868    fn update_visible_edit_prediction(
 7869        &mut self,
 7870        _window: &mut Window,
 7871        cx: &mut Context<Self>,
 7872    ) -> Option<()> {
 7873        if DisableAiSettings::get_global(cx).disable_ai {
 7874            return None;
 7875        }
 7876
 7877        if self.ime_transaction.is_some() {
 7878            self.discard_edit_prediction(false, cx);
 7879            return None;
 7880        }
 7881
 7882        let selection = self.selections.newest_anchor();
 7883        let cursor = selection.head();
 7884        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7885        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7886        let excerpt_id = cursor.excerpt_id;
 7887
 7888        let show_in_menu = self.show_edit_predictions_in_menu();
 7889        let completions_menu_has_precedence = !show_in_menu
 7890            && (self.context_menu.borrow().is_some()
 7891                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7892
 7893        if completions_menu_has_precedence
 7894            || !offset_selection.is_empty()
 7895            || self
 7896                .active_edit_prediction
 7897                .as_ref()
 7898                .is_some_and(|completion| {
 7899                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7900                        return false;
 7901                    };
 7902                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7903                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7904                    !invalidation_range.contains(&offset_selection.head())
 7905                })
 7906        {
 7907            self.discard_edit_prediction(false, cx);
 7908            return None;
 7909        }
 7910
 7911        self.take_active_edit_prediction(cx);
 7912        let Some(provider) = self.edit_prediction_provider() else {
 7913            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7914            return None;
 7915        };
 7916
 7917        let (buffer, cursor_buffer_position) =
 7918            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7919
 7920        self.edit_prediction_settings =
 7921            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7922
 7923        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7924
 7925        if self.edit_prediction_indent_conflict {
 7926            let cursor_point = cursor.to_point(&multibuffer);
 7927
 7928            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7929
 7930            if let Some((_, indent)) = indents.iter().next()
 7931                && indent.len == cursor_point.column
 7932            {
 7933                self.edit_prediction_indent_conflict = false;
 7934            }
 7935        }
 7936
 7937        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7938
 7939        let (completion_id, edits, edit_preview) = match edit_prediction {
 7940            edit_prediction::EditPrediction::Local {
 7941                id,
 7942                edits,
 7943                edit_preview,
 7944            } => (id, edits, edit_preview),
 7945            edit_prediction::EditPrediction::Jump {
 7946                id,
 7947                snapshot,
 7948                target,
 7949            } => {
 7950                self.stale_edit_prediction_in_menu = None;
 7951                self.active_edit_prediction = Some(EditPredictionState {
 7952                    inlay_ids: vec![],
 7953                    completion: EditPrediction::MoveOutside { snapshot, target },
 7954                    completion_id: id,
 7955                    invalidation_range: None,
 7956                });
 7957                cx.notify();
 7958                return Some(());
 7959            }
 7960        };
 7961
 7962        let edits = edits
 7963            .into_iter()
 7964            .flat_map(|(range, new_text)| {
 7965                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7966                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7967                Some((start..end, new_text))
 7968            })
 7969            .collect::<Vec<_>>();
 7970        if edits.is_empty() {
 7971            return None;
 7972        }
 7973
 7974        let first_edit_start = edits.first().unwrap().0.start;
 7975        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7976        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7977
 7978        let last_edit_end = edits.last().unwrap().0.end;
 7979        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7980        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7981
 7982        let cursor_row = cursor.to_point(&multibuffer).row;
 7983
 7984        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7985
 7986        let mut inlay_ids = Vec::new();
 7987        let invalidation_row_range;
 7988        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7989            Some(cursor_row..edit_end_row)
 7990        } else if cursor_row > edit_end_row {
 7991            Some(edit_start_row..cursor_row)
 7992        } else {
 7993            None
 7994        };
 7995        let supports_jump = self
 7996            .edit_prediction_provider
 7997            .as_ref()
 7998            .map(|provider| provider.provider.supports_jump_to_edit())
 7999            .unwrap_or(true);
 8000
 8001        let is_move = supports_jump
 8002            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8003        let completion = if is_move {
 8004            invalidation_row_range =
 8005                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8006            let target = first_edit_start;
 8007            EditPrediction::MoveWithin { target, snapshot }
 8008        } else {
 8009            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8010                && !self.edit_predictions_hidden_for_vim_mode;
 8011
 8012            if show_completions_in_buffer {
 8013                if edits
 8014                    .iter()
 8015                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8016                {
 8017                    let mut inlays = Vec::new();
 8018                    for (range, new_text) in &edits {
 8019                        let inlay = Inlay::edit_prediction(
 8020                            post_inc(&mut self.next_inlay_id),
 8021                            range.start,
 8022                            new_text.as_str(),
 8023                        );
 8024                        inlay_ids.push(inlay.id);
 8025                        inlays.push(inlay);
 8026                    }
 8027
 8028                    self.splice_inlays(&[], inlays, cx);
 8029                } else {
 8030                    let background_color = cx.theme().status().deleted_background;
 8031                    self.highlight_text::<EditPredictionHighlight>(
 8032                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8033                        HighlightStyle {
 8034                            background_color: Some(background_color),
 8035                            ..Default::default()
 8036                        },
 8037                        cx,
 8038                    );
 8039                }
 8040            }
 8041
 8042            invalidation_row_range = edit_start_row..edit_end_row;
 8043
 8044            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8045                if provider.show_tab_accept_marker() {
 8046                    EditDisplayMode::TabAccept
 8047                } else {
 8048                    EditDisplayMode::Inline
 8049                }
 8050            } else {
 8051                EditDisplayMode::DiffPopover
 8052            };
 8053
 8054            EditPrediction::Edit {
 8055                edits,
 8056                edit_preview,
 8057                display_mode,
 8058                snapshot,
 8059            }
 8060        };
 8061
 8062        let invalidation_range = multibuffer
 8063            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8064            ..multibuffer.anchor_after(Point::new(
 8065                invalidation_row_range.end,
 8066                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8067            ));
 8068
 8069        self.stale_edit_prediction_in_menu = None;
 8070        self.active_edit_prediction = Some(EditPredictionState {
 8071            inlay_ids,
 8072            completion,
 8073            completion_id,
 8074            invalidation_range: Some(invalidation_range),
 8075        });
 8076
 8077        cx.notify();
 8078
 8079        Some(())
 8080    }
 8081
 8082    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8083        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8084    }
 8085
 8086    fn clear_tasks(&mut self) {
 8087        self.tasks.clear()
 8088    }
 8089
 8090    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8091        if self.tasks.insert(key, value).is_some() {
 8092            // This case should hopefully be rare, but just in case...
 8093            log::error!(
 8094                "multiple different run targets found on a single line, only the last target will be rendered"
 8095            )
 8096        }
 8097    }
 8098
 8099    /// Get all display points of breakpoints that will be rendered within editor
 8100    ///
 8101    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8102    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8103    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8104    fn active_breakpoints(
 8105        &self,
 8106        range: Range<DisplayRow>,
 8107        window: &mut Window,
 8108        cx: &mut Context<Self>,
 8109    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8110        let mut breakpoint_display_points = HashMap::default();
 8111
 8112        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8113            return breakpoint_display_points;
 8114        };
 8115
 8116        let snapshot = self.snapshot(window, cx);
 8117
 8118        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8119        let Some(project) = self.project() else {
 8120            return breakpoint_display_points;
 8121        };
 8122
 8123        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8124            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8125
 8126        for (buffer_snapshot, range, excerpt_id) in
 8127            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8128        {
 8129            let Some(buffer) = project
 8130                .read(cx)
 8131                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8132            else {
 8133                continue;
 8134            };
 8135            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8136                &buffer,
 8137                Some(
 8138                    buffer_snapshot.anchor_before(range.start)
 8139                        ..buffer_snapshot.anchor_after(range.end),
 8140                ),
 8141                buffer_snapshot,
 8142                cx,
 8143            );
 8144            for (breakpoint, state) in breakpoints {
 8145                let multi_buffer_anchor =
 8146                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8147                let position = multi_buffer_anchor
 8148                    .to_point(multi_buffer_snapshot)
 8149                    .to_display_point(&snapshot);
 8150
 8151                breakpoint_display_points.insert(
 8152                    position.row(),
 8153                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8154                );
 8155            }
 8156        }
 8157
 8158        breakpoint_display_points
 8159    }
 8160
 8161    fn breakpoint_context_menu(
 8162        &self,
 8163        anchor: Anchor,
 8164        window: &mut Window,
 8165        cx: &mut Context<Self>,
 8166    ) -> Entity<ui::ContextMenu> {
 8167        let weak_editor = cx.weak_entity();
 8168        let focus_handle = self.focus_handle(cx);
 8169
 8170        let row = self
 8171            .buffer
 8172            .read(cx)
 8173            .snapshot(cx)
 8174            .summary_for_anchor::<Point>(&anchor)
 8175            .row;
 8176
 8177        let breakpoint = self
 8178            .breakpoint_at_row(row, window, cx)
 8179            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8180
 8181        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8182            "Edit Log Breakpoint"
 8183        } else {
 8184            "Set Log Breakpoint"
 8185        };
 8186
 8187        let condition_breakpoint_msg = if breakpoint
 8188            .as_ref()
 8189            .is_some_and(|bp| bp.1.condition.is_some())
 8190        {
 8191            "Edit Condition Breakpoint"
 8192        } else {
 8193            "Set Condition Breakpoint"
 8194        };
 8195
 8196        let hit_condition_breakpoint_msg = if breakpoint
 8197            .as_ref()
 8198            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8199        {
 8200            "Edit Hit Condition Breakpoint"
 8201        } else {
 8202            "Set Hit Condition Breakpoint"
 8203        };
 8204
 8205        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8206            "Unset Breakpoint"
 8207        } else {
 8208            "Set Breakpoint"
 8209        };
 8210
 8211        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8212
 8213        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8214            BreakpointState::Enabled => Some("Disable"),
 8215            BreakpointState::Disabled => Some("Enable"),
 8216        });
 8217
 8218        let (anchor, breakpoint) =
 8219            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8220
 8221        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8222            menu.on_blur_subscription(Subscription::new(|| {}))
 8223                .context(focus_handle)
 8224                .when(run_to_cursor, |this| {
 8225                    let weak_editor = weak_editor.clone();
 8226                    this.entry("Run to cursor", None, move |window, cx| {
 8227                        weak_editor
 8228                            .update(cx, |editor, cx| {
 8229                                editor.change_selections(
 8230                                    SelectionEffects::no_scroll(),
 8231                                    window,
 8232                                    cx,
 8233                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8234                                );
 8235                            })
 8236                            .ok();
 8237
 8238                        window.dispatch_action(Box::new(RunToCursor), cx);
 8239                    })
 8240                    .separator()
 8241                })
 8242                .when_some(toggle_state_msg, |this, msg| {
 8243                    this.entry(msg, None, {
 8244                        let weak_editor = weak_editor.clone();
 8245                        let breakpoint = breakpoint.clone();
 8246                        move |_window, cx| {
 8247                            weak_editor
 8248                                .update(cx, |this, cx| {
 8249                                    this.edit_breakpoint_at_anchor(
 8250                                        anchor,
 8251                                        breakpoint.as_ref().clone(),
 8252                                        BreakpointEditAction::InvertState,
 8253                                        cx,
 8254                                    );
 8255                                })
 8256                                .log_err();
 8257                        }
 8258                    })
 8259                })
 8260                .entry(set_breakpoint_msg, None, {
 8261                    let weak_editor = weak_editor.clone();
 8262                    let breakpoint = breakpoint.clone();
 8263                    move |_window, cx| {
 8264                        weak_editor
 8265                            .update(cx, |this, cx| {
 8266                                this.edit_breakpoint_at_anchor(
 8267                                    anchor,
 8268                                    breakpoint.as_ref().clone(),
 8269                                    BreakpointEditAction::Toggle,
 8270                                    cx,
 8271                                );
 8272                            })
 8273                            .log_err();
 8274                    }
 8275                })
 8276                .entry(log_breakpoint_msg, None, {
 8277                    let breakpoint = breakpoint.clone();
 8278                    let weak_editor = weak_editor.clone();
 8279                    move |window, cx| {
 8280                        weak_editor
 8281                            .update(cx, |this, cx| {
 8282                                this.add_edit_breakpoint_block(
 8283                                    anchor,
 8284                                    breakpoint.as_ref(),
 8285                                    BreakpointPromptEditAction::Log,
 8286                                    window,
 8287                                    cx,
 8288                                );
 8289                            })
 8290                            .log_err();
 8291                    }
 8292                })
 8293                .entry(condition_breakpoint_msg, None, {
 8294                    let breakpoint = breakpoint.clone();
 8295                    let weak_editor = weak_editor.clone();
 8296                    move |window, cx| {
 8297                        weak_editor
 8298                            .update(cx, |this, cx| {
 8299                                this.add_edit_breakpoint_block(
 8300                                    anchor,
 8301                                    breakpoint.as_ref(),
 8302                                    BreakpointPromptEditAction::Condition,
 8303                                    window,
 8304                                    cx,
 8305                                );
 8306                            })
 8307                            .log_err();
 8308                    }
 8309                })
 8310                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8311                    weak_editor
 8312                        .update(cx, |this, cx| {
 8313                            this.add_edit_breakpoint_block(
 8314                                anchor,
 8315                                breakpoint.as_ref(),
 8316                                BreakpointPromptEditAction::HitCondition,
 8317                                window,
 8318                                cx,
 8319                            );
 8320                        })
 8321                        .log_err();
 8322                })
 8323        })
 8324    }
 8325
 8326    fn render_breakpoint(
 8327        &self,
 8328        position: Anchor,
 8329        row: DisplayRow,
 8330        breakpoint: &Breakpoint,
 8331        state: Option<BreakpointSessionState>,
 8332        cx: &mut Context<Self>,
 8333    ) -> IconButton {
 8334        let is_rejected = state.is_some_and(|s| !s.verified);
 8335        // Is it a breakpoint that shows up when hovering over gutter?
 8336        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8337            (false, false),
 8338            |PhantomBreakpointIndicator {
 8339                 is_active,
 8340                 display_row,
 8341                 collides_with_existing_breakpoint,
 8342             }| {
 8343                (
 8344                    is_active && display_row == row,
 8345                    collides_with_existing_breakpoint,
 8346                )
 8347            },
 8348        );
 8349
 8350        let (color, icon) = {
 8351            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8352                (false, false) => ui::IconName::DebugBreakpoint,
 8353                (true, false) => ui::IconName::DebugLogBreakpoint,
 8354                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8355                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8356            };
 8357
 8358            let color = if is_phantom {
 8359                Color::Hint
 8360            } else if is_rejected {
 8361                Color::Disabled
 8362            } else {
 8363                Color::Debugger
 8364            };
 8365
 8366            (color, icon)
 8367        };
 8368
 8369        let breakpoint = Arc::from(breakpoint.clone());
 8370
 8371        let alt_as_text = gpui::Keystroke {
 8372            modifiers: Modifiers::secondary_key(),
 8373            ..Default::default()
 8374        };
 8375        let primary_action_text = if breakpoint.is_disabled() {
 8376            "Enable breakpoint"
 8377        } else if is_phantom && !collides_with_existing {
 8378            "Set breakpoint"
 8379        } else {
 8380            "Unset breakpoint"
 8381        };
 8382        let focus_handle = self.focus_handle.clone();
 8383
 8384        let meta = if is_rejected {
 8385            SharedString::from("No executable code is associated with this line.")
 8386        } else if collides_with_existing && !breakpoint.is_disabled() {
 8387            SharedString::from(format!(
 8388                "{alt_as_text}-click to disable,\nright-click for more options."
 8389            ))
 8390        } else {
 8391            SharedString::from("Right-click for more options.")
 8392        };
 8393        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8394            .icon_size(IconSize::XSmall)
 8395            .size(ui::ButtonSize::None)
 8396            .when(is_rejected, |this| {
 8397                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8398            })
 8399            .icon_color(color)
 8400            .style(ButtonStyle::Transparent)
 8401            .on_click(cx.listener({
 8402                move |editor, event: &ClickEvent, window, cx| {
 8403                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8404                        BreakpointEditAction::InvertState
 8405                    } else {
 8406                        BreakpointEditAction::Toggle
 8407                    };
 8408
 8409                    window.focus(&editor.focus_handle(cx));
 8410                    editor.edit_breakpoint_at_anchor(
 8411                        position,
 8412                        breakpoint.as_ref().clone(),
 8413                        edit_action,
 8414                        cx,
 8415                    );
 8416                }
 8417            }))
 8418            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8419                editor.set_breakpoint_context_menu(
 8420                    row,
 8421                    Some(position),
 8422                    event.position(),
 8423                    window,
 8424                    cx,
 8425                );
 8426            }))
 8427            .tooltip(move |window, cx| {
 8428                Tooltip::with_meta_in(
 8429                    primary_action_text,
 8430                    Some(&ToggleBreakpoint),
 8431                    meta.clone(),
 8432                    &focus_handle,
 8433                    window,
 8434                    cx,
 8435                )
 8436            })
 8437    }
 8438
 8439    fn build_tasks_context(
 8440        project: &Entity<Project>,
 8441        buffer: &Entity<Buffer>,
 8442        buffer_row: u32,
 8443        tasks: &Arc<RunnableTasks>,
 8444        cx: &mut Context<Self>,
 8445    ) -> Task<Option<task::TaskContext>> {
 8446        let position = Point::new(buffer_row, tasks.column);
 8447        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8448        let location = Location {
 8449            buffer: buffer.clone(),
 8450            range: range_start..range_start,
 8451        };
 8452        // Fill in the environmental variables from the tree-sitter captures
 8453        let mut captured_task_variables = TaskVariables::default();
 8454        for (capture_name, value) in tasks.extra_variables.clone() {
 8455            captured_task_variables.insert(
 8456                task::VariableName::Custom(capture_name.into()),
 8457                value.clone(),
 8458            );
 8459        }
 8460        project.update(cx, |project, cx| {
 8461            project.task_store().update(cx, |task_store, cx| {
 8462                task_store.task_context_for_location(captured_task_variables, location, cx)
 8463            })
 8464        })
 8465    }
 8466
 8467    pub fn spawn_nearest_task(
 8468        &mut self,
 8469        action: &SpawnNearestTask,
 8470        window: &mut Window,
 8471        cx: &mut Context<Self>,
 8472    ) {
 8473        let Some((workspace, _)) = self.workspace.clone() else {
 8474            return;
 8475        };
 8476        let Some(project) = self.project.clone() else {
 8477            return;
 8478        };
 8479
 8480        // Try to find a closest, enclosing node using tree-sitter that has a task
 8481        let Some((buffer, buffer_row, tasks)) = self
 8482            .find_enclosing_node_task(cx)
 8483            // Or find the task that's closest in row-distance.
 8484            .or_else(|| self.find_closest_task(cx))
 8485        else {
 8486            return;
 8487        };
 8488
 8489        let reveal_strategy = action.reveal;
 8490        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8491        cx.spawn_in(window, async move |_, cx| {
 8492            let context = task_context.await?;
 8493            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8494
 8495            let resolved = &mut resolved_task.resolved;
 8496            resolved.reveal = reveal_strategy;
 8497
 8498            workspace
 8499                .update_in(cx, |workspace, window, cx| {
 8500                    workspace.schedule_resolved_task(
 8501                        task_source_kind,
 8502                        resolved_task,
 8503                        false,
 8504                        window,
 8505                        cx,
 8506                    );
 8507                })
 8508                .ok()
 8509        })
 8510        .detach();
 8511    }
 8512
 8513    fn find_closest_task(
 8514        &mut self,
 8515        cx: &mut Context<Self>,
 8516    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8517        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8518
 8519        let ((buffer_id, row), tasks) = self
 8520            .tasks
 8521            .iter()
 8522            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8523
 8524        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8525        let tasks = Arc::new(tasks.to_owned());
 8526        Some((buffer, *row, tasks))
 8527    }
 8528
 8529    fn find_enclosing_node_task(
 8530        &mut self,
 8531        cx: &mut Context<Self>,
 8532    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8533        let snapshot = self.buffer.read(cx).snapshot(cx);
 8534        let offset = self.selections.newest::<usize>(cx).head();
 8535        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8536        let buffer_id = excerpt.buffer().remote_id();
 8537
 8538        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8539        let mut cursor = layer.node().walk();
 8540
 8541        while cursor.goto_first_child_for_byte(offset).is_some() {
 8542            if cursor.node().end_byte() == offset {
 8543                cursor.goto_next_sibling();
 8544            }
 8545        }
 8546
 8547        // Ascend to the smallest ancestor that contains the range and has a task.
 8548        loop {
 8549            let node = cursor.node();
 8550            let node_range = node.byte_range();
 8551            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8552
 8553            // Check if this node contains our offset
 8554            if node_range.start <= offset && node_range.end >= offset {
 8555                // If it contains offset, check for task
 8556                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8557                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8558                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8559                }
 8560            }
 8561
 8562            if !cursor.goto_parent() {
 8563                break;
 8564            }
 8565        }
 8566        None
 8567    }
 8568
 8569    fn render_run_indicator(
 8570        &self,
 8571        _style: &EditorStyle,
 8572        is_active: bool,
 8573        row: DisplayRow,
 8574        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8575        cx: &mut Context<Self>,
 8576    ) -> IconButton {
 8577        let color = Color::Muted;
 8578        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8579
 8580        IconButton::new(
 8581            ("run_indicator", row.0 as usize),
 8582            ui::IconName::PlayOutlined,
 8583        )
 8584        .shape(ui::IconButtonShape::Square)
 8585        .icon_size(IconSize::XSmall)
 8586        .icon_color(color)
 8587        .toggle_state(is_active)
 8588        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8589            let quick_launch = match e {
 8590                ClickEvent::Keyboard(_) => true,
 8591                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8592            };
 8593
 8594            window.focus(&editor.focus_handle(cx));
 8595            editor.toggle_code_actions(
 8596                &ToggleCodeActions {
 8597                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8598                    quick_launch,
 8599                },
 8600                window,
 8601                cx,
 8602            );
 8603        }))
 8604        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8605            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8606        }))
 8607    }
 8608
 8609    pub fn context_menu_visible(&self) -> bool {
 8610        !self.edit_prediction_preview_is_active()
 8611            && self
 8612                .context_menu
 8613                .borrow()
 8614                .as_ref()
 8615                .is_some_and(|menu| menu.visible())
 8616    }
 8617
 8618    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8619        self.context_menu
 8620            .borrow()
 8621            .as_ref()
 8622            .map(|menu| menu.origin())
 8623    }
 8624
 8625    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8626        self.context_menu_options = Some(options);
 8627    }
 8628
 8629    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8630    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8631
 8632    fn render_edit_prediction_popover(
 8633        &mut self,
 8634        text_bounds: &Bounds<Pixels>,
 8635        content_origin: gpui::Point<Pixels>,
 8636        right_margin: Pixels,
 8637        editor_snapshot: &EditorSnapshot,
 8638        visible_row_range: Range<DisplayRow>,
 8639        scroll_top: f32,
 8640        scroll_bottom: f32,
 8641        line_layouts: &[LineWithInvisibles],
 8642        line_height: Pixels,
 8643        scroll_pixel_position: gpui::Point<Pixels>,
 8644        newest_selection_head: Option<DisplayPoint>,
 8645        editor_width: Pixels,
 8646        style: &EditorStyle,
 8647        window: &mut Window,
 8648        cx: &mut App,
 8649    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8650        if self.mode().is_minimap() {
 8651            return None;
 8652        }
 8653        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8654
 8655        if self.edit_prediction_visible_in_cursor_popover(true) {
 8656            return None;
 8657        }
 8658
 8659        match &active_edit_prediction.completion {
 8660            EditPrediction::MoveWithin { target, .. } => {
 8661                let target_display_point = target.to_display_point(editor_snapshot);
 8662
 8663                if self.edit_prediction_requires_modifier() {
 8664                    if !self.edit_prediction_preview_is_active() {
 8665                        return None;
 8666                    }
 8667
 8668                    self.render_edit_prediction_modifier_jump_popover(
 8669                        text_bounds,
 8670                        content_origin,
 8671                        visible_row_range,
 8672                        line_layouts,
 8673                        line_height,
 8674                        scroll_pixel_position,
 8675                        newest_selection_head,
 8676                        target_display_point,
 8677                        window,
 8678                        cx,
 8679                    )
 8680                } else {
 8681                    self.render_edit_prediction_eager_jump_popover(
 8682                        text_bounds,
 8683                        content_origin,
 8684                        editor_snapshot,
 8685                        visible_row_range,
 8686                        scroll_top,
 8687                        scroll_bottom,
 8688                        line_height,
 8689                        scroll_pixel_position,
 8690                        target_display_point,
 8691                        editor_width,
 8692                        window,
 8693                        cx,
 8694                    )
 8695                }
 8696            }
 8697            EditPrediction::Edit {
 8698                display_mode: EditDisplayMode::Inline,
 8699                ..
 8700            } => None,
 8701            EditPrediction::Edit {
 8702                display_mode: EditDisplayMode::TabAccept,
 8703                edits,
 8704                ..
 8705            } => {
 8706                let range = &edits.first()?.0;
 8707                let target_display_point = range.end.to_display_point(editor_snapshot);
 8708
 8709                self.render_edit_prediction_end_of_line_popover(
 8710                    "Accept",
 8711                    editor_snapshot,
 8712                    visible_row_range,
 8713                    target_display_point,
 8714                    line_height,
 8715                    scroll_pixel_position,
 8716                    content_origin,
 8717                    editor_width,
 8718                    window,
 8719                    cx,
 8720                )
 8721            }
 8722            EditPrediction::Edit {
 8723                edits,
 8724                edit_preview,
 8725                display_mode: EditDisplayMode::DiffPopover,
 8726                snapshot,
 8727            } => self.render_edit_prediction_diff_popover(
 8728                text_bounds,
 8729                content_origin,
 8730                right_margin,
 8731                editor_snapshot,
 8732                visible_row_range,
 8733                line_layouts,
 8734                line_height,
 8735                scroll_pixel_position,
 8736                newest_selection_head,
 8737                editor_width,
 8738                style,
 8739                edits,
 8740                edit_preview,
 8741                snapshot,
 8742                window,
 8743                cx,
 8744            ),
 8745            EditPrediction::MoveOutside { snapshot, .. } => {
 8746                let file_name = snapshot
 8747                    .file()
 8748                    .map(|file| file.file_name(cx))
 8749                    .unwrap_or("untitled");
 8750                let mut element = self
 8751                    .render_edit_prediction_line_popover(
 8752                        format!("Jump to {file_name}"),
 8753                        Some(IconName::ZedPredict),
 8754                        window,
 8755                        cx,
 8756                    )
 8757                    .into_any();
 8758
 8759                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8760                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8761                let origin_y = text_bounds.size.height - size.height - px(30.);
 8762                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8763                element.prepaint_at(origin, window, cx);
 8764
 8765                Some((element, origin))
 8766            }
 8767        }
 8768    }
 8769
 8770    fn render_edit_prediction_modifier_jump_popover(
 8771        &mut self,
 8772        text_bounds: &Bounds<Pixels>,
 8773        content_origin: gpui::Point<Pixels>,
 8774        visible_row_range: Range<DisplayRow>,
 8775        line_layouts: &[LineWithInvisibles],
 8776        line_height: Pixels,
 8777        scroll_pixel_position: gpui::Point<Pixels>,
 8778        newest_selection_head: Option<DisplayPoint>,
 8779        target_display_point: DisplayPoint,
 8780        window: &mut Window,
 8781        cx: &mut App,
 8782    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8783        let scrolled_content_origin =
 8784            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8785
 8786        const SCROLL_PADDING_Y: Pixels = px(12.);
 8787
 8788        if target_display_point.row() < visible_row_range.start {
 8789            return self.render_edit_prediction_scroll_popover(
 8790                |_| SCROLL_PADDING_Y,
 8791                IconName::ArrowUp,
 8792                visible_row_range,
 8793                line_layouts,
 8794                newest_selection_head,
 8795                scrolled_content_origin,
 8796                window,
 8797                cx,
 8798            );
 8799        } else if target_display_point.row() >= visible_row_range.end {
 8800            return self.render_edit_prediction_scroll_popover(
 8801                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8802                IconName::ArrowDown,
 8803                visible_row_range,
 8804                line_layouts,
 8805                newest_selection_head,
 8806                scrolled_content_origin,
 8807                window,
 8808                cx,
 8809            );
 8810        }
 8811
 8812        const POLE_WIDTH: Pixels = px(2.);
 8813
 8814        let line_layout =
 8815            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8816        let target_column = target_display_point.column() as usize;
 8817
 8818        let target_x = line_layout.x_for_index(target_column);
 8819        let target_y =
 8820            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8821
 8822        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8823
 8824        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8825        border_color.l += 0.001;
 8826
 8827        let mut element = v_flex()
 8828            .items_end()
 8829            .when(flag_on_right, |el| el.items_start())
 8830            .child(if flag_on_right {
 8831                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8832                    .rounded_bl(px(0.))
 8833                    .rounded_tl(px(0.))
 8834                    .border_l_2()
 8835                    .border_color(border_color)
 8836            } else {
 8837                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8838                    .rounded_br(px(0.))
 8839                    .rounded_tr(px(0.))
 8840                    .border_r_2()
 8841                    .border_color(border_color)
 8842            })
 8843            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8844            .into_any();
 8845
 8846        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8847
 8848        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8849            - point(
 8850                if flag_on_right {
 8851                    POLE_WIDTH
 8852                } else {
 8853                    size.width - POLE_WIDTH
 8854                },
 8855                size.height - line_height,
 8856            );
 8857
 8858        origin.x = origin.x.max(content_origin.x);
 8859
 8860        element.prepaint_at(origin, window, cx);
 8861
 8862        Some((element, origin))
 8863    }
 8864
 8865    fn render_edit_prediction_scroll_popover(
 8866        &mut self,
 8867        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8868        scroll_icon: IconName,
 8869        visible_row_range: Range<DisplayRow>,
 8870        line_layouts: &[LineWithInvisibles],
 8871        newest_selection_head: Option<DisplayPoint>,
 8872        scrolled_content_origin: gpui::Point<Pixels>,
 8873        window: &mut Window,
 8874        cx: &mut App,
 8875    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8876        let mut element = self
 8877            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8878            .into_any();
 8879
 8880        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8881
 8882        let cursor = newest_selection_head?;
 8883        let cursor_row_layout =
 8884            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8885        let cursor_column = cursor.column() as usize;
 8886
 8887        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8888
 8889        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8890
 8891        element.prepaint_at(origin, window, cx);
 8892        Some((element, origin))
 8893    }
 8894
 8895    fn render_edit_prediction_eager_jump_popover(
 8896        &mut self,
 8897        text_bounds: &Bounds<Pixels>,
 8898        content_origin: gpui::Point<Pixels>,
 8899        editor_snapshot: &EditorSnapshot,
 8900        visible_row_range: Range<DisplayRow>,
 8901        scroll_top: f32,
 8902        scroll_bottom: f32,
 8903        line_height: Pixels,
 8904        scroll_pixel_position: gpui::Point<Pixels>,
 8905        target_display_point: DisplayPoint,
 8906        editor_width: Pixels,
 8907        window: &mut Window,
 8908        cx: &mut App,
 8909    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8910        if target_display_point.row().as_f32() < scroll_top {
 8911            let mut element = self
 8912                .render_edit_prediction_line_popover(
 8913                    "Jump to Edit",
 8914                    Some(IconName::ArrowUp),
 8915                    window,
 8916                    cx,
 8917                )
 8918                .into_any();
 8919
 8920            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8921            let offset = point(
 8922                (text_bounds.size.width - size.width) / 2.,
 8923                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8924            );
 8925
 8926            let origin = text_bounds.origin + offset;
 8927            element.prepaint_at(origin, window, cx);
 8928            Some((element, origin))
 8929        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8930            let mut element = self
 8931                .render_edit_prediction_line_popover(
 8932                    "Jump to Edit",
 8933                    Some(IconName::ArrowDown),
 8934                    window,
 8935                    cx,
 8936                )
 8937                .into_any();
 8938
 8939            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8940            let offset = point(
 8941                (text_bounds.size.width - size.width) / 2.,
 8942                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8943            );
 8944
 8945            let origin = text_bounds.origin + offset;
 8946            element.prepaint_at(origin, window, cx);
 8947            Some((element, origin))
 8948        } else {
 8949            self.render_edit_prediction_end_of_line_popover(
 8950                "Jump to Edit",
 8951                editor_snapshot,
 8952                visible_row_range,
 8953                target_display_point,
 8954                line_height,
 8955                scroll_pixel_position,
 8956                content_origin,
 8957                editor_width,
 8958                window,
 8959                cx,
 8960            )
 8961        }
 8962    }
 8963
 8964    fn render_edit_prediction_end_of_line_popover(
 8965        self: &mut Editor,
 8966        label: &'static str,
 8967        editor_snapshot: &EditorSnapshot,
 8968        visible_row_range: Range<DisplayRow>,
 8969        target_display_point: DisplayPoint,
 8970        line_height: Pixels,
 8971        scroll_pixel_position: gpui::Point<Pixels>,
 8972        content_origin: gpui::Point<Pixels>,
 8973        editor_width: Pixels,
 8974        window: &mut Window,
 8975        cx: &mut App,
 8976    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8977        let target_line_end = DisplayPoint::new(
 8978            target_display_point.row(),
 8979            editor_snapshot.line_len(target_display_point.row()),
 8980        );
 8981
 8982        let mut element = self
 8983            .render_edit_prediction_line_popover(label, None, window, cx)
 8984            .into_any();
 8985
 8986        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8987
 8988        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8989
 8990        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8991        let mut origin = start_point
 8992            + line_origin
 8993            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8994        origin.x = origin.x.max(content_origin.x);
 8995
 8996        let max_x = content_origin.x + editor_width - size.width;
 8997
 8998        if origin.x > max_x {
 8999            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9000
 9001            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9002                origin.y += offset;
 9003                IconName::ArrowUp
 9004            } else {
 9005                origin.y -= offset;
 9006                IconName::ArrowDown
 9007            };
 9008
 9009            element = self
 9010                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9011                .into_any();
 9012
 9013            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9014
 9015            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9016        }
 9017
 9018        element.prepaint_at(origin, window, cx);
 9019        Some((element, origin))
 9020    }
 9021
 9022    fn render_edit_prediction_diff_popover(
 9023        self: &Editor,
 9024        text_bounds: &Bounds<Pixels>,
 9025        content_origin: gpui::Point<Pixels>,
 9026        right_margin: Pixels,
 9027        editor_snapshot: &EditorSnapshot,
 9028        visible_row_range: Range<DisplayRow>,
 9029        line_layouts: &[LineWithInvisibles],
 9030        line_height: Pixels,
 9031        scroll_pixel_position: gpui::Point<Pixels>,
 9032        newest_selection_head: Option<DisplayPoint>,
 9033        editor_width: Pixels,
 9034        style: &EditorStyle,
 9035        edits: &Vec<(Range<Anchor>, String)>,
 9036        edit_preview: &Option<language::EditPreview>,
 9037        snapshot: &language::BufferSnapshot,
 9038        window: &mut Window,
 9039        cx: &mut App,
 9040    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9041        let edit_start = edits
 9042            .first()
 9043            .unwrap()
 9044            .0
 9045            .start
 9046            .to_display_point(editor_snapshot);
 9047        let edit_end = edits
 9048            .last()
 9049            .unwrap()
 9050            .0
 9051            .end
 9052            .to_display_point(editor_snapshot);
 9053
 9054        let is_visible = visible_row_range.contains(&edit_start.row())
 9055            || visible_row_range.contains(&edit_end.row());
 9056        if !is_visible {
 9057            return None;
 9058        }
 9059
 9060        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9061            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9062        } else {
 9063            // Fallback for providers without edit_preview
 9064            crate::edit_prediction_fallback_text(edits, cx)
 9065        };
 9066
 9067        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9068        let line_count = highlighted_edits.text.lines().count();
 9069
 9070        const BORDER_WIDTH: Pixels = px(1.);
 9071
 9072        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9073        let has_keybind = keybind.is_some();
 9074
 9075        let mut element = h_flex()
 9076            .items_start()
 9077            .child(
 9078                h_flex()
 9079                    .bg(cx.theme().colors().editor_background)
 9080                    .border(BORDER_WIDTH)
 9081                    .shadow_xs()
 9082                    .border_color(cx.theme().colors().border)
 9083                    .rounded_l_lg()
 9084                    .when(line_count > 1, |el| el.rounded_br_lg())
 9085                    .pr_1()
 9086                    .child(styled_text),
 9087            )
 9088            .child(
 9089                h_flex()
 9090                    .h(line_height + BORDER_WIDTH * 2.)
 9091                    .px_1p5()
 9092                    .gap_1()
 9093                    // Workaround: For some reason, there's a gap if we don't do this
 9094                    .ml(-BORDER_WIDTH)
 9095                    .shadow(vec![gpui::BoxShadow {
 9096                        color: gpui::black().opacity(0.05),
 9097                        offset: point(px(1.), px(1.)),
 9098                        blur_radius: px(2.),
 9099                        spread_radius: px(0.),
 9100                    }])
 9101                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9102                    .border(BORDER_WIDTH)
 9103                    .border_color(cx.theme().colors().border)
 9104                    .rounded_r_lg()
 9105                    .id("edit_prediction_diff_popover_keybind")
 9106                    .when(!has_keybind, |el| {
 9107                        let status_colors = cx.theme().status();
 9108
 9109                        el.bg(status_colors.error_background)
 9110                            .border_color(status_colors.error.opacity(0.6))
 9111                            .child(Icon::new(IconName::Info).color(Color::Error))
 9112                            .cursor_default()
 9113                            .hoverable_tooltip(move |_window, cx| {
 9114                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9115                            })
 9116                    })
 9117                    .children(keybind),
 9118            )
 9119            .into_any();
 9120
 9121        let longest_row =
 9122            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9123        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9124            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9125        } else {
 9126            layout_line(
 9127                longest_row,
 9128                editor_snapshot,
 9129                style,
 9130                editor_width,
 9131                |_| false,
 9132                window,
 9133                cx,
 9134            )
 9135            .width
 9136        };
 9137
 9138        let viewport_bounds =
 9139            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9140                right: -right_margin,
 9141                ..Default::default()
 9142            });
 9143
 9144        let x_after_longest =
 9145            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9146                - scroll_pixel_position.x;
 9147
 9148        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9149
 9150        // Fully visible if it can be displayed within the window (allow overlapping other
 9151        // panes). However, this is only allowed if the popover starts within text_bounds.
 9152        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9153            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9154
 9155        let mut origin = if can_position_to_the_right {
 9156            point(
 9157                x_after_longest,
 9158                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9159                    - scroll_pixel_position.y,
 9160            )
 9161        } else {
 9162            let cursor_row = newest_selection_head.map(|head| head.row());
 9163            let above_edit = edit_start
 9164                .row()
 9165                .0
 9166                .checked_sub(line_count as u32)
 9167                .map(DisplayRow);
 9168            let below_edit = Some(edit_end.row() + 1);
 9169            let above_cursor =
 9170                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9171            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9172
 9173            // Place the edit popover adjacent to the edit if there is a location
 9174            // available that is onscreen and does not obscure the cursor. Otherwise,
 9175            // place it adjacent to the cursor.
 9176            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9177                .into_iter()
 9178                .flatten()
 9179                .find(|&start_row| {
 9180                    let end_row = start_row + line_count as u32;
 9181                    visible_row_range.contains(&start_row)
 9182                        && visible_row_range.contains(&end_row)
 9183                        && cursor_row
 9184                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9185                })?;
 9186
 9187            content_origin
 9188                + point(
 9189                    -scroll_pixel_position.x,
 9190                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9191                )
 9192        };
 9193
 9194        origin.x -= BORDER_WIDTH;
 9195
 9196        window.defer_draw(element, origin, 1);
 9197
 9198        // Do not return an element, since it will already be drawn due to defer_draw.
 9199        None
 9200    }
 9201
 9202    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9203        px(30.)
 9204    }
 9205
 9206    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9207        if self.read_only(cx) {
 9208            cx.theme().players().read_only()
 9209        } else {
 9210            self.style.as_ref().unwrap().local_player
 9211        }
 9212    }
 9213
 9214    fn render_edit_prediction_accept_keybind(
 9215        &self,
 9216        window: &mut Window,
 9217        cx: &App,
 9218    ) -> Option<AnyElement> {
 9219        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9220        let accept_keystroke = accept_binding.keystroke()?;
 9221
 9222        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9223
 9224        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9225            Color::Accent
 9226        } else {
 9227            Color::Muted
 9228        };
 9229
 9230        h_flex()
 9231            .px_0p5()
 9232            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9233            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9234            .text_size(TextSize::XSmall.rems(cx))
 9235            .child(h_flex().children(ui::render_modifiers(
 9236                accept_keystroke.modifiers(),
 9237                PlatformStyle::platform(),
 9238                Some(modifiers_color),
 9239                Some(IconSize::XSmall.rems().into()),
 9240                true,
 9241            )))
 9242            .when(is_platform_style_mac, |parent| {
 9243                parent.child(accept_keystroke.key().to_string())
 9244            })
 9245            .when(!is_platform_style_mac, |parent| {
 9246                parent.child(
 9247                    Key::new(
 9248                        util::capitalize(accept_keystroke.key()),
 9249                        Some(Color::Default),
 9250                    )
 9251                    .size(Some(IconSize::XSmall.rems().into())),
 9252                )
 9253            })
 9254            .into_any()
 9255            .into()
 9256    }
 9257
 9258    fn render_edit_prediction_line_popover(
 9259        &self,
 9260        label: impl Into<SharedString>,
 9261        icon: Option<IconName>,
 9262        window: &mut Window,
 9263        cx: &App,
 9264    ) -> Stateful<Div> {
 9265        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9266
 9267        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9268        let has_keybind = keybind.is_some();
 9269
 9270        h_flex()
 9271            .id("ep-line-popover")
 9272            .py_0p5()
 9273            .pl_1()
 9274            .pr(padding_right)
 9275            .gap_1()
 9276            .rounded_md()
 9277            .border_1()
 9278            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9279            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9280            .shadow_xs()
 9281            .when(!has_keybind, |el| {
 9282                let status_colors = cx.theme().status();
 9283
 9284                el.bg(status_colors.error_background)
 9285                    .border_color(status_colors.error.opacity(0.6))
 9286                    .pl_2()
 9287                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9288                    .cursor_default()
 9289                    .hoverable_tooltip(move |_window, cx| {
 9290                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9291                    })
 9292            })
 9293            .children(keybind)
 9294            .child(
 9295                Label::new(label)
 9296                    .size(LabelSize::Small)
 9297                    .when(!has_keybind, |el| {
 9298                        el.color(cx.theme().status().error.into()).strikethrough()
 9299                    }),
 9300            )
 9301            .when(!has_keybind, |el| {
 9302                el.child(
 9303                    h_flex().ml_1().child(
 9304                        Icon::new(IconName::Info)
 9305                            .size(IconSize::Small)
 9306                            .color(cx.theme().status().error.into()),
 9307                    ),
 9308                )
 9309            })
 9310            .when_some(icon, |element, icon| {
 9311                element.child(
 9312                    div()
 9313                        .mt(px(1.5))
 9314                        .child(Icon::new(icon).size(IconSize::Small)),
 9315                )
 9316            })
 9317    }
 9318
 9319    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9320        let accent_color = cx.theme().colors().text_accent;
 9321        let editor_bg_color = cx.theme().colors().editor_background;
 9322        editor_bg_color.blend(accent_color.opacity(0.1))
 9323    }
 9324
 9325    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9326        let accent_color = cx.theme().colors().text_accent;
 9327        let editor_bg_color = cx.theme().colors().editor_background;
 9328        editor_bg_color.blend(accent_color.opacity(0.6))
 9329    }
 9330    fn get_prediction_provider_icon_name(
 9331        provider: &Option<RegisteredEditPredictionProvider>,
 9332    ) -> IconName {
 9333        match provider {
 9334            Some(provider) => match provider.provider.name() {
 9335                "copilot" => IconName::Copilot,
 9336                "supermaven" => IconName::Supermaven,
 9337                _ => IconName::ZedPredict,
 9338            },
 9339            None => IconName::ZedPredict,
 9340        }
 9341    }
 9342
 9343    fn render_edit_prediction_cursor_popover(
 9344        &self,
 9345        min_width: Pixels,
 9346        max_width: Pixels,
 9347        cursor_point: Point,
 9348        style: &EditorStyle,
 9349        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9350        _window: &Window,
 9351        cx: &mut Context<Editor>,
 9352    ) -> Option<AnyElement> {
 9353        let provider = self.edit_prediction_provider.as_ref()?;
 9354        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9355
 9356        let is_refreshing = provider.provider.is_refreshing(cx);
 9357
 9358        fn pending_completion_container(icon: IconName) -> Div {
 9359            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9360        }
 9361
 9362        let completion = match &self.active_edit_prediction {
 9363            Some(prediction) => {
 9364                if !self.has_visible_completions_menu() {
 9365                    const RADIUS: Pixels = px(6.);
 9366                    const BORDER_WIDTH: Pixels = px(1.);
 9367
 9368                    return Some(
 9369                        h_flex()
 9370                            .elevation_2(cx)
 9371                            .border(BORDER_WIDTH)
 9372                            .border_color(cx.theme().colors().border)
 9373                            .when(accept_keystroke.is_none(), |el| {
 9374                                el.border_color(cx.theme().status().error)
 9375                            })
 9376                            .rounded(RADIUS)
 9377                            .rounded_tl(px(0.))
 9378                            .overflow_hidden()
 9379                            .child(div().px_1p5().child(match &prediction.completion {
 9380                                EditPrediction::MoveWithin { target, snapshot } => {
 9381                                    use text::ToPoint as _;
 9382                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9383                                    {
 9384                                        Icon::new(IconName::ZedPredictDown)
 9385                                    } else {
 9386                                        Icon::new(IconName::ZedPredictUp)
 9387                                    }
 9388                                }
 9389                                EditPrediction::MoveOutside { .. } => {
 9390                                    // TODO [zeta2] custom icon for external jump?
 9391                                    Icon::new(provider_icon)
 9392                                }
 9393                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9394                            }))
 9395                            .child(
 9396                                h_flex()
 9397                                    .gap_1()
 9398                                    .py_1()
 9399                                    .px_2()
 9400                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9401                                    .border_l_1()
 9402                                    .border_color(cx.theme().colors().border)
 9403                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9404                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9405                                        el.child(
 9406                                            Label::new("Hold")
 9407                                                .size(LabelSize::Small)
 9408                                                .when(accept_keystroke.is_none(), |el| {
 9409                                                    el.strikethrough()
 9410                                                })
 9411                                                .line_height_style(LineHeightStyle::UiLabel),
 9412                                        )
 9413                                    })
 9414                                    .id("edit_prediction_cursor_popover_keybind")
 9415                                    .when(accept_keystroke.is_none(), |el| {
 9416                                        let status_colors = cx.theme().status();
 9417
 9418                                        el.bg(status_colors.error_background)
 9419                                            .border_color(status_colors.error.opacity(0.6))
 9420                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9421                                            .cursor_default()
 9422                                            .hoverable_tooltip(move |_window, cx| {
 9423                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9424                                                    .into()
 9425                                            })
 9426                                    })
 9427                                    .when_some(
 9428                                        accept_keystroke.as_ref(),
 9429                                        |el, accept_keystroke| {
 9430                                            el.child(h_flex().children(ui::render_modifiers(
 9431                                                accept_keystroke.modifiers(),
 9432                                                PlatformStyle::platform(),
 9433                                                Some(Color::Default),
 9434                                                Some(IconSize::XSmall.rems().into()),
 9435                                                false,
 9436                                            )))
 9437                                        },
 9438                                    ),
 9439                            )
 9440                            .into_any(),
 9441                    );
 9442                }
 9443
 9444                self.render_edit_prediction_cursor_popover_preview(
 9445                    prediction,
 9446                    cursor_point,
 9447                    style,
 9448                    cx,
 9449                )?
 9450            }
 9451
 9452            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9453                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9454                    stale_completion,
 9455                    cursor_point,
 9456                    style,
 9457                    cx,
 9458                )?,
 9459
 9460                None => pending_completion_container(provider_icon)
 9461                    .child(Label::new("...").size(LabelSize::Small)),
 9462            },
 9463
 9464            None => pending_completion_container(provider_icon)
 9465                .child(Label::new("...").size(LabelSize::Small)),
 9466        };
 9467
 9468        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9469            completion
 9470                .with_animation(
 9471                    "loading-completion",
 9472                    Animation::new(Duration::from_secs(2))
 9473                        .repeat()
 9474                        .with_easing(pulsating_between(0.4, 0.8)),
 9475                    |label, delta| label.opacity(delta),
 9476                )
 9477                .into_any_element()
 9478        } else {
 9479            completion.into_any_element()
 9480        };
 9481
 9482        let has_completion = self.active_edit_prediction.is_some();
 9483
 9484        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9485        Some(
 9486            h_flex()
 9487                .min_w(min_width)
 9488                .max_w(max_width)
 9489                .flex_1()
 9490                .elevation_2(cx)
 9491                .border_color(cx.theme().colors().border)
 9492                .child(
 9493                    div()
 9494                        .flex_1()
 9495                        .py_1()
 9496                        .px_2()
 9497                        .overflow_hidden()
 9498                        .child(completion),
 9499                )
 9500                .when_some(accept_keystroke, |el, accept_keystroke| {
 9501                    if !accept_keystroke.modifiers().modified() {
 9502                        return el;
 9503                    }
 9504
 9505                    el.child(
 9506                        h_flex()
 9507                            .h_full()
 9508                            .border_l_1()
 9509                            .rounded_r_lg()
 9510                            .border_color(cx.theme().colors().border)
 9511                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9512                            .gap_1()
 9513                            .py_1()
 9514                            .px_2()
 9515                            .child(
 9516                                h_flex()
 9517                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9518                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9519                                    .child(h_flex().children(ui::render_modifiers(
 9520                                        accept_keystroke.modifiers(),
 9521                                        PlatformStyle::platform(),
 9522                                        Some(if !has_completion {
 9523                                            Color::Muted
 9524                                        } else {
 9525                                            Color::Default
 9526                                        }),
 9527                                        None,
 9528                                        false,
 9529                                    ))),
 9530                            )
 9531                            .child(Label::new("Preview").into_any_element())
 9532                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9533                    )
 9534                })
 9535                .into_any(),
 9536        )
 9537    }
 9538
 9539    fn render_edit_prediction_cursor_popover_preview(
 9540        &self,
 9541        completion: &EditPredictionState,
 9542        cursor_point: Point,
 9543        style: &EditorStyle,
 9544        cx: &mut Context<Editor>,
 9545    ) -> Option<Div> {
 9546        use text::ToPoint as _;
 9547
 9548        fn render_relative_row_jump(
 9549            prefix: impl Into<String>,
 9550            current_row: u32,
 9551            target_row: u32,
 9552        ) -> Div {
 9553            let (row_diff, arrow) = if target_row < current_row {
 9554                (current_row - target_row, IconName::ArrowUp)
 9555            } else {
 9556                (target_row - current_row, IconName::ArrowDown)
 9557            };
 9558
 9559            h_flex()
 9560                .child(
 9561                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9562                        .color(Color::Muted)
 9563                        .size(LabelSize::Small),
 9564                )
 9565                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9566        }
 9567
 9568        let supports_jump = self
 9569            .edit_prediction_provider
 9570            .as_ref()
 9571            .map(|provider| provider.provider.supports_jump_to_edit())
 9572            .unwrap_or(true);
 9573
 9574        match &completion.completion {
 9575            EditPrediction::MoveWithin {
 9576                target, snapshot, ..
 9577            } => {
 9578                if !supports_jump {
 9579                    return None;
 9580                }
 9581
 9582                Some(
 9583                    h_flex()
 9584                        .px_2()
 9585                        .gap_2()
 9586                        .flex_1()
 9587                        .child(
 9588                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9589                                Icon::new(IconName::ZedPredictDown)
 9590                            } else {
 9591                                Icon::new(IconName::ZedPredictUp)
 9592                            },
 9593                        )
 9594                        .child(Label::new("Jump to Edit")),
 9595                )
 9596            }
 9597            EditPrediction::MoveOutside { snapshot, .. } => {
 9598                let file_name = snapshot
 9599                    .file()
 9600                    .map(|file| file.file_name(cx))
 9601                    .unwrap_or("untitled");
 9602                Some(
 9603                    h_flex()
 9604                        .px_2()
 9605                        .gap_2()
 9606                        .flex_1()
 9607                        .child(Icon::new(IconName::ZedPredict))
 9608                        .child(Label::new(format!("Jump to {file_name}"))),
 9609                )
 9610            }
 9611            EditPrediction::Edit {
 9612                edits,
 9613                edit_preview,
 9614                snapshot,
 9615                display_mode: _,
 9616            } => {
 9617                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9618
 9619                let (highlighted_edits, has_more_lines) =
 9620                    if let Some(edit_preview) = edit_preview.as_ref() {
 9621                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9622                            .first_line_preview()
 9623                    } else {
 9624                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9625                    };
 9626
 9627                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9628                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9629
 9630                let preview = h_flex()
 9631                    .gap_1()
 9632                    .min_w_16()
 9633                    .child(styled_text)
 9634                    .when(has_more_lines, |parent| parent.child(""));
 9635
 9636                let left = if supports_jump && first_edit_row != cursor_point.row {
 9637                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9638                        .into_any_element()
 9639                } else {
 9640                    let icon_name =
 9641                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9642                    Icon::new(icon_name).into_any_element()
 9643                };
 9644
 9645                Some(
 9646                    h_flex()
 9647                        .h_full()
 9648                        .flex_1()
 9649                        .gap_2()
 9650                        .pr_1()
 9651                        .overflow_x_hidden()
 9652                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9653                        .child(left)
 9654                        .child(preview),
 9655                )
 9656            }
 9657        }
 9658    }
 9659
 9660    pub fn render_context_menu(
 9661        &self,
 9662        style: &EditorStyle,
 9663        max_height_in_lines: u32,
 9664        window: &mut Window,
 9665        cx: &mut Context<Editor>,
 9666    ) -> Option<AnyElement> {
 9667        let menu = self.context_menu.borrow();
 9668        let menu = menu.as_ref()?;
 9669        if !menu.visible() {
 9670            return None;
 9671        };
 9672        Some(menu.render(style, max_height_in_lines, window, cx))
 9673    }
 9674
 9675    fn render_context_menu_aside(
 9676        &mut self,
 9677        max_size: Size<Pixels>,
 9678        window: &mut Window,
 9679        cx: &mut Context<Editor>,
 9680    ) -> Option<AnyElement> {
 9681        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9682            if menu.visible() {
 9683                menu.render_aside(max_size, window, cx)
 9684            } else {
 9685                None
 9686            }
 9687        })
 9688    }
 9689
 9690    fn hide_context_menu(
 9691        &mut self,
 9692        window: &mut Window,
 9693        cx: &mut Context<Self>,
 9694    ) -> Option<CodeContextMenu> {
 9695        cx.notify();
 9696        self.completion_tasks.clear();
 9697        let context_menu = self.context_menu.borrow_mut().take();
 9698        self.stale_edit_prediction_in_menu.take();
 9699        self.update_visible_edit_prediction(window, cx);
 9700        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9701            && let Some(completion_provider) = &self.completion_provider
 9702        {
 9703            completion_provider.selection_changed(None, window, cx);
 9704        }
 9705        context_menu
 9706    }
 9707
 9708    fn show_snippet_choices(
 9709        &mut self,
 9710        choices: &Vec<String>,
 9711        selection: Range<Anchor>,
 9712        cx: &mut Context<Self>,
 9713    ) {
 9714        let Some((_, buffer, _)) = self
 9715            .buffer()
 9716            .read(cx)
 9717            .excerpt_containing(selection.start, cx)
 9718        else {
 9719            return;
 9720        };
 9721        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9722        else {
 9723            return;
 9724        };
 9725        if buffer != end_buffer {
 9726            log::error!("expected anchor range to have matching buffer IDs");
 9727            return;
 9728        }
 9729
 9730        let id = post_inc(&mut self.next_completion_id);
 9731        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9732        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9733            CompletionsMenu::new_snippet_choices(
 9734                id,
 9735                true,
 9736                choices,
 9737                selection,
 9738                buffer,
 9739                snippet_sort_order,
 9740            ),
 9741        ));
 9742    }
 9743
 9744    pub fn insert_snippet(
 9745        &mut self,
 9746        insertion_ranges: &[Range<usize>],
 9747        snippet: Snippet,
 9748        window: &mut Window,
 9749        cx: &mut Context<Self>,
 9750    ) -> Result<()> {
 9751        struct Tabstop<T> {
 9752            is_end_tabstop: bool,
 9753            ranges: Vec<Range<T>>,
 9754            choices: Option<Vec<String>>,
 9755        }
 9756
 9757        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9758            let snippet_text: Arc<str> = snippet.text.clone().into();
 9759            let edits = insertion_ranges
 9760                .iter()
 9761                .cloned()
 9762                .map(|range| (range, snippet_text.clone()));
 9763            let autoindent_mode = AutoindentMode::Block {
 9764                original_indent_columns: Vec::new(),
 9765            };
 9766            buffer.edit(edits, Some(autoindent_mode), cx);
 9767
 9768            let snapshot = &*buffer.read(cx);
 9769            let snippet = &snippet;
 9770            snippet
 9771                .tabstops
 9772                .iter()
 9773                .map(|tabstop| {
 9774                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9775                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9776                    });
 9777                    let mut tabstop_ranges = tabstop
 9778                        .ranges
 9779                        .iter()
 9780                        .flat_map(|tabstop_range| {
 9781                            let mut delta = 0_isize;
 9782                            insertion_ranges.iter().map(move |insertion_range| {
 9783                                let insertion_start = insertion_range.start as isize + delta;
 9784                                delta +=
 9785                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9786
 9787                                let start = ((insertion_start + tabstop_range.start) as usize)
 9788                                    .min(snapshot.len());
 9789                                let end = ((insertion_start + tabstop_range.end) as usize)
 9790                                    .min(snapshot.len());
 9791                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9792                            })
 9793                        })
 9794                        .collect::<Vec<_>>();
 9795                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9796
 9797                    Tabstop {
 9798                        is_end_tabstop,
 9799                        ranges: tabstop_ranges,
 9800                        choices: tabstop.choices.clone(),
 9801                    }
 9802                })
 9803                .collect::<Vec<_>>()
 9804        });
 9805        if let Some(tabstop) = tabstops.first() {
 9806            self.change_selections(Default::default(), window, cx, |s| {
 9807                // Reverse order so that the first range is the newest created selection.
 9808                // Completions will use it and autoscroll will prioritize it.
 9809                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9810            });
 9811
 9812            if let Some(choices) = &tabstop.choices
 9813                && let Some(selection) = tabstop.ranges.first()
 9814            {
 9815                self.show_snippet_choices(choices, selection.clone(), cx)
 9816            }
 9817
 9818            // If we're already at the last tabstop and it's at the end of the snippet,
 9819            // we're done, we don't need to keep the state around.
 9820            if !tabstop.is_end_tabstop {
 9821                let choices = tabstops
 9822                    .iter()
 9823                    .map(|tabstop| tabstop.choices.clone())
 9824                    .collect();
 9825
 9826                let ranges = tabstops
 9827                    .into_iter()
 9828                    .map(|tabstop| tabstop.ranges)
 9829                    .collect::<Vec<_>>();
 9830
 9831                self.snippet_stack.push(SnippetState {
 9832                    active_index: 0,
 9833                    ranges,
 9834                    choices,
 9835                });
 9836            }
 9837
 9838            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9839            if self.autoclose_regions.is_empty() {
 9840                let snapshot = self.buffer.read(cx).snapshot(cx);
 9841                let mut all_selections = self.selections.all::<Point>(cx);
 9842                for selection in &mut all_selections {
 9843                    let selection_head = selection.head();
 9844                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9845                        continue;
 9846                    };
 9847
 9848                    let mut bracket_pair = None;
 9849                    let max_lookup_length = scope
 9850                        .brackets()
 9851                        .map(|(pair, _)| {
 9852                            pair.start
 9853                                .as_str()
 9854                                .chars()
 9855                                .count()
 9856                                .max(pair.end.as_str().chars().count())
 9857                        })
 9858                        .max();
 9859                    if let Some(max_lookup_length) = max_lookup_length {
 9860                        let next_text = snapshot
 9861                            .chars_at(selection_head)
 9862                            .take(max_lookup_length)
 9863                            .collect::<String>();
 9864                        let prev_text = snapshot
 9865                            .reversed_chars_at(selection_head)
 9866                            .take(max_lookup_length)
 9867                            .collect::<String>();
 9868
 9869                        for (pair, enabled) in scope.brackets() {
 9870                            if enabled
 9871                                && pair.close
 9872                                && prev_text.starts_with(pair.start.as_str())
 9873                                && next_text.starts_with(pair.end.as_str())
 9874                            {
 9875                                bracket_pair = Some(pair.clone());
 9876                                break;
 9877                            }
 9878                        }
 9879                    }
 9880
 9881                    if let Some(pair) = bracket_pair {
 9882                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9883                        let autoclose_enabled =
 9884                            self.use_autoclose && snapshot_settings.use_autoclose;
 9885                        if autoclose_enabled {
 9886                            let start = snapshot.anchor_after(selection_head);
 9887                            let end = snapshot.anchor_after(selection_head);
 9888                            self.autoclose_regions.push(AutocloseRegion {
 9889                                selection_id: selection.id,
 9890                                range: start..end,
 9891                                pair,
 9892                            });
 9893                        }
 9894                    }
 9895                }
 9896            }
 9897        }
 9898        Ok(())
 9899    }
 9900
 9901    pub fn move_to_next_snippet_tabstop(
 9902        &mut self,
 9903        window: &mut Window,
 9904        cx: &mut Context<Self>,
 9905    ) -> bool {
 9906        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9907    }
 9908
 9909    pub fn move_to_prev_snippet_tabstop(
 9910        &mut self,
 9911        window: &mut Window,
 9912        cx: &mut Context<Self>,
 9913    ) -> bool {
 9914        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9915    }
 9916
 9917    pub fn move_to_snippet_tabstop(
 9918        &mut self,
 9919        bias: Bias,
 9920        window: &mut Window,
 9921        cx: &mut Context<Self>,
 9922    ) -> bool {
 9923        if let Some(mut snippet) = self.snippet_stack.pop() {
 9924            match bias {
 9925                Bias::Left => {
 9926                    if snippet.active_index > 0 {
 9927                        snippet.active_index -= 1;
 9928                    } else {
 9929                        self.snippet_stack.push(snippet);
 9930                        return false;
 9931                    }
 9932                }
 9933                Bias::Right => {
 9934                    if snippet.active_index + 1 < snippet.ranges.len() {
 9935                        snippet.active_index += 1;
 9936                    } else {
 9937                        self.snippet_stack.push(snippet);
 9938                        return false;
 9939                    }
 9940                }
 9941            }
 9942            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9943                self.change_selections(Default::default(), window, cx, |s| {
 9944                    // Reverse order so that the first range is the newest created selection.
 9945                    // Completions will use it and autoscroll will prioritize it.
 9946                    s.select_ranges(current_ranges.iter().rev().cloned())
 9947                });
 9948
 9949                if let Some(choices) = &snippet.choices[snippet.active_index]
 9950                    && let Some(selection) = current_ranges.first()
 9951                {
 9952                    self.show_snippet_choices(choices, selection.clone(), cx);
 9953                }
 9954
 9955                // If snippet state is not at the last tabstop, push it back on the stack
 9956                if snippet.active_index + 1 < snippet.ranges.len() {
 9957                    self.snippet_stack.push(snippet);
 9958                }
 9959                return true;
 9960            }
 9961        }
 9962
 9963        false
 9964    }
 9965
 9966    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9967        self.transact(window, cx, |this, window, cx| {
 9968            this.select_all(&SelectAll, window, cx);
 9969            this.insert("", window, cx);
 9970        });
 9971    }
 9972
 9973    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9974        if self.read_only(cx) {
 9975            return;
 9976        }
 9977        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9978        self.transact(window, cx, |this, window, cx| {
 9979            this.select_autoclose_pair(window, cx);
 9980            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9981            if !this.linked_edit_ranges.is_empty() {
 9982                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9983                let snapshot = this.buffer.read(cx).snapshot(cx);
 9984
 9985                for selection in selections.iter() {
 9986                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9987                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9988                    if selection_start.buffer_id != selection_end.buffer_id {
 9989                        continue;
 9990                    }
 9991                    if let Some(ranges) =
 9992                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9993                    {
 9994                        for (buffer, entries) in ranges {
 9995                            linked_ranges.entry(buffer).or_default().extend(entries);
 9996                        }
 9997                    }
 9998                }
 9999            }
10000
10001            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10002            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10003            for selection in &mut selections {
10004                if selection.is_empty() {
10005                    let old_head = selection.head();
10006                    let mut new_head =
10007                        movement::left(&display_map, old_head.to_display_point(&display_map))
10008                            .to_point(&display_map);
10009                    if let Some((buffer, line_buffer_range)) = display_map
10010                        .buffer_snapshot
10011                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10012                    {
10013                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10014                        let indent_len = match indent_size.kind {
10015                            IndentKind::Space => {
10016                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10017                            }
10018                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10019                        };
10020                        if old_head.column <= indent_size.len && old_head.column > 0 {
10021                            let indent_len = indent_len.get();
10022                            new_head = cmp::min(
10023                                new_head,
10024                                MultiBufferPoint::new(
10025                                    old_head.row,
10026                                    ((old_head.column - 1) / indent_len) * indent_len,
10027                                ),
10028                            );
10029                        }
10030                    }
10031
10032                    selection.set_head(new_head, SelectionGoal::None);
10033                }
10034            }
10035
10036            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10037            this.insert("", window, cx);
10038            let empty_str: Arc<str> = Arc::from("");
10039            for (buffer, edits) in linked_ranges {
10040                let snapshot = buffer.read(cx).snapshot();
10041                use text::ToPoint as TP;
10042
10043                let edits = edits
10044                    .into_iter()
10045                    .map(|range| {
10046                        let end_point = TP::to_point(&range.end, &snapshot);
10047                        let mut start_point = TP::to_point(&range.start, &snapshot);
10048
10049                        if end_point == start_point {
10050                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10051                                .saturating_sub(1);
10052                            start_point =
10053                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10054                        };
10055
10056                        (start_point..end_point, empty_str.clone())
10057                    })
10058                    .sorted_by_key(|(range, _)| range.start)
10059                    .collect::<Vec<_>>();
10060                buffer.update(cx, |this, cx| {
10061                    this.edit(edits, None, cx);
10062                })
10063            }
10064            this.refresh_edit_prediction(true, false, window, cx);
10065            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
10066        });
10067    }
10068
10069    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10070        if self.read_only(cx) {
10071            return;
10072        }
10073        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10074        self.transact(window, cx, |this, window, cx| {
10075            this.change_selections(Default::default(), window, cx, |s| {
10076                s.move_with(|map, selection| {
10077                    if selection.is_empty() {
10078                        let cursor = movement::right(map, selection.head());
10079                        selection.end = cursor;
10080                        selection.reversed = true;
10081                        selection.goal = SelectionGoal::None;
10082                    }
10083                })
10084            });
10085            this.insert("", window, cx);
10086            this.refresh_edit_prediction(true, false, window, cx);
10087        });
10088    }
10089
10090    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10091        if self.mode.is_single_line() {
10092            cx.propagate();
10093            return;
10094        }
10095
10096        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10097        if self.move_to_prev_snippet_tabstop(window, cx) {
10098            return;
10099        }
10100        self.outdent(&Outdent, window, cx);
10101    }
10102
10103    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10104        if self.mode.is_single_line() {
10105            cx.propagate();
10106            return;
10107        }
10108
10109        if self.move_to_next_snippet_tabstop(window, cx) {
10110            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10111            return;
10112        }
10113        if self.read_only(cx) {
10114            return;
10115        }
10116        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10117        let mut selections = self.selections.all_adjusted(cx);
10118        let buffer = self.buffer.read(cx);
10119        let snapshot = buffer.snapshot(cx);
10120        let rows_iter = selections.iter().map(|s| s.head().row);
10121        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10122
10123        let has_some_cursor_in_whitespace = selections
10124            .iter()
10125            .filter(|selection| selection.is_empty())
10126            .any(|selection| {
10127                let cursor = selection.head();
10128                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10129                cursor.column < current_indent.len
10130            });
10131
10132        let mut edits = Vec::new();
10133        let mut prev_edited_row = 0;
10134        let mut row_delta = 0;
10135        for selection in &mut selections {
10136            if selection.start.row != prev_edited_row {
10137                row_delta = 0;
10138            }
10139            prev_edited_row = selection.end.row;
10140
10141            // If the selection is non-empty, then increase the indentation of the selected lines.
10142            if !selection.is_empty() {
10143                row_delta =
10144                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10145                continue;
10146            }
10147
10148            let cursor = selection.head();
10149            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10150            if let Some(suggested_indent) =
10151                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10152            {
10153                // Don't do anything if already at suggested indent
10154                // and there is any other cursor which is not
10155                if has_some_cursor_in_whitespace
10156                    && cursor.column == current_indent.len
10157                    && current_indent.len == suggested_indent.len
10158                {
10159                    continue;
10160                }
10161
10162                // Adjust line and move cursor to suggested indent
10163                // if cursor is not at suggested indent
10164                if cursor.column < suggested_indent.len
10165                    && cursor.column <= current_indent.len
10166                    && current_indent.len <= suggested_indent.len
10167                {
10168                    selection.start = Point::new(cursor.row, suggested_indent.len);
10169                    selection.end = selection.start;
10170                    if row_delta == 0 {
10171                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10172                            cursor.row,
10173                            current_indent,
10174                            suggested_indent,
10175                        ));
10176                        row_delta = suggested_indent.len - current_indent.len;
10177                    }
10178                    continue;
10179                }
10180
10181                // If current indent is more than suggested indent
10182                // only move cursor to current indent and skip indent
10183                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10184                    selection.start = Point::new(cursor.row, current_indent.len);
10185                    selection.end = selection.start;
10186                    continue;
10187                }
10188            }
10189
10190            // Otherwise, insert a hard or soft tab.
10191            let settings = buffer.language_settings_at(cursor, cx);
10192            let tab_size = if settings.hard_tabs {
10193                IndentSize::tab()
10194            } else {
10195                let tab_size = settings.tab_size.get();
10196                let indent_remainder = snapshot
10197                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10198                    .flat_map(str::chars)
10199                    .fold(row_delta % tab_size, |counter: u32, c| {
10200                        if c == '\t' {
10201                            0
10202                        } else {
10203                            (counter + 1) % tab_size
10204                        }
10205                    });
10206
10207                let chars_to_next_tab_stop = tab_size - indent_remainder;
10208                IndentSize::spaces(chars_to_next_tab_stop)
10209            };
10210            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10211            selection.end = selection.start;
10212            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10213            row_delta += tab_size.len;
10214        }
10215
10216        self.transact(window, cx, |this, window, cx| {
10217            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10218            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10219            this.refresh_edit_prediction(true, false, window, cx);
10220        });
10221    }
10222
10223    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10224        if self.read_only(cx) {
10225            return;
10226        }
10227        if self.mode.is_single_line() {
10228            cx.propagate();
10229            return;
10230        }
10231
10232        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10233        let mut selections = self.selections.all::<Point>(cx);
10234        let mut prev_edited_row = 0;
10235        let mut row_delta = 0;
10236        let mut edits = Vec::new();
10237        let buffer = self.buffer.read(cx);
10238        let snapshot = buffer.snapshot(cx);
10239        for selection in &mut selections {
10240            if selection.start.row != prev_edited_row {
10241                row_delta = 0;
10242            }
10243            prev_edited_row = selection.end.row;
10244
10245            row_delta =
10246                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10247        }
10248
10249        self.transact(window, cx, |this, window, cx| {
10250            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10251            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10252        });
10253    }
10254
10255    fn indent_selection(
10256        buffer: &MultiBuffer,
10257        snapshot: &MultiBufferSnapshot,
10258        selection: &mut Selection<Point>,
10259        edits: &mut Vec<(Range<Point>, String)>,
10260        delta_for_start_row: u32,
10261        cx: &App,
10262    ) -> u32 {
10263        let settings = buffer.language_settings_at(selection.start, cx);
10264        let tab_size = settings.tab_size.get();
10265        let indent_kind = if settings.hard_tabs {
10266            IndentKind::Tab
10267        } else {
10268            IndentKind::Space
10269        };
10270        let mut start_row = selection.start.row;
10271        let mut end_row = selection.end.row + 1;
10272
10273        // If a selection ends at the beginning of a line, don't indent
10274        // that last line.
10275        if selection.end.column == 0 && selection.end.row > selection.start.row {
10276            end_row -= 1;
10277        }
10278
10279        // Avoid re-indenting a row that has already been indented by a
10280        // previous selection, but still update this selection's column
10281        // to reflect that indentation.
10282        if delta_for_start_row > 0 {
10283            start_row += 1;
10284            selection.start.column += delta_for_start_row;
10285            if selection.end.row == selection.start.row {
10286                selection.end.column += delta_for_start_row;
10287            }
10288        }
10289
10290        let mut delta_for_end_row = 0;
10291        let has_multiple_rows = start_row + 1 != end_row;
10292        for row in start_row..end_row {
10293            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10294            let indent_delta = match (current_indent.kind, indent_kind) {
10295                (IndentKind::Space, IndentKind::Space) => {
10296                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10297                    IndentSize::spaces(columns_to_next_tab_stop)
10298                }
10299                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10300                (_, IndentKind::Tab) => IndentSize::tab(),
10301            };
10302
10303            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10304                0
10305            } else {
10306                selection.start.column
10307            };
10308            let row_start = Point::new(row, start);
10309            edits.push((
10310                row_start..row_start,
10311                indent_delta.chars().collect::<String>(),
10312            ));
10313
10314            // Update this selection's endpoints to reflect the indentation.
10315            if row == selection.start.row {
10316                selection.start.column += indent_delta.len;
10317            }
10318            if row == selection.end.row {
10319                selection.end.column += indent_delta.len;
10320                delta_for_end_row = indent_delta.len;
10321            }
10322        }
10323
10324        if selection.start.row == selection.end.row {
10325            delta_for_start_row + delta_for_end_row
10326        } else {
10327            delta_for_end_row
10328        }
10329    }
10330
10331    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10332        if self.read_only(cx) {
10333            return;
10334        }
10335        if self.mode.is_single_line() {
10336            cx.propagate();
10337            return;
10338        }
10339
10340        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10341        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10342        let selections = self.selections.all::<Point>(cx);
10343        let mut deletion_ranges = Vec::new();
10344        let mut last_outdent = None;
10345        {
10346            let buffer = self.buffer.read(cx);
10347            let snapshot = buffer.snapshot(cx);
10348            for selection in &selections {
10349                let settings = buffer.language_settings_at(selection.start, cx);
10350                let tab_size = settings.tab_size.get();
10351                let mut rows = selection.spanned_rows(false, &display_map);
10352
10353                // Avoid re-outdenting a row that has already been outdented by a
10354                // previous selection.
10355                if let Some(last_row) = last_outdent
10356                    && last_row == rows.start
10357                {
10358                    rows.start = rows.start.next_row();
10359                }
10360                let has_multiple_rows = rows.len() > 1;
10361                for row in rows.iter_rows() {
10362                    let indent_size = snapshot.indent_size_for_line(row);
10363                    if indent_size.len > 0 {
10364                        let deletion_len = match indent_size.kind {
10365                            IndentKind::Space => {
10366                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10367                                if columns_to_prev_tab_stop == 0 {
10368                                    tab_size
10369                                } else {
10370                                    columns_to_prev_tab_stop
10371                                }
10372                            }
10373                            IndentKind::Tab => 1,
10374                        };
10375                        let start = if has_multiple_rows
10376                            || deletion_len > selection.start.column
10377                            || indent_size.len < selection.start.column
10378                        {
10379                            0
10380                        } else {
10381                            selection.start.column - deletion_len
10382                        };
10383                        deletion_ranges.push(
10384                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10385                        );
10386                        last_outdent = Some(row);
10387                    }
10388                }
10389            }
10390        }
10391
10392        self.transact(window, cx, |this, window, cx| {
10393            this.buffer.update(cx, |buffer, cx| {
10394                let empty_str: Arc<str> = Arc::default();
10395                buffer.edit(
10396                    deletion_ranges
10397                        .into_iter()
10398                        .map(|range| (range, empty_str.clone())),
10399                    None,
10400                    cx,
10401                );
10402            });
10403            let selections = this.selections.all::<usize>(cx);
10404            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10405        });
10406    }
10407
10408    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10409        if self.read_only(cx) {
10410            return;
10411        }
10412        if self.mode.is_single_line() {
10413            cx.propagate();
10414            return;
10415        }
10416
10417        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10418        let selections = self
10419            .selections
10420            .all::<usize>(cx)
10421            .into_iter()
10422            .map(|s| s.range());
10423
10424        self.transact(window, cx, |this, window, cx| {
10425            this.buffer.update(cx, |buffer, cx| {
10426                buffer.autoindent_ranges(selections, cx);
10427            });
10428            let selections = this.selections.all::<usize>(cx);
10429            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10430        });
10431    }
10432
10433    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10434        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10435        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10436        let selections = self.selections.all::<Point>(cx);
10437
10438        let mut new_cursors = Vec::new();
10439        let mut edit_ranges = Vec::new();
10440        let mut selections = selections.iter().peekable();
10441        while let Some(selection) = selections.next() {
10442            let mut rows = selection.spanned_rows(false, &display_map);
10443            let goal_display_column = selection.head().to_display_point(&display_map).column();
10444
10445            // Accumulate contiguous regions of rows that we want to delete.
10446            while let Some(next_selection) = selections.peek() {
10447                let next_rows = next_selection.spanned_rows(false, &display_map);
10448                if next_rows.start <= rows.end {
10449                    rows.end = next_rows.end;
10450                    selections.next().unwrap();
10451                } else {
10452                    break;
10453                }
10454            }
10455
10456            let buffer = &display_map.buffer_snapshot;
10457            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10458            let edit_end;
10459            let cursor_buffer_row;
10460            if buffer.max_point().row >= rows.end.0 {
10461                // If there's a line after the range, delete the \n from the end of the row range
10462                // and position the cursor on the next line.
10463                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10464                cursor_buffer_row = rows.end;
10465            } else {
10466                // If there isn't a line after the range, delete the \n from the line before the
10467                // start of the row range and position the cursor there.
10468                edit_start = edit_start.saturating_sub(1);
10469                edit_end = buffer.len();
10470                cursor_buffer_row = rows.start.previous_row();
10471            }
10472
10473            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10474            *cursor.column_mut() =
10475                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10476
10477            new_cursors.push((
10478                selection.id,
10479                buffer.anchor_after(cursor.to_point(&display_map)),
10480            ));
10481            edit_ranges.push(edit_start..edit_end);
10482        }
10483
10484        self.transact(window, cx, |this, window, cx| {
10485            let buffer = this.buffer.update(cx, |buffer, cx| {
10486                let empty_str: Arc<str> = Arc::default();
10487                buffer.edit(
10488                    edit_ranges
10489                        .into_iter()
10490                        .map(|range| (range, empty_str.clone())),
10491                    None,
10492                    cx,
10493                );
10494                buffer.snapshot(cx)
10495            });
10496            let new_selections = new_cursors
10497                .into_iter()
10498                .map(|(id, cursor)| {
10499                    let cursor = cursor.to_point(&buffer);
10500                    Selection {
10501                        id,
10502                        start: cursor,
10503                        end: cursor,
10504                        reversed: false,
10505                        goal: SelectionGoal::None,
10506                    }
10507                })
10508                .collect();
10509
10510            this.change_selections(Default::default(), window, cx, |s| {
10511                s.select(new_selections);
10512            });
10513        });
10514    }
10515
10516    pub fn join_lines_impl(
10517        &mut self,
10518        insert_whitespace: bool,
10519        window: &mut Window,
10520        cx: &mut Context<Self>,
10521    ) {
10522        if self.read_only(cx) {
10523            return;
10524        }
10525        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10526        for selection in self.selections.all::<Point>(cx) {
10527            let start = MultiBufferRow(selection.start.row);
10528            // Treat single line selections as if they include the next line. Otherwise this action
10529            // would do nothing for single line selections individual cursors.
10530            let end = if selection.start.row == selection.end.row {
10531                MultiBufferRow(selection.start.row + 1)
10532            } else {
10533                MultiBufferRow(selection.end.row)
10534            };
10535
10536            if let Some(last_row_range) = row_ranges.last_mut()
10537                && start <= last_row_range.end
10538            {
10539                last_row_range.end = end;
10540                continue;
10541            }
10542            row_ranges.push(start..end);
10543        }
10544
10545        let snapshot = self.buffer.read(cx).snapshot(cx);
10546        let mut cursor_positions = Vec::new();
10547        for row_range in &row_ranges {
10548            let anchor = snapshot.anchor_before(Point::new(
10549                row_range.end.previous_row().0,
10550                snapshot.line_len(row_range.end.previous_row()),
10551            ));
10552            cursor_positions.push(anchor..anchor);
10553        }
10554
10555        self.transact(window, cx, |this, window, cx| {
10556            for row_range in row_ranges.into_iter().rev() {
10557                for row in row_range.iter_rows().rev() {
10558                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10559                    let next_line_row = row.next_row();
10560                    let indent = snapshot.indent_size_for_line(next_line_row);
10561                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10562
10563                    let replace =
10564                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10565                            " "
10566                        } else {
10567                            ""
10568                        };
10569
10570                    this.buffer.update(cx, |buffer, cx| {
10571                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10572                    });
10573                }
10574            }
10575
10576            this.change_selections(Default::default(), window, cx, |s| {
10577                s.select_anchor_ranges(cursor_positions)
10578            });
10579        });
10580    }
10581
10582    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10583        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10584        self.join_lines_impl(true, window, cx);
10585    }
10586
10587    pub fn sort_lines_case_sensitive(
10588        &mut self,
10589        _: &SortLinesCaseSensitive,
10590        window: &mut Window,
10591        cx: &mut Context<Self>,
10592    ) {
10593        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10594    }
10595
10596    pub fn sort_lines_by_length(
10597        &mut self,
10598        _: &SortLinesByLength,
10599        window: &mut Window,
10600        cx: &mut Context<Self>,
10601    ) {
10602        self.manipulate_immutable_lines(window, cx, |lines| {
10603            lines.sort_by_key(|&line| line.chars().count())
10604        })
10605    }
10606
10607    pub fn sort_lines_case_insensitive(
10608        &mut self,
10609        _: &SortLinesCaseInsensitive,
10610        window: &mut Window,
10611        cx: &mut Context<Self>,
10612    ) {
10613        self.manipulate_immutable_lines(window, cx, |lines| {
10614            lines.sort_by_key(|line| line.to_lowercase())
10615        })
10616    }
10617
10618    pub fn unique_lines_case_insensitive(
10619        &mut self,
10620        _: &UniqueLinesCaseInsensitive,
10621        window: &mut Window,
10622        cx: &mut Context<Self>,
10623    ) {
10624        self.manipulate_immutable_lines(window, cx, |lines| {
10625            let mut seen = HashSet::default();
10626            lines.retain(|line| seen.insert(line.to_lowercase()));
10627        })
10628    }
10629
10630    pub fn unique_lines_case_sensitive(
10631        &mut self,
10632        _: &UniqueLinesCaseSensitive,
10633        window: &mut Window,
10634        cx: &mut Context<Self>,
10635    ) {
10636        self.manipulate_immutable_lines(window, cx, |lines| {
10637            let mut seen = HashSet::default();
10638            lines.retain(|line| seen.insert(*line));
10639        })
10640    }
10641
10642    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10643        let snapshot = self.buffer.read(cx).snapshot(cx);
10644        for selection in self.selections.disjoint_anchors_arc().iter() {
10645            if snapshot
10646                .language_at(selection.start)
10647                .and_then(|lang| lang.config().wrap_characters.as_ref())
10648                .is_some()
10649            {
10650                return true;
10651            }
10652        }
10653        false
10654    }
10655
10656    fn wrap_selections_in_tag(
10657        &mut self,
10658        _: &WrapSelectionsInTag,
10659        window: &mut Window,
10660        cx: &mut Context<Self>,
10661    ) {
10662        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10663
10664        let snapshot = self.buffer.read(cx).snapshot(cx);
10665
10666        let mut edits = Vec::new();
10667        let mut boundaries = Vec::new();
10668
10669        for selection in self.selections.all::<Point>(cx).iter() {
10670            let Some(wrap_config) = snapshot
10671                .language_at(selection.start)
10672                .and_then(|lang| lang.config().wrap_characters.clone())
10673            else {
10674                continue;
10675            };
10676
10677            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10678            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10679
10680            let start_before = snapshot.anchor_before(selection.start);
10681            let end_after = snapshot.anchor_after(selection.end);
10682
10683            edits.push((start_before..start_before, open_tag));
10684            edits.push((end_after..end_after, close_tag));
10685
10686            boundaries.push((
10687                start_before,
10688                end_after,
10689                wrap_config.start_prefix.len(),
10690                wrap_config.end_suffix.len(),
10691            ));
10692        }
10693
10694        if edits.is_empty() {
10695            return;
10696        }
10697
10698        self.transact(window, cx, |this, window, cx| {
10699            let buffer = this.buffer.update(cx, |buffer, cx| {
10700                buffer.edit(edits, None, cx);
10701                buffer.snapshot(cx)
10702            });
10703
10704            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10705            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10706                boundaries.into_iter()
10707            {
10708                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10709                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10710                new_selections.push(open_offset..open_offset);
10711                new_selections.push(close_offset..close_offset);
10712            }
10713
10714            this.change_selections(Default::default(), window, cx, |s| {
10715                s.select_ranges(new_selections);
10716            });
10717
10718            this.request_autoscroll(Autoscroll::fit(), cx);
10719        });
10720    }
10721
10722    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10723        let Some(project) = self.project.clone() else {
10724            return;
10725        };
10726        self.reload(project, window, cx)
10727            .detach_and_notify_err(window, cx);
10728    }
10729
10730    pub fn restore_file(
10731        &mut self,
10732        _: &::git::RestoreFile,
10733        window: &mut Window,
10734        cx: &mut Context<Self>,
10735    ) {
10736        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10737        let mut buffer_ids = HashSet::default();
10738        let snapshot = self.buffer().read(cx).snapshot(cx);
10739        for selection in self.selections.all::<usize>(cx) {
10740            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10741        }
10742
10743        let buffer = self.buffer().read(cx);
10744        let ranges = buffer_ids
10745            .into_iter()
10746            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10747            .collect::<Vec<_>>();
10748
10749        self.restore_hunks_in_ranges(ranges, window, cx);
10750    }
10751
10752    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10753        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10754        let selections = self
10755            .selections
10756            .all(cx)
10757            .into_iter()
10758            .map(|s| s.range())
10759            .collect();
10760        self.restore_hunks_in_ranges(selections, window, cx);
10761    }
10762
10763    pub fn restore_hunks_in_ranges(
10764        &mut self,
10765        ranges: Vec<Range<Point>>,
10766        window: &mut Window,
10767        cx: &mut Context<Editor>,
10768    ) {
10769        let mut revert_changes = HashMap::default();
10770        let chunk_by = self
10771            .snapshot(window, cx)
10772            .hunks_for_ranges(ranges)
10773            .into_iter()
10774            .chunk_by(|hunk| hunk.buffer_id);
10775        for (buffer_id, hunks) in &chunk_by {
10776            let hunks = hunks.collect::<Vec<_>>();
10777            for hunk in &hunks {
10778                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10779            }
10780            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10781        }
10782        drop(chunk_by);
10783        if !revert_changes.is_empty() {
10784            self.transact(window, cx, |editor, window, cx| {
10785                editor.restore(revert_changes, window, cx);
10786            });
10787        }
10788    }
10789
10790    pub fn open_active_item_in_terminal(
10791        &mut self,
10792        _: &OpenInTerminal,
10793        window: &mut Window,
10794        cx: &mut Context<Self>,
10795    ) {
10796        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10797            let project_path = buffer.read(cx).project_path(cx)?;
10798            let project = self.project()?.read(cx);
10799            let entry = project.entry_for_path(&project_path, cx)?;
10800            let parent = match &entry.canonical_path {
10801                Some(canonical_path) => canonical_path.to_path_buf(),
10802                None => project.absolute_path(&project_path, cx)?,
10803            }
10804            .parent()?
10805            .to_path_buf();
10806            Some(parent)
10807        }) {
10808            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10809        }
10810    }
10811
10812    fn set_breakpoint_context_menu(
10813        &mut self,
10814        display_row: DisplayRow,
10815        position: Option<Anchor>,
10816        clicked_point: gpui::Point<Pixels>,
10817        window: &mut Window,
10818        cx: &mut Context<Self>,
10819    ) {
10820        let source = self
10821            .buffer
10822            .read(cx)
10823            .snapshot(cx)
10824            .anchor_before(Point::new(display_row.0, 0u32));
10825
10826        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10827
10828        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10829            self,
10830            source,
10831            clicked_point,
10832            context_menu,
10833            window,
10834            cx,
10835        );
10836    }
10837
10838    fn add_edit_breakpoint_block(
10839        &mut self,
10840        anchor: Anchor,
10841        breakpoint: &Breakpoint,
10842        edit_action: BreakpointPromptEditAction,
10843        window: &mut Window,
10844        cx: &mut Context<Self>,
10845    ) {
10846        let weak_editor = cx.weak_entity();
10847        let bp_prompt = cx.new(|cx| {
10848            BreakpointPromptEditor::new(
10849                weak_editor,
10850                anchor,
10851                breakpoint.clone(),
10852                edit_action,
10853                window,
10854                cx,
10855            )
10856        });
10857
10858        let height = bp_prompt.update(cx, |this, cx| {
10859            this.prompt
10860                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10861        });
10862        let cloned_prompt = bp_prompt.clone();
10863        let blocks = vec![BlockProperties {
10864            style: BlockStyle::Sticky,
10865            placement: BlockPlacement::Above(anchor),
10866            height: Some(height),
10867            render: Arc::new(move |cx| {
10868                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10869                cloned_prompt.clone().into_any_element()
10870            }),
10871            priority: 0,
10872        }];
10873
10874        let focus_handle = bp_prompt.focus_handle(cx);
10875        window.focus(&focus_handle);
10876
10877        let block_ids = self.insert_blocks(blocks, None, cx);
10878        bp_prompt.update(cx, |prompt, _| {
10879            prompt.add_block_ids(block_ids);
10880        });
10881    }
10882
10883    pub(crate) fn breakpoint_at_row(
10884        &self,
10885        row: u32,
10886        window: &mut Window,
10887        cx: &mut Context<Self>,
10888    ) -> Option<(Anchor, Breakpoint)> {
10889        let snapshot = self.snapshot(window, cx);
10890        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10891
10892        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10893    }
10894
10895    pub(crate) fn breakpoint_at_anchor(
10896        &self,
10897        breakpoint_position: Anchor,
10898        snapshot: &EditorSnapshot,
10899        cx: &mut Context<Self>,
10900    ) -> Option<(Anchor, Breakpoint)> {
10901        let buffer = self
10902            .buffer
10903            .read(cx)
10904            .buffer_for_anchor(breakpoint_position, cx)?;
10905
10906        let enclosing_excerpt = breakpoint_position.excerpt_id;
10907        let buffer_snapshot = buffer.read(cx).snapshot();
10908
10909        let row = buffer_snapshot
10910            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10911            .row;
10912
10913        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10914        let anchor_end = snapshot
10915            .buffer_snapshot
10916            .anchor_after(Point::new(row, line_len));
10917
10918        self.breakpoint_store
10919            .as_ref()?
10920            .read_with(cx, |breakpoint_store, cx| {
10921                breakpoint_store
10922                    .breakpoints(
10923                        &buffer,
10924                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10925                        &buffer_snapshot,
10926                        cx,
10927                    )
10928                    .next()
10929                    .and_then(|(bp, _)| {
10930                        let breakpoint_row = buffer_snapshot
10931                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10932                            .row;
10933
10934                        if breakpoint_row == row {
10935                            snapshot
10936                                .buffer_snapshot
10937                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10938                                .map(|position| (position, bp.bp.clone()))
10939                        } else {
10940                            None
10941                        }
10942                    })
10943            })
10944    }
10945
10946    pub fn edit_log_breakpoint(
10947        &mut self,
10948        _: &EditLogBreakpoint,
10949        window: &mut Window,
10950        cx: &mut Context<Self>,
10951    ) {
10952        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10953            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10954                message: None,
10955                state: BreakpointState::Enabled,
10956                condition: None,
10957                hit_condition: None,
10958            });
10959
10960            self.add_edit_breakpoint_block(
10961                anchor,
10962                &breakpoint,
10963                BreakpointPromptEditAction::Log,
10964                window,
10965                cx,
10966            );
10967        }
10968    }
10969
10970    fn breakpoints_at_cursors(
10971        &self,
10972        window: &mut Window,
10973        cx: &mut Context<Self>,
10974    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10975        let snapshot = self.snapshot(window, cx);
10976        let cursors = self
10977            .selections
10978            .disjoint_anchors_arc()
10979            .iter()
10980            .map(|selection| {
10981                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10982
10983                let breakpoint_position = self
10984                    .breakpoint_at_row(cursor_position.row, window, cx)
10985                    .map(|bp| bp.0)
10986                    .unwrap_or_else(|| {
10987                        snapshot
10988                            .display_snapshot
10989                            .buffer_snapshot
10990                            .anchor_after(Point::new(cursor_position.row, 0))
10991                    });
10992
10993                let breakpoint = self
10994                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10995                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10996
10997                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10998            })
10999            // 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.
11000            .collect::<HashMap<Anchor, _>>();
11001
11002        cursors.into_iter().collect()
11003    }
11004
11005    pub fn enable_breakpoint(
11006        &mut self,
11007        _: &crate::actions::EnableBreakpoint,
11008        window: &mut Window,
11009        cx: &mut Context<Self>,
11010    ) {
11011        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11012            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11013                continue;
11014            };
11015            self.edit_breakpoint_at_anchor(
11016                anchor,
11017                breakpoint,
11018                BreakpointEditAction::InvertState,
11019                cx,
11020            );
11021        }
11022    }
11023
11024    pub fn disable_breakpoint(
11025        &mut self,
11026        _: &crate::actions::DisableBreakpoint,
11027        window: &mut Window,
11028        cx: &mut Context<Self>,
11029    ) {
11030        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11031            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11032                continue;
11033            };
11034            self.edit_breakpoint_at_anchor(
11035                anchor,
11036                breakpoint,
11037                BreakpointEditAction::InvertState,
11038                cx,
11039            );
11040        }
11041    }
11042
11043    pub fn toggle_breakpoint(
11044        &mut self,
11045        _: &crate::actions::ToggleBreakpoint,
11046        window: &mut Window,
11047        cx: &mut Context<Self>,
11048    ) {
11049        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11050            if let Some(breakpoint) = breakpoint {
11051                self.edit_breakpoint_at_anchor(
11052                    anchor,
11053                    breakpoint,
11054                    BreakpointEditAction::Toggle,
11055                    cx,
11056                );
11057            } else {
11058                self.edit_breakpoint_at_anchor(
11059                    anchor,
11060                    Breakpoint::new_standard(),
11061                    BreakpointEditAction::Toggle,
11062                    cx,
11063                );
11064            }
11065        }
11066    }
11067
11068    pub fn edit_breakpoint_at_anchor(
11069        &mut self,
11070        breakpoint_position: Anchor,
11071        breakpoint: Breakpoint,
11072        edit_action: BreakpointEditAction,
11073        cx: &mut Context<Self>,
11074    ) {
11075        let Some(breakpoint_store) = &self.breakpoint_store else {
11076            return;
11077        };
11078
11079        let Some(buffer) = self
11080            .buffer
11081            .read(cx)
11082            .buffer_for_anchor(breakpoint_position, cx)
11083        else {
11084            return;
11085        };
11086
11087        breakpoint_store.update(cx, |breakpoint_store, cx| {
11088            breakpoint_store.toggle_breakpoint(
11089                buffer,
11090                BreakpointWithPosition {
11091                    position: breakpoint_position.text_anchor,
11092                    bp: breakpoint,
11093                },
11094                edit_action,
11095                cx,
11096            );
11097        });
11098
11099        cx.notify();
11100    }
11101
11102    #[cfg(any(test, feature = "test-support"))]
11103    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11104        self.breakpoint_store.clone()
11105    }
11106
11107    pub fn prepare_restore_change(
11108        &self,
11109        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11110        hunk: &MultiBufferDiffHunk,
11111        cx: &mut App,
11112    ) -> Option<()> {
11113        if hunk.is_created_file() {
11114            return None;
11115        }
11116        let buffer = self.buffer.read(cx);
11117        let diff = buffer.diff_for(hunk.buffer_id)?;
11118        let buffer = buffer.buffer(hunk.buffer_id)?;
11119        let buffer = buffer.read(cx);
11120        let original_text = diff
11121            .read(cx)
11122            .base_text()
11123            .as_rope()
11124            .slice(hunk.diff_base_byte_range.clone());
11125        let buffer_snapshot = buffer.snapshot();
11126        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11127        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11128            probe
11129                .0
11130                .start
11131                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11132                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11133        }) {
11134            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11135            Some(())
11136        } else {
11137            None
11138        }
11139    }
11140
11141    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11142        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11143    }
11144
11145    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11146        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11147    }
11148
11149    fn manipulate_lines<M>(
11150        &mut self,
11151        window: &mut Window,
11152        cx: &mut Context<Self>,
11153        mut manipulate: M,
11154    ) where
11155        M: FnMut(&str) -> LineManipulationResult,
11156    {
11157        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11158
11159        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11160        let buffer = self.buffer.read(cx).snapshot(cx);
11161
11162        let mut edits = Vec::new();
11163
11164        let selections = self.selections.all::<Point>(cx);
11165        let mut selections = selections.iter().peekable();
11166        let mut contiguous_row_selections = Vec::new();
11167        let mut new_selections = Vec::new();
11168        let mut added_lines = 0;
11169        let mut removed_lines = 0;
11170
11171        while let Some(selection) = selections.next() {
11172            let (start_row, end_row) = consume_contiguous_rows(
11173                &mut contiguous_row_selections,
11174                selection,
11175                &display_map,
11176                &mut selections,
11177            );
11178
11179            let start_point = Point::new(start_row.0, 0);
11180            let end_point = Point::new(
11181                end_row.previous_row().0,
11182                buffer.line_len(end_row.previous_row()),
11183            );
11184            let text = buffer
11185                .text_for_range(start_point..end_point)
11186                .collect::<String>();
11187
11188            let LineManipulationResult {
11189                new_text,
11190                line_count_before,
11191                line_count_after,
11192            } = manipulate(&text);
11193
11194            edits.push((start_point..end_point, new_text));
11195
11196            // Selections must change based on added and removed line count
11197            let start_row =
11198                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11199            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11200            new_selections.push(Selection {
11201                id: selection.id,
11202                start: start_row,
11203                end: end_row,
11204                goal: SelectionGoal::None,
11205                reversed: selection.reversed,
11206            });
11207
11208            if line_count_after > line_count_before {
11209                added_lines += line_count_after - line_count_before;
11210            } else if line_count_before > line_count_after {
11211                removed_lines += line_count_before - line_count_after;
11212            }
11213        }
11214
11215        self.transact(window, cx, |this, window, cx| {
11216            let buffer = this.buffer.update(cx, |buffer, cx| {
11217                buffer.edit(edits, None, cx);
11218                buffer.snapshot(cx)
11219            });
11220
11221            // Recalculate offsets on newly edited buffer
11222            let new_selections = new_selections
11223                .iter()
11224                .map(|s| {
11225                    let start_point = Point::new(s.start.0, 0);
11226                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11227                    Selection {
11228                        id: s.id,
11229                        start: buffer.point_to_offset(start_point),
11230                        end: buffer.point_to_offset(end_point),
11231                        goal: s.goal,
11232                        reversed: s.reversed,
11233                    }
11234                })
11235                .collect();
11236
11237            this.change_selections(Default::default(), window, cx, |s| {
11238                s.select(new_selections);
11239            });
11240
11241            this.request_autoscroll(Autoscroll::fit(), cx);
11242        });
11243    }
11244
11245    fn manipulate_immutable_lines<Fn>(
11246        &mut self,
11247        window: &mut Window,
11248        cx: &mut Context<Self>,
11249        mut callback: Fn,
11250    ) where
11251        Fn: FnMut(&mut Vec<&str>),
11252    {
11253        self.manipulate_lines(window, cx, |text| {
11254            let mut lines: Vec<&str> = text.split('\n').collect();
11255            let line_count_before = lines.len();
11256
11257            callback(&mut lines);
11258
11259            LineManipulationResult {
11260                new_text: lines.join("\n"),
11261                line_count_before,
11262                line_count_after: lines.len(),
11263            }
11264        });
11265    }
11266
11267    fn manipulate_mutable_lines<Fn>(
11268        &mut self,
11269        window: &mut Window,
11270        cx: &mut Context<Self>,
11271        mut callback: Fn,
11272    ) where
11273        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11274    {
11275        self.manipulate_lines(window, cx, |text| {
11276            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11277            let line_count_before = lines.len();
11278
11279            callback(&mut lines);
11280
11281            LineManipulationResult {
11282                new_text: lines.join("\n"),
11283                line_count_before,
11284                line_count_after: lines.len(),
11285            }
11286        });
11287    }
11288
11289    pub fn convert_indentation_to_spaces(
11290        &mut self,
11291        _: &ConvertIndentationToSpaces,
11292        window: &mut Window,
11293        cx: &mut Context<Self>,
11294    ) {
11295        let settings = self.buffer.read(cx).language_settings(cx);
11296        let tab_size = settings.tab_size.get() as usize;
11297
11298        self.manipulate_mutable_lines(window, cx, |lines| {
11299            // Allocates a reasonably sized scratch buffer once for the whole loop
11300            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11301            // Avoids recomputing spaces that could be inserted many times
11302            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11303                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11304                .collect();
11305
11306            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11307                let mut chars = line.as_ref().chars();
11308                let mut col = 0;
11309                let mut changed = false;
11310
11311                for ch in chars.by_ref() {
11312                    match ch {
11313                        ' ' => {
11314                            reindented_line.push(' ');
11315                            col += 1;
11316                        }
11317                        '\t' => {
11318                            // \t are converted to spaces depending on the current column
11319                            let spaces_len = tab_size - (col % tab_size);
11320                            reindented_line.extend(&space_cache[spaces_len - 1]);
11321                            col += spaces_len;
11322                            changed = true;
11323                        }
11324                        _ => {
11325                            // If we dont append before break, the character is consumed
11326                            reindented_line.push(ch);
11327                            break;
11328                        }
11329                    }
11330                }
11331
11332                if !changed {
11333                    reindented_line.clear();
11334                    continue;
11335                }
11336                // Append the rest of the line and replace old reference with new one
11337                reindented_line.extend(chars);
11338                *line = Cow::Owned(reindented_line.clone());
11339                reindented_line.clear();
11340            }
11341        });
11342    }
11343
11344    pub fn convert_indentation_to_tabs(
11345        &mut self,
11346        _: &ConvertIndentationToTabs,
11347        window: &mut Window,
11348        cx: &mut Context<Self>,
11349    ) {
11350        let settings = self.buffer.read(cx).language_settings(cx);
11351        let tab_size = settings.tab_size.get() as usize;
11352
11353        self.manipulate_mutable_lines(window, cx, |lines| {
11354            // Allocates a reasonably sized buffer once for the whole loop
11355            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11356            // Avoids recomputing spaces that could be inserted many times
11357            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11358                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11359                .collect();
11360
11361            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11362                let mut chars = line.chars();
11363                let mut spaces_count = 0;
11364                let mut first_non_indent_char = None;
11365                let mut changed = false;
11366
11367                for ch in chars.by_ref() {
11368                    match ch {
11369                        ' ' => {
11370                            // Keep track of spaces. Append \t when we reach tab_size
11371                            spaces_count += 1;
11372                            changed = true;
11373                            if spaces_count == tab_size {
11374                                reindented_line.push('\t');
11375                                spaces_count = 0;
11376                            }
11377                        }
11378                        '\t' => {
11379                            reindented_line.push('\t');
11380                            spaces_count = 0;
11381                        }
11382                        _ => {
11383                            // Dont append it yet, we might have remaining spaces
11384                            first_non_indent_char = Some(ch);
11385                            break;
11386                        }
11387                    }
11388                }
11389
11390                if !changed {
11391                    reindented_line.clear();
11392                    continue;
11393                }
11394                // Remaining spaces that didn't make a full tab stop
11395                if spaces_count > 0 {
11396                    reindented_line.extend(&space_cache[spaces_count - 1]);
11397                }
11398                // If we consume an extra character that was not indentation, add it back
11399                if let Some(extra_char) = first_non_indent_char {
11400                    reindented_line.push(extra_char);
11401                }
11402                // Append the rest of the line and replace old reference with new one
11403                reindented_line.extend(chars);
11404                *line = Cow::Owned(reindented_line.clone());
11405                reindented_line.clear();
11406            }
11407        });
11408    }
11409
11410    pub fn convert_to_upper_case(
11411        &mut self,
11412        _: &ConvertToUpperCase,
11413        window: &mut Window,
11414        cx: &mut Context<Self>,
11415    ) {
11416        self.manipulate_text(window, cx, |text| text.to_uppercase())
11417    }
11418
11419    pub fn convert_to_lower_case(
11420        &mut self,
11421        _: &ConvertToLowerCase,
11422        window: &mut Window,
11423        cx: &mut Context<Self>,
11424    ) {
11425        self.manipulate_text(window, cx, |text| text.to_lowercase())
11426    }
11427
11428    pub fn convert_to_title_case(
11429        &mut self,
11430        _: &ConvertToTitleCase,
11431        window: &mut Window,
11432        cx: &mut Context<Self>,
11433    ) {
11434        self.manipulate_text(window, cx, |text| {
11435            text.split('\n')
11436                .map(|line| line.to_case(Case::Title))
11437                .join("\n")
11438        })
11439    }
11440
11441    pub fn convert_to_snake_case(
11442        &mut self,
11443        _: &ConvertToSnakeCase,
11444        window: &mut Window,
11445        cx: &mut Context<Self>,
11446    ) {
11447        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11448    }
11449
11450    pub fn convert_to_kebab_case(
11451        &mut self,
11452        _: &ConvertToKebabCase,
11453        window: &mut Window,
11454        cx: &mut Context<Self>,
11455    ) {
11456        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11457    }
11458
11459    pub fn convert_to_upper_camel_case(
11460        &mut self,
11461        _: &ConvertToUpperCamelCase,
11462        window: &mut Window,
11463        cx: &mut Context<Self>,
11464    ) {
11465        self.manipulate_text(window, cx, |text| {
11466            text.split('\n')
11467                .map(|line| line.to_case(Case::UpperCamel))
11468                .join("\n")
11469        })
11470    }
11471
11472    pub fn convert_to_lower_camel_case(
11473        &mut self,
11474        _: &ConvertToLowerCamelCase,
11475        window: &mut Window,
11476        cx: &mut Context<Self>,
11477    ) {
11478        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11479    }
11480
11481    pub fn convert_to_opposite_case(
11482        &mut self,
11483        _: &ConvertToOppositeCase,
11484        window: &mut Window,
11485        cx: &mut Context<Self>,
11486    ) {
11487        self.manipulate_text(window, cx, |text| {
11488            text.chars()
11489                .fold(String::with_capacity(text.len()), |mut t, c| {
11490                    if c.is_uppercase() {
11491                        t.extend(c.to_lowercase());
11492                    } else {
11493                        t.extend(c.to_uppercase());
11494                    }
11495                    t
11496                })
11497        })
11498    }
11499
11500    pub fn convert_to_sentence_case(
11501        &mut self,
11502        _: &ConvertToSentenceCase,
11503        window: &mut Window,
11504        cx: &mut Context<Self>,
11505    ) {
11506        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11507    }
11508
11509    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11510        self.manipulate_text(window, cx, |text| {
11511            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11512            if has_upper_case_characters {
11513                text.to_lowercase()
11514            } else {
11515                text.to_uppercase()
11516            }
11517        })
11518    }
11519
11520    pub fn convert_to_rot13(
11521        &mut self,
11522        _: &ConvertToRot13,
11523        window: &mut Window,
11524        cx: &mut Context<Self>,
11525    ) {
11526        self.manipulate_text(window, cx, |text| {
11527            text.chars()
11528                .map(|c| match c {
11529                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11530                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11531                    _ => c,
11532                })
11533                .collect()
11534        })
11535    }
11536
11537    pub fn convert_to_rot47(
11538        &mut self,
11539        _: &ConvertToRot47,
11540        window: &mut Window,
11541        cx: &mut Context<Self>,
11542    ) {
11543        self.manipulate_text(window, cx, |text| {
11544            text.chars()
11545                .map(|c| {
11546                    let code_point = c as u32;
11547                    if code_point >= 33 && code_point <= 126 {
11548                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11549                    }
11550                    c
11551                })
11552                .collect()
11553        })
11554    }
11555
11556    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11557    where
11558        Fn: FnMut(&str) -> String,
11559    {
11560        let buffer = self.buffer.read(cx).snapshot(cx);
11561
11562        let mut new_selections = Vec::new();
11563        let mut edits = Vec::new();
11564        let mut selection_adjustment = 0i32;
11565
11566        for selection in self.selections.all_adjusted(cx) {
11567            let selection_is_empty = selection.is_empty();
11568
11569            let (start, end) = if selection_is_empty {
11570                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11571                (word_range.start, word_range.end)
11572            } else {
11573                (
11574                    buffer.point_to_offset(selection.start),
11575                    buffer.point_to_offset(selection.end),
11576                )
11577            };
11578
11579            let text = buffer.text_for_range(start..end).collect::<String>();
11580            let old_length = text.len() as i32;
11581            let text = callback(&text);
11582
11583            new_selections.push(Selection {
11584                start: (start as i32 - selection_adjustment) as usize,
11585                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11586                goal: SelectionGoal::None,
11587                id: selection.id,
11588                reversed: selection.reversed,
11589            });
11590
11591            selection_adjustment += old_length - text.len() as i32;
11592
11593            edits.push((start..end, text));
11594        }
11595
11596        self.transact(window, cx, |this, window, cx| {
11597            this.buffer.update(cx, |buffer, cx| {
11598                buffer.edit(edits, None, cx);
11599            });
11600
11601            this.change_selections(Default::default(), window, cx, |s| {
11602                s.select(new_selections);
11603            });
11604
11605            this.request_autoscroll(Autoscroll::fit(), cx);
11606        });
11607    }
11608
11609    pub fn move_selection_on_drop(
11610        &mut self,
11611        selection: &Selection<Anchor>,
11612        target: DisplayPoint,
11613        is_cut: bool,
11614        window: &mut Window,
11615        cx: &mut Context<Self>,
11616    ) {
11617        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11618        let buffer = &display_map.buffer_snapshot;
11619        let mut edits = Vec::new();
11620        let insert_point = display_map
11621            .clip_point(target, Bias::Left)
11622            .to_point(&display_map);
11623        let text = buffer
11624            .text_for_range(selection.start..selection.end)
11625            .collect::<String>();
11626        if is_cut {
11627            edits.push(((selection.start..selection.end), String::new()));
11628        }
11629        let insert_anchor = buffer.anchor_before(insert_point);
11630        edits.push(((insert_anchor..insert_anchor), text));
11631        let last_edit_start = insert_anchor.bias_left(buffer);
11632        let last_edit_end = insert_anchor.bias_right(buffer);
11633        self.transact(window, cx, |this, window, cx| {
11634            this.buffer.update(cx, |buffer, cx| {
11635                buffer.edit(edits, None, cx);
11636            });
11637            this.change_selections(Default::default(), window, cx, |s| {
11638                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11639            });
11640        });
11641    }
11642
11643    pub fn clear_selection_drag_state(&mut self) {
11644        self.selection_drag_state = SelectionDragState::None;
11645    }
11646
11647    pub fn duplicate(
11648        &mut self,
11649        upwards: bool,
11650        whole_lines: bool,
11651        window: &mut Window,
11652        cx: &mut Context<Self>,
11653    ) {
11654        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11655
11656        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11657        let buffer = &display_map.buffer_snapshot;
11658        let selections = self.selections.all::<Point>(cx);
11659
11660        let mut edits = Vec::new();
11661        let mut selections_iter = selections.iter().peekable();
11662        while let Some(selection) = selections_iter.next() {
11663            let mut rows = selection.spanned_rows(false, &display_map);
11664            // duplicate line-wise
11665            if whole_lines || selection.start == selection.end {
11666                // Avoid duplicating the same lines twice.
11667                while let Some(next_selection) = selections_iter.peek() {
11668                    let next_rows = next_selection.spanned_rows(false, &display_map);
11669                    if next_rows.start < rows.end {
11670                        rows.end = next_rows.end;
11671                        selections_iter.next().unwrap();
11672                    } else {
11673                        break;
11674                    }
11675                }
11676
11677                // Copy the text from the selected row region and splice it either at the start
11678                // or end of the region.
11679                let start = Point::new(rows.start.0, 0);
11680                let end = Point::new(
11681                    rows.end.previous_row().0,
11682                    buffer.line_len(rows.end.previous_row()),
11683                );
11684                let text = buffer
11685                    .text_for_range(start..end)
11686                    .chain(Some("\n"))
11687                    .collect::<String>();
11688                let insert_location = if upwards {
11689                    Point::new(rows.end.0, 0)
11690                } else {
11691                    start
11692                };
11693                edits.push((insert_location..insert_location, text));
11694            } else {
11695                // duplicate character-wise
11696                let start = selection.start;
11697                let end = selection.end;
11698                let text = buffer.text_for_range(start..end).collect::<String>();
11699                edits.push((selection.end..selection.end, text));
11700            }
11701        }
11702
11703        self.transact(window, cx, |this, _, cx| {
11704            this.buffer.update(cx, |buffer, cx| {
11705                buffer.edit(edits, None, cx);
11706            });
11707
11708            this.request_autoscroll(Autoscroll::fit(), cx);
11709        });
11710    }
11711
11712    pub fn duplicate_line_up(
11713        &mut self,
11714        _: &DuplicateLineUp,
11715        window: &mut Window,
11716        cx: &mut Context<Self>,
11717    ) {
11718        self.duplicate(true, true, window, cx);
11719    }
11720
11721    pub fn duplicate_line_down(
11722        &mut self,
11723        _: &DuplicateLineDown,
11724        window: &mut Window,
11725        cx: &mut Context<Self>,
11726    ) {
11727        self.duplicate(false, true, window, cx);
11728    }
11729
11730    pub fn duplicate_selection(
11731        &mut self,
11732        _: &DuplicateSelection,
11733        window: &mut Window,
11734        cx: &mut Context<Self>,
11735    ) {
11736        self.duplicate(false, false, window, cx);
11737    }
11738
11739    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11741        if self.mode.is_single_line() {
11742            cx.propagate();
11743            return;
11744        }
11745
11746        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11747        let buffer = self.buffer.read(cx).snapshot(cx);
11748
11749        let mut edits = Vec::new();
11750        let mut unfold_ranges = Vec::new();
11751        let mut refold_creases = Vec::new();
11752
11753        let selections = self.selections.all::<Point>(cx);
11754        let mut selections = selections.iter().peekable();
11755        let mut contiguous_row_selections = Vec::new();
11756        let mut new_selections = Vec::new();
11757
11758        while let Some(selection) = selections.next() {
11759            // Find all the selections that span a contiguous row range
11760            let (start_row, end_row) = consume_contiguous_rows(
11761                &mut contiguous_row_selections,
11762                selection,
11763                &display_map,
11764                &mut selections,
11765            );
11766
11767            // Move the text spanned by the row range to be before the line preceding the row range
11768            if start_row.0 > 0 {
11769                let range_to_move = Point::new(
11770                    start_row.previous_row().0,
11771                    buffer.line_len(start_row.previous_row()),
11772                )
11773                    ..Point::new(
11774                        end_row.previous_row().0,
11775                        buffer.line_len(end_row.previous_row()),
11776                    );
11777                let insertion_point = display_map
11778                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11779                    .0;
11780
11781                // Don't move lines across excerpts
11782                if buffer
11783                    .excerpt_containing(insertion_point..range_to_move.end)
11784                    .is_some()
11785                {
11786                    let text = buffer
11787                        .text_for_range(range_to_move.clone())
11788                        .flat_map(|s| s.chars())
11789                        .skip(1)
11790                        .chain(['\n'])
11791                        .collect::<String>();
11792
11793                    edits.push((
11794                        buffer.anchor_after(range_to_move.start)
11795                            ..buffer.anchor_before(range_to_move.end),
11796                        String::new(),
11797                    ));
11798                    let insertion_anchor = buffer.anchor_after(insertion_point);
11799                    edits.push((insertion_anchor..insertion_anchor, text));
11800
11801                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11802
11803                    // Move selections up
11804                    new_selections.extend(contiguous_row_selections.drain(..).map(
11805                        |mut selection| {
11806                            selection.start.row -= row_delta;
11807                            selection.end.row -= row_delta;
11808                            selection
11809                        },
11810                    ));
11811
11812                    // Move folds up
11813                    unfold_ranges.push(range_to_move.clone());
11814                    for fold in display_map.folds_in_range(
11815                        buffer.anchor_before(range_to_move.start)
11816                            ..buffer.anchor_after(range_to_move.end),
11817                    ) {
11818                        let mut start = fold.range.start.to_point(&buffer);
11819                        let mut end = fold.range.end.to_point(&buffer);
11820                        start.row -= row_delta;
11821                        end.row -= row_delta;
11822                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11823                    }
11824                }
11825            }
11826
11827            // If we didn't move line(s), preserve the existing selections
11828            new_selections.append(&mut contiguous_row_selections);
11829        }
11830
11831        self.transact(window, cx, |this, window, cx| {
11832            this.unfold_ranges(&unfold_ranges, true, true, cx);
11833            this.buffer.update(cx, |buffer, cx| {
11834                for (range, text) in edits {
11835                    buffer.edit([(range, text)], None, cx);
11836                }
11837            });
11838            this.fold_creases(refold_creases, true, window, cx);
11839            this.change_selections(Default::default(), window, cx, |s| {
11840                s.select(new_selections);
11841            })
11842        });
11843    }
11844
11845    pub fn move_line_down(
11846        &mut self,
11847        _: &MoveLineDown,
11848        window: &mut Window,
11849        cx: &mut Context<Self>,
11850    ) {
11851        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11852        if self.mode.is_single_line() {
11853            cx.propagate();
11854            return;
11855        }
11856
11857        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11858        let buffer = self.buffer.read(cx).snapshot(cx);
11859
11860        let mut edits = Vec::new();
11861        let mut unfold_ranges = Vec::new();
11862        let mut refold_creases = Vec::new();
11863
11864        let selections = self.selections.all::<Point>(cx);
11865        let mut selections = selections.iter().peekable();
11866        let mut contiguous_row_selections = Vec::new();
11867        let mut new_selections = Vec::new();
11868
11869        while let Some(selection) = selections.next() {
11870            // Find all the selections that span a contiguous row range
11871            let (start_row, end_row) = consume_contiguous_rows(
11872                &mut contiguous_row_selections,
11873                selection,
11874                &display_map,
11875                &mut selections,
11876            );
11877
11878            // Move the text spanned by the row range to be after the last line of the row range
11879            if end_row.0 <= buffer.max_point().row {
11880                let range_to_move =
11881                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11882                let insertion_point = display_map
11883                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11884                    .0;
11885
11886                // Don't move lines across excerpt boundaries
11887                if buffer
11888                    .excerpt_containing(range_to_move.start..insertion_point)
11889                    .is_some()
11890                {
11891                    let mut text = String::from("\n");
11892                    text.extend(buffer.text_for_range(range_to_move.clone()));
11893                    text.pop(); // Drop trailing newline
11894                    edits.push((
11895                        buffer.anchor_after(range_to_move.start)
11896                            ..buffer.anchor_before(range_to_move.end),
11897                        String::new(),
11898                    ));
11899                    let insertion_anchor = buffer.anchor_after(insertion_point);
11900                    edits.push((insertion_anchor..insertion_anchor, text));
11901
11902                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11903
11904                    // Move selections down
11905                    new_selections.extend(contiguous_row_selections.drain(..).map(
11906                        |mut selection| {
11907                            selection.start.row += row_delta;
11908                            selection.end.row += row_delta;
11909                            selection
11910                        },
11911                    ));
11912
11913                    // Move folds down
11914                    unfold_ranges.push(range_to_move.clone());
11915                    for fold in display_map.folds_in_range(
11916                        buffer.anchor_before(range_to_move.start)
11917                            ..buffer.anchor_after(range_to_move.end),
11918                    ) {
11919                        let mut start = fold.range.start.to_point(&buffer);
11920                        let mut end = fold.range.end.to_point(&buffer);
11921                        start.row += row_delta;
11922                        end.row += row_delta;
11923                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11924                    }
11925                }
11926            }
11927
11928            // If we didn't move line(s), preserve the existing selections
11929            new_selections.append(&mut contiguous_row_selections);
11930        }
11931
11932        self.transact(window, cx, |this, window, cx| {
11933            this.unfold_ranges(&unfold_ranges, true, true, cx);
11934            this.buffer.update(cx, |buffer, cx| {
11935                for (range, text) in edits {
11936                    buffer.edit([(range, text)], None, cx);
11937                }
11938            });
11939            this.fold_creases(refold_creases, true, window, cx);
11940            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11941        });
11942    }
11943
11944    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11945        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11946        let text_layout_details = &self.text_layout_details(window);
11947        self.transact(window, cx, |this, window, cx| {
11948            let edits = this.change_selections(Default::default(), window, cx, |s| {
11949                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11950                s.move_with(|display_map, selection| {
11951                    if !selection.is_empty() {
11952                        return;
11953                    }
11954
11955                    let mut head = selection.head();
11956                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11957                    if head.column() == display_map.line_len(head.row()) {
11958                        transpose_offset = display_map
11959                            .buffer_snapshot
11960                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11961                    }
11962
11963                    if transpose_offset == 0 {
11964                        return;
11965                    }
11966
11967                    *head.column_mut() += 1;
11968                    head = display_map.clip_point(head, Bias::Right);
11969                    let goal = SelectionGoal::HorizontalPosition(
11970                        display_map
11971                            .x_for_display_point(head, text_layout_details)
11972                            .into(),
11973                    );
11974                    selection.collapse_to(head, goal);
11975
11976                    let transpose_start = display_map
11977                        .buffer_snapshot
11978                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11979                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11980                        let transpose_end = display_map
11981                            .buffer_snapshot
11982                            .clip_offset(transpose_offset + 1, Bias::Right);
11983                        if let Some(ch) =
11984                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11985                        {
11986                            edits.push((transpose_start..transpose_offset, String::new()));
11987                            edits.push((transpose_end..transpose_end, ch.to_string()));
11988                        }
11989                    }
11990                });
11991                edits
11992            });
11993            this.buffer
11994                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11995            let selections = this.selections.all::<usize>(cx);
11996            this.change_selections(Default::default(), window, cx, |s| {
11997                s.select(selections);
11998            });
11999        });
12000    }
12001
12002    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12003        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12004        if self.mode.is_single_line() {
12005            cx.propagate();
12006            return;
12007        }
12008
12009        self.rewrap_impl(RewrapOptions::default(), cx)
12010    }
12011
12012    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12013        let buffer = self.buffer.read(cx).snapshot(cx);
12014        let selections = self.selections.all::<Point>(cx);
12015
12016        #[derive(Clone, Debug, PartialEq)]
12017        enum CommentFormat {
12018            /// single line comment, with prefix for line
12019            Line(String),
12020            /// single line within a block comment, with prefix for line
12021            BlockLine(String),
12022            /// a single line of a block comment that includes the initial delimiter
12023            BlockCommentWithStart(BlockCommentConfig),
12024            /// a single line of a block comment that includes the ending delimiter
12025            BlockCommentWithEnd(BlockCommentConfig),
12026        }
12027
12028        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12029        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12030            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12031                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12032                .peekable();
12033
12034            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12035                row
12036            } else {
12037                return Vec::new();
12038            };
12039
12040            let language_settings = buffer.language_settings_at(selection.head(), cx);
12041            let language_scope = buffer.language_scope_at(selection.head());
12042
12043            let indent_and_prefix_for_row =
12044                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12045                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12046                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12047                        &language_scope
12048                    {
12049                        let indent_end = Point::new(row, indent.len);
12050                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12051                        let line_text_after_indent = buffer
12052                            .text_for_range(indent_end..line_end)
12053                            .collect::<String>();
12054
12055                        let is_within_comment_override = buffer
12056                            .language_scope_at(indent_end)
12057                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12058                        let comment_delimiters = if is_within_comment_override {
12059                            // we are within a comment syntax node, but we don't
12060                            // yet know what kind of comment: block, doc or line
12061                            match (
12062                                language_scope.documentation_comment(),
12063                                language_scope.block_comment(),
12064                            ) {
12065                                (Some(config), _) | (_, Some(config))
12066                                    if buffer.contains_str_at(indent_end, &config.start) =>
12067                                {
12068                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12069                                }
12070                                (Some(config), _) | (_, Some(config))
12071                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12072                                {
12073                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12074                                }
12075                                (Some(config), _) | (_, Some(config))
12076                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12077                                {
12078                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12079                                }
12080                                (_, _) => language_scope
12081                                    .line_comment_prefixes()
12082                                    .iter()
12083                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12084                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12085                            }
12086                        } else {
12087                            // we not in an overridden comment node, but we may
12088                            // be within a non-overridden line comment node
12089                            language_scope
12090                                .line_comment_prefixes()
12091                                .iter()
12092                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12093                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12094                        };
12095
12096                        let rewrap_prefix = language_scope
12097                            .rewrap_prefixes()
12098                            .iter()
12099                            .find_map(|prefix_regex| {
12100                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12101                                    if mat.start() == 0 {
12102                                        Some(mat.as_str().to_string())
12103                                    } else {
12104                                        None
12105                                    }
12106                                })
12107                            })
12108                            .flatten();
12109                        (comment_delimiters, rewrap_prefix)
12110                    } else {
12111                        (None, None)
12112                    };
12113                    (indent, comment_prefix, rewrap_prefix)
12114                };
12115
12116            let mut ranges = Vec::new();
12117            let from_empty_selection = selection.is_empty();
12118
12119            let mut current_range_start = first_row;
12120            let mut prev_row = first_row;
12121            let (
12122                mut current_range_indent,
12123                mut current_range_comment_delimiters,
12124                mut current_range_rewrap_prefix,
12125            ) = indent_and_prefix_for_row(first_row);
12126
12127            for row in non_blank_rows_iter.skip(1) {
12128                let has_paragraph_break = row > prev_row + 1;
12129
12130                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12131                    indent_and_prefix_for_row(row);
12132
12133                let has_indent_change = row_indent != current_range_indent;
12134                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12135
12136                let has_boundary_change = has_comment_change
12137                    || row_rewrap_prefix.is_some()
12138                    || (has_indent_change && current_range_comment_delimiters.is_some());
12139
12140                if has_paragraph_break || has_boundary_change {
12141                    ranges.push((
12142                        language_settings.clone(),
12143                        Point::new(current_range_start, 0)
12144                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12145                        current_range_indent,
12146                        current_range_comment_delimiters.clone(),
12147                        current_range_rewrap_prefix.clone(),
12148                        from_empty_selection,
12149                    ));
12150                    current_range_start = row;
12151                    current_range_indent = row_indent;
12152                    current_range_comment_delimiters = row_comment_delimiters;
12153                    current_range_rewrap_prefix = row_rewrap_prefix;
12154                }
12155                prev_row = row;
12156            }
12157
12158            ranges.push((
12159                language_settings.clone(),
12160                Point::new(current_range_start, 0)
12161                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12162                current_range_indent,
12163                current_range_comment_delimiters,
12164                current_range_rewrap_prefix,
12165                from_empty_selection,
12166            ));
12167
12168            ranges
12169        });
12170
12171        let mut edits = Vec::new();
12172        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12173
12174        for (
12175            language_settings,
12176            wrap_range,
12177            mut indent_size,
12178            comment_prefix,
12179            rewrap_prefix,
12180            from_empty_selection,
12181        ) in wrap_ranges
12182        {
12183            let mut start_row = wrap_range.start.row;
12184            let mut end_row = wrap_range.end.row;
12185
12186            // Skip selections that overlap with a range that has already been rewrapped.
12187            let selection_range = start_row..end_row;
12188            if rewrapped_row_ranges
12189                .iter()
12190                .any(|range| range.overlaps(&selection_range))
12191            {
12192                continue;
12193            }
12194
12195            let tab_size = language_settings.tab_size;
12196
12197            let (line_prefix, inside_comment) = match &comment_prefix {
12198                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12199                    (Some(prefix.as_str()), true)
12200                }
12201                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12202                    (Some(prefix.as_ref()), true)
12203                }
12204                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12205                    start: _,
12206                    end: _,
12207                    prefix,
12208                    tab_size,
12209                })) => {
12210                    indent_size.len += tab_size;
12211                    (Some(prefix.as_ref()), true)
12212                }
12213                None => (None, false),
12214            };
12215            let indent_prefix = indent_size.chars().collect::<String>();
12216            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12217
12218            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12219                RewrapBehavior::InComments => inside_comment,
12220                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12221                RewrapBehavior::Anywhere => true,
12222            };
12223
12224            let should_rewrap = options.override_language_settings
12225                || allow_rewrap_based_on_language
12226                || self.hard_wrap.is_some();
12227            if !should_rewrap {
12228                continue;
12229            }
12230
12231            if from_empty_selection {
12232                'expand_upwards: while start_row > 0 {
12233                    let prev_row = start_row - 1;
12234                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12235                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12236                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12237                    {
12238                        start_row = prev_row;
12239                    } else {
12240                        break 'expand_upwards;
12241                    }
12242                }
12243
12244                'expand_downwards: while end_row < buffer.max_point().row {
12245                    let next_row = end_row + 1;
12246                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12247                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12248                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12249                    {
12250                        end_row = next_row;
12251                    } else {
12252                        break 'expand_downwards;
12253                    }
12254                }
12255            }
12256
12257            let start = Point::new(start_row, 0);
12258            let start_offset = start.to_offset(&buffer);
12259            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12260            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12261            let mut first_line_delimiter = None;
12262            let mut last_line_delimiter = None;
12263            let Some(lines_without_prefixes) = selection_text
12264                .lines()
12265                .enumerate()
12266                .map(|(ix, line)| {
12267                    let line_trimmed = line.trim_start();
12268                    if rewrap_prefix.is_some() && ix > 0 {
12269                        Ok(line_trimmed)
12270                    } else if let Some(
12271                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12272                            start,
12273                            prefix,
12274                            end,
12275                            tab_size,
12276                        })
12277                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12278                            start,
12279                            prefix,
12280                            end,
12281                            tab_size,
12282                        }),
12283                    ) = &comment_prefix
12284                    {
12285                        let line_trimmed = line_trimmed
12286                            .strip_prefix(start.as_ref())
12287                            .map(|s| {
12288                                let mut indent_size = indent_size;
12289                                indent_size.len -= tab_size;
12290                                let indent_prefix: String = indent_size.chars().collect();
12291                                first_line_delimiter = Some((indent_prefix, start));
12292                                s.trim_start()
12293                            })
12294                            .unwrap_or(line_trimmed);
12295                        let line_trimmed = line_trimmed
12296                            .strip_suffix(end.as_ref())
12297                            .map(|s| {
12298                                last_line_delimiter = Some(end);
12299                                s.trim_end()
12300                            })
12301                            .unwrap_or(line_trimmed);
12302                        let line_trimmed = line_trimmed
12303                            .strip_prefix(prefix.as_ref())
12304                            .unwrap_or(line_trimmed);
12305                        Ok(line_trimmed)
12306                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12307                        line_trimmed.strip_prefix(prefix).with_context(|| {
12308                            format!("line did not start with prefix {prefix:?}: {line:?}")
12309                        })
12310                    } else {
12311                        line_trimmed
12312                            .strip_prefix(&line_prefix.trim_start())
12313                            .with_context(|| {
12314                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12315                            })
12316                    }
12317                })
12318                .collect::<Result<Vec<_>, _>>()
12319                .log_err()
12320            else {
12321                continue;
12322            };
12323
12324            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12325                buffer
12326                    .language_settings_at(Point::new(start_row, 0), cx)
12327                    .preferred_line_length as usize
12328            });
12329
12330            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12331                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12332            } else {
12333                line_prefix.clone()
12334            };
12335
12336            let wrapped_text = {
12337                let mut wrapped_text = wrap_with_prefix(
12338                    line_prefix,
12339                    subsequent_lines_prefix,
12340                    lines_without_prefixes.join("\n"),
12341                    wrap_column,
12342                    tab_size,
12343                    options.preserve_existing_whitespace,
12344                );
12345
12346                if let Some((indent, delimiter)) = first_line_delimiter {
12347                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12348                }
12349                if let Some(last_line) = last_line_delimiter {
12350                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12351                }
12352
12353                wrapped_text
12354            };
12355
12356            // TODO: should always use char-based diff while still supporting cursor behavior that
12357            // matches vim.
12358            let mut diff_options = DiffOptions::default();
12359            if options.override_language_settings {
12360                diff_options.max_word_diff_len = 0;
12361                diff_options.max_word_diff_line_count = 0;
12362            } else {
12363                diff_options.max_word_diff_len = usize::MAX;
12364                diff_options.max_word_diff_line_count = usize::MAX;
12365            }
12366
12367            for (old_range, new_text) in
12368                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12369            {
12370                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12371                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12372                edits.push((edit_start..edit_end, new_text));
12373            }
12374
12375            rewrapped_row_ranges.push(start_row..=end_row);
12376        }
12377
12378        self.buffer
12379            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12380    }
12381
12382    pub fn cut_common(
12383        &mut self,
12384        cut_no_selection_line: bool,
12385        window: &mut Window,
12386        cx: &mut Context<Self>,
12387    ) -> ClipboardItem {
12388        let mut text = String::new();
12389        let buffer = self.buffer.read(cx).snapshot(cx);
12390        let mut selections = self.selections.all::<Point>(cx);
12391        let mut clipboard_selections = Vec::with_capacity(selections.len());
12392        {
12393            let max_point = buffer.max_point();
12394            let mut is_first = true;
12395            for selection in &mut selections {
12396                let is_entire_line =
12397                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12398                if is_entire_line {
12399                    selection.start = Point::new(selection.start.row, 0);
12400                    if !selection.is_empty() && selection.end.column == 0 {
12401                        selection.end = cmp::min(max_point, selection.end);
12402                    } else {
12403                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12404                    }
12405                    selection.goal = SelectionGoal::None;
12406                }
12407                if is_first {
12408                    is_first = false;
12409                } else {
12410                    text += "\n";
12411                }
12412                let mut len = 0;
12413                for chunk in buffer.text_for_range(selection.start..selection.end) {
12414                    text.push_str(chunk);
12415                    len += chunk.len();
12416                }
12417                clipboard_selections.push(ClipboardSelection {
12418                    len,
12419                    is_entire_line,
12420                    first_line_indent: buffer
12421                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12422                        .len,
12423                });
12424            }
12425        }
12426
12427        self.transact(window, cx, |this, window, cx| {
12428            this.change_selections(Default::default(), window, cx, |s| {
12429                s.select(selections);
12430            });
12431            this.insert("", window, cx);
12432        });
12433        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12434    }
12435
12436    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12437        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12438        let item = self.cut_common(true, window, cx);
12439        cx.write_to_clipboard(item);
12440    }
12441
12442    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12443        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12444        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12445            s.move_with(|snapshot, sel| {
12446                if sel.is_empty() {
12447                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12448                }
12449                if sel.is_empty() {
12450                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12451                }
12452            });
12453        });
12454        let item = self.cut_common(false, window, cx);
12455        cx.set_global(KillRing(item))
12456    }
12457
12458    pub fn kill_ring_yank(
12459        &mut self,
12460        _: &KillRingYank,
12461        window: &mut Window,
12462        cx: &mut Context<Self>,
12463    ) {
12464        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12465        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12466            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12467                (kill_ring.text().to_string(), kill_ring.metadata_json())
12468            } else {
12469                return;
12470            }
12471        } else {
12472            return;
12473        };
12474        self.do_paste(&text, metadata, false, window, cx);
12475    }
12476
12477    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12478        self.do_copy(true, cx);
12479    }
12480
12481    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12482        self.do_copy(false, cx);
12483    }
12484
12485    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12486        let selections = self.selections.all::<Point>(cx);
12487        let buffer = self.buffer.read(cx).read(cx);
12488        let mut text = String::new();
12489
12490        let mut clipboard_selections = Vec::with_capacity(selections.len());
12491        {
12492            let max_point = buffer.max_point();
12493            let mut is_first = true;
12494            for selection in &selections {
12495                let mut start = selection.start;
12496                let mut end = selection.end;
12497                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12498                if is_entire_line {
12499                    start = Point::new(start.row, 0);
12500                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12501                }
12502
12503                let mut trimmed_selections = Vec::new();
12504                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12505                    let row = MultiBufferRow(start.row);
12506                    let first_indent = buffer.indent_size_for_line(row);
12507                    if first_indent.len == 0 || start.column > first_indent.len {
12508                        trimmed_selections.push(start..end);
12509                    } else {
12510                        trimmed_selections.push(
12511                            Point::new(row.0, first_indent.len)
12512                                ..Point::new(row.0, buffer.line_len(row)),
12513                        );
12514                        for row in start.row + 1..=end.row {
12515                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12516                            if row == end.row {
12517                                line_len = end.column;
12518                            }
12519                            if line_len == 0 {
12520                                trimmed_selections
12521                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12522                                continue;
12523                            }
12524                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12525                            if row_indent_size.len >= first_indent.len {
12526                                trimmed_selections.push(
12527                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12528                                );
12529                            } else {
12530                                trimmed_selections.clear();
12531                                trimmed_selections.push(start..end);
12532                                break;
12533                            }
12534                        }
12535                    }
12536                } else {
12537                    trimmed_selections.push(start..end);
12538                }
12539
12540                for trimmed_range in trimmed_selections {
12541                    if is_first {
12542                        is_first = false;
12543                    } else {
12544                        text += "\n";
12545                    }
12546                    let mut len = 0;
12547                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12548                        text.push_str(chunk);
12549                        len += chunk.len();
12550                    }
12551                    clipboard_selections.push(ClipboardSelection {
12552                        len,
12553                        is_entire_line,
12554                        first_line_indent: buffer
12555                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12556                            .len,
12557                    });
12558                }
12559            }
12560        }
12561
12562        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12563            text,
12564            clipboard_selections,
12565        ));
12566    }
12567
12568    pub fn do_paste(
12569        &mut self,
12570        text: &String,
12571        clipboard_selections: Option<Vec<ClipboardSelection>>,
12572        handle_entire_lines: bool,
12573        window: &mut Window,
12574        cx: &mut Context<Self>,
12575    ) {
12576        if self.read_only(cx) {
12577            return;
12578        }
12579
12580        let clipboard_text = Cow::Borrowed(text.as_str());
12581
12582        self.transact(window, cx, |this, window, cx| {
12583            let had_active_edit_prediction = this.has_active_edit_prediction();
12584            let old_selections = this.selections.all::<usize>(cx);
12585            let cursor_offset = this.selections.last::<usize>(cx).head();
12586
12587            if let Some(mut clipboard_selections) = clipboard_selections {
12588                let all_selections_were_entire_line =
12589                    clipboard_selections.iter().all(|s| s.is_entire_line);
12590                let first_selection_indent_column =
12591                    clipboard_selections.first().map(|s| s.first_line_indent);
12592                if clipboard_selections.len() != old_selections.len() {
12593                    clipboard_selections.drain(..);
12594                }
12595                let mut auto_indent_on_paste = true;
12596
12597                this.buffer.update(cx, |buffer, cx| {
12598                    let snapshot = buffer.read(cx);
12599                    auto_indent_on_paste = snapshot
12600                        .language_settings_at(cursor_offset, cx)
12601                        .auto_indent_on_paste;
12602
12603                    let mut start_offset = 0;
12604                    let mut edits = Vec::new();
12605                    let mut original_indent_columns = Vec::new();
12606                    for (ix, selection) in old_selections.iter().enumerate() {
12607                        let to_insert;
12608                        let entire_line;
12609                        let original_indent_column;
12610                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12611                            let end_offset = start_offset + clipboard_selection.len;
12612                            to_insert = &clipboard_text[start_offset..end_offset];
12613                            entire_line = clipboard_selection.is_entire_line;
12614                            start_offset = end_offset + 1;
12615                            original_indent_column = Some(clipboard_selection.first_line_indent);
12616                        } else {
12617                            to_insert = &*clipboard_text;
12618                            entire_line = all_selections_were_entire_line;
12619                            original_indent_column = first_selection_indent_column
12620                        }
12621
12622                        let (range, to_insert) =
12623                            if selection.is_empty() && handle_entire_lines && entire_line {
12624                                // If the corresponding selection was empty when this slice of the
12625                                // clipboard text was written, then the entire line containing the
12626                                // selection was copied. If this selection is also currently empty,
12627                                // then paste the line before the current line of the buffer.
12628                                let column = selection.start.to_point(&snapshot).column as usize;
12629                                let line_start = selection.start - column;
12630                                (line_start..line_start, Cow::Borrowed(to_insert))
12631                            } else {
12632                                let language = snapshot.language_at(selection.head());
12633                                let range = selection.range();
12634                                if let Some(language) = language
12635                                    && language.name() == "Markdown".into()
12636                                {
12637                                    edit_for_markdown_paste(
12638                                        &snapshot,
12639                                        range,
12640                                        to_insert,
12641                                        url::Url::parse(to_insert).ok(),
12642                                    )
12643                                } else {
12644                                    (range, Cow::Borrowed(to_insert))
12645                                }
12646                            };
12647
12648                        edits.push((range, to_insert));
12649                        original_indent_columns.push(original_indent_column);
12650                    }
12651                    drop(snapshot);
12652
12653                    buffer.edit(
12654                        edits,
12655                        if auto_indent_on_paste {
12656                            Some(AutoindentMode::Block {
12657                                original_indent_columns,
12658                            })
12659                        } else {
12660                            None
12661                        },
12662                        cx,
12663                    );
12664                });
12665
12666                let selections = this.selections.all::<usize>(cx);
12667                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12668            } else {
12669                let url = url::Url::parse(&clipboard_text).ok();
12670
12671                let auto_indent_mode = if !clipboard_text.is_empty() {
12672                    Some(AutoindentMode::Block {
12673                        original_indent_columns: Vec::new(),
12674                    })
12675                } else {
12676                    None
12677                };
12678
12679                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12680                    let snapshot = buffer.snapshot(cx);
12681
12682                    let anchors = old_selections
12683                        .iter()
12684                        .map(|s| {
12685                            let anchor = snapshot.anchor_after(s.head());
12686                            s.map(|_| anchor)
12687                        })
12688                        .collect::<Vec<_>>();
12689
12690                    let mut edits = Vec::new();
12691
12692                    for selection in old_selections.iter() {
12693                        let language = snapshot.language_at(selection.head());
12694                        let range = selection.range();
12695
12696                        let (edit_range, edit_text) = if let Some(language) = language
12697                            && language.name() == "Markdown".into()
12698                        {
12699                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12700                        } else {
12701                            (range, clipboard_text.clone())
12702                        };
12703
12704                        edits.push((edit_range, edit_text));
12705                    }
12706
12707                    drop(snapshot);
12708                    buffer.edit(edits, auto_indent_mode, cx);
12709
12710                    anchors
12711                });
12712
12713                this.change_selections(Default::default(), window, cx, |s| {
12714                    s.select_anchors(selection_anchors);
12715                });
12716            }
12717
12718            let trigger_in_words =
12719                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12720
12721            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12722        });
12723    }
12724
12725    pub fn diff_clipboard_with_selection(
12726        &mut self,
12727        _: &DiffClipboardWithSelection,
12728        window: &mut Window,
12729        cx: &mut Context<Self>,
12730    ) {
12731        let selections = self.selections.all::<usize>(cx);
12732
12733        if selections.is_empty() {
12734            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12735            return;
12736        };
12737
12738        let clipboard_text = match cx.read_from_clipboard() {
12739            Some(item) => match item.entries().first() {
12740                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12741                _ => None,
12742            },
12743            None => None,
12744        };
12745
12746        let Some(clipboard_text) = clipboard_text else {
12747            log::warn!("Clipboard doesn't contain text.");
12748            return;
12749        };
12750
12751        window.dispatch_action(
12752            Box::new(DiffClipboardWithSelectionData {
12753                clipboard_text,
12754                editor: cx.entity(),
12755            }),
12756            cx,
12757        );
12758    }
12759
12760    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12761        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12762        if let Some(item) = cx.read_from_clipboard() {
12763            let entries = item.entries();
12764
12765            match entries.first() {
12766                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12767                // of all the pasted entries.
12768                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12769                    .do_paste(
12770                        clipboard_string.text(),
12771                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12772                        true,
12773                        window,
12774                        cx,
12775                    ),
12776                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12777            }
12778        }
12779    }
12780
12781    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12782        if self.read_only(cx) {
12783            return;
12784        }
12785
12786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12787
12788        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12789            if let Some((selections, _)) =
12790                self.selection_history.transaction(transaction_id).cloned()
12791            {
12792                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12793                    s.select_anchors(selections.to_vec());
12794                });
12795            } else {
12796                log::error!(
12797                    "No entry in selection_history found for undo. \
12798                     This may correspond to a bug where undo does not update the selection. \
12799                     If this is occurring, please add details to \
12800                     https://github.com/zed-industries/zed/issues/22692"
12801                );
12802            }
12803            self.request_autoscroll(Autoscroll::fit(), cx);
12804            self.unmark_text(window, cx);
12805            self.refresh_edit_prediction(true, false, window, cx);
12806            cx.emit(EditorEvent::Edited { transaction_id });
12807            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12808        }
12809    }
12810
12811    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12812        if self.read_only(cx) {
12813            return;
12814        }
12815
12816        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12817
12818        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12819            if let Some((_, Some(selections))) =
12820                self.selection_history.transaction(transaction_id).cloned()
12821            {
12822                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12823                    s.select_anchors(selections.to_vec());
12824                });
12825            } else {
12826                log::error!(
12827                    "No entry in selection_history found for redo. \
12828                     This may correspond to a bug where undo does not update the selection. \
12829                     If this is occurring, please add details to \
12830                     https://github.com/zed-industries/zed/issues/22692"
12831                );
12832            }
12833            self.request_autoscroll(Autoscroll::fit(), cx);
12834            self.unmark_text(window, cx);
12835            self.refresh_edit_prediction(true, false, window, cx);
12836            cx.emit(EditorEvent::Edited { transaction_id });
12837        }
12838    }
12839
12840    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12841        self.buffer
12842            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12843    }
12844
12845    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12846        self.buffer
12847            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12848    }
12849
12850    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12852        self.change_selections(Default::default(), window, cx, |s| {
12853            s.move_with(|map, selection| {
12854                let cursor = if selection.is_empty() {
12855                    movement::left(map, selection.start)
12856                } else {
12857                    selection.start
12858                };
12859                selection.collapse_to(cursor, SelectionGoal::None);
12860            });
12861        })
12862    }
12863
12864    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12866        self.change_selections(Default::default(), window, cx, |s| {
12867            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12868        })
12869    }
12870
12871    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12872        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12873        self.change_selections(Default::default(), window, cx, |s| {
12874            s.move_with(|map, selection| {
12875                let cursor = if selection.is_empty() {
12876                    movement::right(map, selection.end)
12877                } else {
12878                    selection.end
12879                };
12880                selection.collapse_to(cursor, SelectionGoal::None)
12881            });
12882        })
12883    }
12884
12885    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12886        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12887        self.change_selections(Default::default(), window, cx, |s| {
12888            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12889        })
12890    }
12891
12892    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12893        if self.take_rename(true, window, cx).is_some() {
12894            return;
12895        }
12896
12897        if self.mode.is_single_line() {
12898            cx.propagate();
12899            return;
12900        }
12901
12902        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12903
12904        let text_layout_details = &self.text_layout_details(window);
12905        let selection_count = self.selections.count();
12906        let first_selection = self.selections.first_anchor();
12907
12908        self.change_selections(Default::default(), window, cx, |s| {
12909            s.move_with(|map, selection| {
12910                if !selection.is_empty() {
12911                    selection.goal = SelectionGoal::None;
12912                }
12913                let (cursor, goal) = movement::up(
12914                    map,
12915                    selection.start,
12916                    selection.goal,
12917                    false,
12918                    text_layout_details,
12919                );
12920                selection.collapse_to(cursor, goal);
12921            });
12922        });
12923
12924        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12925        {
12926            cx.propagate();
12927        }
12928    }
12929
12930    pub fn move_up_by_lines(
12931        &mut self,
12932        action: &MoveUpByLines,
12933        window: &mut Window,
12934        cx: &mut Context<Self>,
12935    ) {
12936        if self.take_rename(true, window, cx).is_some() {
12937            return;
12938        }
12939
12940        if self.mode.is_single_line() {
12941            cx.propagate();
12942            return;
12943        }
12944
12945        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12946
12947        let text_layout_details = &self.text_layout_details(window);
12948
12949        self.change_selections(Default::default(), window, cx, |s| {
12950            s.move_with(|map, selection| {
12951                if !selection.is_empty() {
12952                    selection.goal = SelectionGoal::None;
12953                }
12954                let (cursor, goal) = movement::up_by_rows(
12955                    map,
12956                    selection.start,
12957                    action.lines,
12958                    selection.goal,
12959                    false,
12960                    text_layout_details,
12961                );
12962                selection.collapse_to(cursor, goal);
12963            });
12964        })
12965    }
12966
12967    pub fn move_down_by_lines(
12968        &mut self,
12969        action: &MoveDownByLines,
12970        window: &mut Window,
12971        cx: &mut Context<Self>,
12972    ) {
12973        if self.take_rename(true, window, cx).is_some() {
12974            return;
12975        }
12976
12977        if self.mode.is_single_line() {
12978            cx.propagate();
12979            return;
12980        }
12981
12982        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12983
12984        let text_layout_details = &self.text_layout_details(window);
12985
12986        self.change_selections(Default::default(), window, cx, |s| {
12987            s.move_with(|map, selection| {
12988                if !selection.is_empty() {
12989                    selection.goal = SelectionGoal::None;
12990                }
12991                let (cursor, goal) = movement::down_by_rows(
12992                    map,
12993                    selection.start,
12994                    action.lines,
12995                    selection.goal,
12996                    false,
12997                    text_layout_details,
12998                );
12999                selection.collapse_to(cursor, goal);
13000            });
13001        })
13002    }
13003
13004    pub fn select_down_by_lines(
13005        &mut self,
13006        action: &SelectDownByLines,
13007        window: &mut Window,
13008        cx: &mut Context<Self>,
13009    ) {
13010        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13011        let text_layout_details = &self.text_layout_details(window);
13012        self.change_selections(Default::default(), window, cx, |s| {
13013            s.move_heads_with(|map, head, goal| {
13014                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13015            })
13016        })
13017    }
13018
13019    pub fn select_up_by_lines(
13020        &mut self,
13021        action: &SelectUpByLines,
13022        window: &mut Window,
13023        cx: &mut Context<Self>,
13024    ) {
13025        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13026        let text_layout_details = &self.text_layout_details(window);
13027        self.change_selections(Default::default(), window, cx, |s| {
13028            s.move_heads_with(|map, head, goal| {
13029                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13030            })
13031        })
13032    }
13033
13034    pub fn select_page_up(
13035        &mut self,
13036        _: &SelectPageUp,
13037        window: &mut Window,
13038        cx: &mut Context<Self>,
13039    ) {
13040        let Some(row_count) = self.visible_row_count() else {
13041            return;
13042        };
13043
13044        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13045
13046        let text_layout_details = &self.text_layout_details(window);
13047
13048        self.change_selections(Default::default(), window, cx, |s| {
13049            s.move_heads_with(|map, head, goal| {
13050                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13051            })
13052        })
13053    }
13054
13055    pub fn move_page_up(
13056        &mut self,
13057        action: &MovePageUp,
13058        window: &mut Window,
13059        cx: &mut Context<Self>,
13060    ) {
13061        if self.take_rename(true, window, cx).is_some() {
13062            return;
13063        }
13064
13065        if self
13066            .context_menu
13067            .borrow_mut()
13068            .as_mut()
13069            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13070            .unwrap_or(false)
13071        {
13072            return;
13073        }
13074
13075        if matches!(self.mode, EditorMode::SingleLine) {
13076            cx.propagate();
13077            return;
13078        }
13079
13080        let Some(row_count) = self.visible_row_count() else {
13081            return;
13082        };
13083
13084        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13085
13086        let effects = if action.center_cursor {
13087            SelectionEffects::scroll(Autoscroll::center())
13088        } else {
13089            SelectionEffects::default()
13090        };
13091
13092        let text_layout_details = &self.text_layout_details(window);
13093
13094        self.change_selections(effects, window, cx, |s| {
13095            s.move_with(|map, selection| {
13096                if !selection.is_empty() {
13097                    selection.goal = SelectionGoal::None;
13098                }
13099                let (cursor, goal) = movement::up_by_rows(
13100                    map,
13101                    selection.end,
13102                    row_count,
13103                    selection.goal,
13104                    false,
13105                    text_layout_details,
13106                );
13107                selection.collapse_to(cursor, goal);
13108            });
13109        });
13110    }
13111
13112    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13113        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13114        let text_layout_details = &self.text_layout_details(window);
13115        self.change_selections(Default::default(), window, cx, |s| {
13116            s.move_heads_with(|map, head, goal| {
13117                movement::up(map, head, goal, false, text_layout_details)
13118            })
13119        })
13120    }
13121
13122    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13123        self.take_rename(true, window, cx);
13124
13125        if self.mode.is_single_line() {
13126            cx.propagate();
13127            return;
13128        }
13129
13130        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13131
13132        let text_layout_details = &self.text_layout_details(window);
13133        let selection_count = self.selections.count();
13134        let first_selection = self.selections.first_anchor();
13135
13136        self.change_selections(Default::default(), window, cx, |s| {
13137            s.move_with(|map, selection| {
13138                if !selection.is_empty() {
13139                    selection.goal = SelectionGoal::None;
13140                }
13141                let (cursor, goal) = movement::down(
13142                    map,
13143                    selection.end,
13144                    selection.goal,
13145                    false,
13146                    text_layout_details,
13147                );
13148                selection.collapse_to(cursor, goal);
13149            });
13150        });
13151
13152        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13153        {
13154            cx.propagate();
13155        }
13156    }
13157
13158    pub fn select_page_down(
13159        &mut self,
13160        _: &SelectPageDown,
13161        window: &mut Window,
13162        cx: &mut Context<Self>,
13163    ) {
13164        let Some(row_count) = self.visible_row_count() else {
13165            return;
13166        };
13167
13168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13169
13170        let text_layout_details = &self.text_layout_details(window);
13171
13172        self.change_selections(Default::default(), window, cx, |s| {
13173            s.move_heads_with(|map, head, goal| {
13174                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13175            })
13176        })
13177    }
13178
13179    pub fn move_page_down(
13180        &mut self,
13181        action: &MovePageDown,
13182        window: &mut Window,
13183        cx: &mut Context<Self>,
13184    ) {
13185        if self.take_rename(true, window, cx).is_some() {
13186            return;
13187        }
13188
13189        if self
13190            .context_menu
13191            .borrow_mut()
13192            .as_mut()
13193            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13194            .unwrap_or(false)
13195        {
13196            return;
13197        }
13198
13199        if matches!(self.mode, EditorMode::SingleLine) {
13200            cx.propagate();
13201            return;
13202        }
13203
13204        let Some(row_count) = self.visible_row_count() else {
13205            return;
13206        };
13207
13208        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13209
13210        let effects = if action.center_cursor {
13211            SelectionEffects::scroll(Autoscroll::center())
13212        } else {
13213            SelectionEffects::default()
13214        };
13215
13216        let text_layout_details = &self.text_layout_details(window);
13217        self.change_selections(effects, window, cx, |s| {
13218            s.move_with(|map, selection| {
13219                if !selection.is_empty() {
13220                    selection.goal = SelectionGoal::None;
13221                }
13222                let (cursor, goal) = movement::down_by_rows(
13223                    map,
13224                    selection.end,
13225                    row_count,
13226                    selection.goal,
13227                    false,
13228                    text_layout_details,
13229                );
13230                selection.collapse_to(cursor, goal);
13231            });
13232        });
13233    }
13234
13235    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13236        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13237        let text_layout_details = &self.text_layout_details(window);
13238        self.change_selections(Default::default(), window, cx, |s| {
13239            s.move_heads_with(|map, head, goal| {
13240                movement::down(map, head, goal, false, text_layout_details)
13241            })
13242        });
13243    }
13244
13245    pub fn context_menu_first(
13246        &mut self,
13247        _: &ContextMenuFirst,
13248        window: &mut Window,
13249        cx: &mut Context<Self>,
13250    ) {
13251        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13252            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13253        }
13254    }
13255
13256    pub fn context_menu_prev(
13257        &mut self,
13258        _: &ContextMenuPrevious,
13259        window: &mut Window,
13260        cx: &mut Context<Self>,
13261    ) {
13262        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13263            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13264        }
13265    }
13266
13267    pub fn context_menu_next(
13268        &mut self,
13269        _: &ContextMenuNext,
13270        window: &mut Window,
13271        cx: &mut Context<Self>,
13272    ) {
13273        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13274            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13275        }
13276    }
13277
13278    pub fn context_menu_last(
13279        &mut self,
13280        _: &ContextMenuLast,
13281        window: &mut Window,
13282        cx: &mut Context<Self>,
13283    ) {
13284        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13285            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13286        }
13287    }
13288
13289    pub fn signature_help_prev(
13290        &mut self,
13291        _: &SignatureHelpPrevious,
13292        _: &mut Window,
13293        cx: &mut Context<Self>,
13294    ) {
13295        if let Some(popover) = self.signature_help_state.popover_mut() {
13296            if popover.current_signature == 0 {
13297                popover.current_signature = popover.signatures.len() - 1;
13298            } else {
13299                popover.current_signature -= 1;
13300            }
13301            cx.notify();
13302        }
13303    }
13304
13305    pub fn signature_help_next(
13306        &mut self,
13307        _: &SignatureHelpNext,
13308        _: &mut Window,
13309        cx: &mut Context<Self>,
13310    ) {
13311        if let Some(popover) = self.signature_help_state.popover_mut() {
13312            if popover.current_signature + 1 == popover.signatures.len() {
13313                popover.current_signature = 0;
13314            } else {
13315                popover.current_signature += 1;
13316            }
13317            cx.notify();
13318        }
13319    }
13320
13321    pub fn move_to_previous_word_start(
13322        &mut self,
13323        _: &MoveToPreviousWordStart,
13324        window: &mut Window,
13325        cx: &mut Context<Self>,
13326    ) {
13327        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13328        self.change_selections(Default::default(), window, cx, |s| {
13329            s.move_cursors_with(|map, head, _| {
13330                (
13331                    movement::previous_word_start(map, head),
13332                    SelectionGoal::None,
13333                )
13334            });
13335        })
13336    }
13337
13338    pub fn move_to_previous_subword_start(
13339        &mut self,
13340        _: &MoveToPreviousSubwordStart,
13341        window: &mut Window,
13342        cx: &mut Context<Self>,
13343    ) {
13344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13345        self.change_selections(Default::default(), window, cx, |s| {
13346            s.move_cursors_with(|map, head, _| {
13347                (
13348                    movement::previous_subword_start(map, head),
13349                    SelectionGoal::None,
13350                )
13351            });
13352        })
13353    }
13354
13355    pub fn select_to_previous_word_start(
13356        &mut self,
13357        _: &SelectToPreviousWordStart,
13358        window: &mut Window,
13359        cx: &mut Context<Self>,
13360    ) {
13361        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13362        self.change_selections(Default::default(), window, cx, |s| {
13363            s.move_heads_with(|map, head, _| {
13364                (
13365                    movement::previous_word_start(map, head),
13366                    SelectionGoal::None,
13367                )
13368            });
13369        })
13370    }
13371
13372    pub fn select_to_previous_subword_start(
13373        &mut self,
13374        _: &SelectToPreviousSubwordStart,
13375        window: &mut Window,
13376        cx: &mut Context<Self>,
13377    ) {
13378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13379        self.change_selections(Default::default(), window, cx, |s| {
13380            s.move_heads_with(|map, head, _| {
13381                (
13382                    movement::previous_subword_start(map, head),
13383                    SelectionGoal::None,
13384                )
13385            });
13386        })
13387    }
13388
13389    pub fn delete_to_previous_word_start(
13390        &mut self,
13391        action: &DeleteToPreviousWordStart,
13392        window: &mut Window,
13393        cx: &mut Context<Self>,
13394    ) {
13395        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13396        self.transact(window, cx, |this, window, cx| {
13397            this.select_autoclose_pair(window, cx);
13398            this.change_selections(Default::default(), window, cx, |s| {
13399                s.move_with(|map, selection| {
13400                    if selection.is_empty() {
13401                        let mut cursor = if action.ignore_newlines {
13402                            movement::previous_word_start(map, selection.head())
13403                        } else {
13404                            movement::previous_word_start_or_newline(map, selection.head())
13405                        };
13406                        cursor = movement::adjust_greedy_deletion(
13407                            map,
13408                            selection.head(),
13409                            cursor,
13410                            action.ignore_brackets,
13411                        );
13412                        selection.set_head(cursor, SelectionGoal::None);
13413                    }
13414                });
13415            });
13416            this.insert("", window, cx);
13417        });
13418    }
13419
13420    pub fn delete_to_previous_subword_start(
13421        &mut self,
13422        _: &DeleteToPreviousSubwordStart,
13423        window: &mut Window,
13424        cx: &mut Context<Self>,
13425    ) {
13426        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13427        self.transact(window, cx, |this, window, cx| {
13428            this.select_autoclose_pair(window, cx);
13429            this.change_selections(Default::default(), window, cx, |s| {
13430                s.move_with(|map, selection| {
13431                    if selection.is_empty() {
13432                        let mut cursor = movement::previous_subword_start(map, selection.head());
13433                        cursor =
13434                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13435                        selection.set_head(cursor, SelectionGoal::None);
13436                    }
13437                });
13438            });
13439            this.insert("", window, cx);
13440        });
13441    }
13442
13443    pub fn move_to_next_word_end(
13444        &mut self,
13445        _: &MoveToNextWordEnd,
13446        window: &mut Window,
13447        cx: &mut Context<Self>,
13448    ) {
13449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13450        self.change_selections(Default::default(), window, cx, |s| {
13451            s.move_cursors_with(|map, head, _| {
13452                (movement::next_word_end(map, head), SelectionGoal::None)
13453            });
13454        })
13455    }
13456
13457    pub fn move_to_next_subword_end(
13458        &mut self,
13459        _: &MoveToNextSubwordEnd,
13460        window: &mut Window,
13461        cx: &mut Context<Self>,
13462    ) {
13463        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13464        self.change_selections(Default::default(), window, cx, |s| {
13465            s.move_cursors_with(|map, head, _| {
13466                (movement::next_subword_end(map, head), SelectionGoal::None)
13467            });
13468        })
13469    }
13470
13471    pub fn select_to_next_word_end(
13472        &mut self,
13473        _: &SelectToNextWordEnd,
13474        window: &mut Window,
13475        cx: &mut Context<Self>,
13476    ) {
13477        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13478        self.change_selections(Default::default(), window, cx, |s| {
13479            s.move_heads_with(|map, head, _| {
13480                (movement::next_word_end(map, head), SelectionGoal::None)
13481            });
13482        })
13483    }
13484
13485    pub fn select_to_next_subword_end(
13486        &mut self,
13487        _: &SelectToNextSubwordEnd,
13488        window: &mut Window,
13489        cx: &mut Context<Self>,
13490    ) {
13491        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13492        self.change_selections(Default::default(), window, cx, |s| {
13493            s.move_heads_with(|map, head, _| {
13494                (movement::next_subword_end(map, head), SelectionGoal::None)
13495            });
13496        })
13497    }
13498
13499    pub fn delete_to_next_word_end(
13500        &mut self,
13501        action: &DeleteToNextWordEnd,
13502        window: &mut Window,
13503        cx: &mut Context<Self>,
13504    ) {
13505        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13506        self.transact(window, cx, |this, window, cx| {
13507            this.change_selections(Default::default(), window, cx, |s| {
13508                s.move_with(|map, selection| {
13509                    if selection.is_empty() {
13510                        let mut cursor = if action.ignore_newlines {
13511                            movement::next_word_end(map, selection.head())
13512                        } else {
13513                            movement::next_word_end_or_newline(map, selection.head())
13514                        };
13515                        cursor = movement::adjust_greedy_deletion(
13516                            map,
13517                            selection.head(),
13518                            cursor,
13519                            action.ignore_brackets,
13520                        );
13521                        selection.set_head(cursor, SelectionGoal::None);
13522                    }
13523                });
13524            });
13525            this.insert("", window, cx);
13526        });
13527    }
13528
13529    pub fn delete_to_next_subword_end(
13530        &mut self,
13531        _: &DeleteToNextSubwordEnd,
13532        window: &mut Window,
13533        cx: &mut Context<Self>,
13534    ) {
13535        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13536        self.transact(window, cx, |this, window, cx| {
13537            this.change_selections(Default::default(), window, cx, |s| {
13538                s.move_with(|map, selection| {
13539                    if selection.is_empty() {
13540                        let mut cursor = movement::next_subword_end(map, selection.head());
13541                        cursor =
13542                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13543                        selection.set_head(cursor, SelectionGoal::None);
13544                    }
13545                });
13546            });
13547            this.insert("", window, cx);
13548        });
13549    }
13550
13551    pub fn move_to_beginning_of_line(
13552        &mut self,
13553        action: &MoveToBeginningOfLine,
13554        window: &mut Window,
13555        cx: &mut Context<Self>,
13556    ) {
13557        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13558        self.change_selections(Default::default(), window, cx, |s| {
13559            s.move_cursors_with(|map, head, _| {
13560                (
13561                    movement::indented_line_beginning(
13562                        map,
13563                        head,
13564                        action.stop_at_soft_wraps,
13565                        action.stop_at_indent,
13566                    ),
13567                    SelectionGoal::None,
13568                )
13569            });
13570        })
13571    }
13572
13573    pub fn select_to_beginning_of_line(
13574        &mut self,
13575        action: &SelectToBeginningOfLine,
13576        window: &mut Window,
13577        cx: &mut Context<Self>,
13578    ) {
13579        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13580        self.change_selections(Default::default(), window, cx, |s| {
13581            s.move_heads_with(|map, head, _| {
13582                (
13583                    movement::indented_line_beginning(
13584                        map,
13585                        head,
13586                        action.stop_at_soft_wraps,
13587                        action.stop_at_indent,
13588                    ),
13589                    SelectionGoal::None,
13590                )
13591            });
13592        });
13593    }
13594
13595    pub fn delete_to_beginning_of_line(
13596        &mut self,
13597        action: &DeleteToBeginningOfLine,
13598        window: &mut Window,
13599        cx: &mut Context<Self>,
13600    ) {
13601        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13602        self.transact(window, cx, |this, window, cx| {
13603            this.change_selections(Default::default(), window, cx, |s| {
13604                s.move_with(|_, selection| {
13605                    selection.reversed = true;
13606                });
13607            });
13608
13609            this.select_to_beginning_of_line(
13610                &SelectToBeginningOfLine {
13611                    stop_at_soft_wraps: false,
13612                    stop_at_indent: action.stop_at_indent,
13613                },
13614                window,
13615                cx,
13616            );
13617            this.backspace(&Backspace, window, cx);
13618        });
13619    }
13620
13621    pub fn move_to_end_of_line(
13622        &mut self,
13623        action: &MoveToEndOfLine,
13624        window: &mut Window,
13625        cx: &mut Context<Self>,
13626    ) {
13627        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13628        self.change_selections(Default::default(), window, cx, |s| {
13629            s.move_cursors_with(|map, head, _| {
13630                (
13631                    movement::line_end(map, head, action.stop_at_soft_wraps),
13632                    SelectionGoal::None,
13633                )
13634            });
13635        })
13636    }
13637
13638    pub fn select_to_end_of_line(
13639        &mut self,
13640        action: &SelectToEndOfLine,
13641        window: &mut Window,
13642        cx: &mut Context<Self>,
13643    ) {
13644        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13645        self.change_selections(Default::default(), window, cx, |s| {
13646            s.move_heads_with(|map, head, _| {
13647                (
13648                    movement::line_end(map, head, action.stop_at_soft_wraps),
13649                    SelectionGoal::None,
13650                )
13651            });
13652        })
13653    }
13654
13655    pub fn delete_to_end_of_line(
13656        &mut self,
13657        _: &DeleteToEndOfLine,
13658        window: &mut Window,
13659        cx: &mut Context<Self>,
13660    ) {
13661        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13662        self.transact(window, cx, |this, window, cx| {
13663            this.select_to_end_of_line(
13664                &SelectToEndOfLine {
13665                    stop_at_soft_wraps: false,
13666                },
13667                window,
13668                cx,
13669            );
13670            this.delete(&Delete, window, cx);
13671        });
13672    }
13673
13674    pub fn cut_to_end_of_line(
13675        &mut self,
13676        action: &CutToEndOfLine,
13677        window: &mut Window,
13678        cx: &mut Context<Self>,
13679    ) {
13680        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13681        self.transact(window, cx, |this, window, cx| {
13682            this.select_to_end_of_line(
13683                &SelectToEndOfLine {
13684                    stop_at_soft_wraps: false,
13685                },
13686                window,
13687                cx,
13688            );
13689            if !action.stop_at_newlines {
13690                this.change_selections(Default::default(), window, cx, |s| {
13691                    s.move_with(|_, sel| {
13692                        if sel.is_empty() {
13693                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13694                        }
13695                    });
13696                });
13697            }
13698            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13699            let item = this.cut_common(false, window, cx);
13700            cx.write_to_clipboard(item);
13701        });
13702    }
13703
13704    pub fn move_to_start_of_paragraph(
13705        &mut self,
13706        _: &MoveToStartOfParagraph,
13707        window: &mut Window,
13708        cx: &mut Context<Self>,
13709    ) {
13710        if matches!(self.mode, EditorMode::SingleLine) {
13711            cx.propagate();
13712            return;
13713        }
13714        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13715        self.change_selections(Default::default(), window, cx, |s| {
13716            s.move_with(|map, selection| {
13717                selection.collapse_to(
13718                    movement::start_of_paragraph(map, selection.head(), 1),
13719                    SelectionGoal::None,
13720                )
13721            });
13722        })
13723    }
13724
13725    pub fn move_to_end_of_paragraph(
13726        &mut self,
13727        _: &MoveToEndOfParagraph,
13728        window: &mut Window,
13729        cx: &mut Context<Self>,
13730    ) {
13731        if matches!(self.mode, EditorMode::SingleLine) {
13732            cx.propagate();
13733            return;
13734        }
13735        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13736        self.change_selections(Default::default(), window, cx, |s| {
13737            s.move_with(|map, selection| {
13738                selection.collapse_to(
13739                    movement::end_of_paragraph(map, selection.head(), 1),
13740                    SelectionGoal::None,
13741                )
13742            });
13743        })
13744    }
13745
13746    pub fn select_to_start_of_paragraph(
13747        &mut self,
13748        _: &SelectToStartOfParagraph,
13749        window: &mut Window,
13750        cx: &mut Context<Self>,
13751    ) {
13752        if matches!(self.mode, EditorMode::SingleLine) {
13753            cx.propagate();
13754            return;
13755        }
13756        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13757        self.change_selections(Default::default(), window, cx, |s| {
13758            s.move_heads_with(|map, head, _| {
13759                (
13760                    movement::start_of_paragraph(map, head, 1),
13761                    SelectionGoal::None,
13762                )
13763            });
13764        })
13765    }
13766
13767    pub fn select_to_end_of_paragraph(
13768        &mut self,
13769        _: &SelectToEndOfParagraph,
13770        window: &mut Window,
13771        cx: &mut Context<Self>,
13772    ) {
13773        if matches!(self.mode, EditorMode::SingleLine) {
13774            cx.propagate();
13775            return;
13776        }
13777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13778        self.change_selections(Default::default(), window, cx, |s| {
13779            s.move_heads_with(|map, head, _| {
13780                (
13781                    movement::end_of_paragraph(map, head, 1),
13782                    SelectionGoal::None,
13783                )
13784            });
13785        })
13786    }
13787
13788    pub fn move_to_start_of_excerpt(
13789        &mut self,
13790        _: &MoveToStartOfExcerpt,
13791        window: &mut Window,
13792        cx: &mut Context<Self>,
13793    ) {
13794        if matches!(self.mode, EditorMode::SingleLine) {
13795            cx.propagate();
13796            return;
13797        }
13798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13799        self.change_selections(Default::default(), window, cx, |s| {
13800            s.move_with(|map, selection| {
13801                selection.collapse_to(
13802                    movement::start_of_excerpt(
13803                        map,
13804                        selection.head(),
13805                        workspace::searchable::Direction::Prev,
13806                    ),
13807                    SelectionGoal::None,
13808                )
13809            });
13810        })
13811    }
13812
13813    pub fn move_to_start_of_next_excerpt(
13814        &mut self,
13815        _: &MoveToStartOfNextExcerpt,
13816        window: &mut Window,
13817        cx: &mut Context<Self>,
13818    ) {
13819        if matches!(self.mode, EditorMode::SingleLine) {
13820            cx.propagate();
13821            return;
13822        }
13823
13824        self.change_selections(Default::default(), window, cx, |s| {
13825            s.move_with(|map, selection| {
13826                selection.collapse_to(
13827                    movement::start_of_excerpt(
13828                        map,
13829                        selection.head(),
13830                        workspace::searchable::Direction::Next,
13831                    ),
13832                    SelectionGoal::None,
13833                )
13834            });
13835        })
13836    }
13837
13838    pub fn move_to_end_of_excerpt(
13839        &mut self,
13840        _: &MoveToEndOfExcerpt,
13841        window: &mut Window,
13842        cx: &mut Context<Self>,
13843    ) {
13844        if matches!(self.mode, EditorMode::SingleLine) {
13845            cx.propagate();
13846            return;
13847        }
13848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13849        self.change_selections(Default::default(), window, cx, |s| {
13850            s.move_with(|map, selection| {
13851                selection.collapse_to(
13852                    movement::end_of_excerpt(
13853                        map,
13854                        selection.head(),
13855                        workspace::searchable::Direction::Next,
13856                    ),
13857                    SelectionGoal::None,
13858                )
13859            });
13860        })
13861    }
13862
13863    pub fn move_to_end_of_previous_excerpt(
13864        &mut self,
13865        _: &MoveToEndOfPreviousExcerpt,
13866        window: &mut Window,
13867        cx: &mut Context<Self>,
13868    ) {
13869        if matches!(self.mode, EditorMode::SingleLine) {
13870            cx.propagate();
13871            return;
13872        }
13873        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13874        self.change_selections(Default::default(), window, cx, |s| {
13875            s.move_with(|map, selection| {
13876                selection.collapse_to(
13877                    movement::end_of_excerpt(
13878                        map,
13879                        selection.head(),
13880                        workspace::searchable::Direction::Prev,
13881                    ),
13882                    SelectionGoal::None,
13883                )
13884            });
13885        })
13886    }
13887
13888    pub fn select_to_start_of_excerpt(
13889        &mut self,
13890        _: &SelectToStartOfExcerpt,
13891        window: &mut Window,
13892        cx: &mut Context<Self>,
13893    ) {
13894        if matches!(self.mode, EditorMode::SingleLine) {
13895            cx.propagate();
13896            return;
13897        }
13898        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13899        self.change_selections(Default::default(), window, cx, |s| {
13900            s.move_heads_with(|map, head, _| {
13901                (
13902                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13903                    SelectionGoal::None,
13904                )
13905            });
13906        })
13907    }
13908
13909    pub fn select_to_start_of_next_excerpt(
13910        &mut self,
13911        _: &SelectToStartOfNextExcerpt,
13912        window: &mut Window,
13913        cx: &mut Context<Self>,
13914    ) {
13915        if matches!(self.mode, EditorMode::SingleLine) {
13916            cx.propagate();
13917            return;
13918        }
13919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13920        self.change_selections(Default::default(), window, cx, |s| {
13921            s.move_heads_with(|map, head, _| {
13922                (
13923                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13924                    SelectionGoal::None,
13925                )
13926            });
13927        })
13928    }
13929
13930    pub fn select_to_end_of_excerpt(
13931        &mut self,
13932        _: &SelectToEndOfExcerpt,
13933        window: &mut Window,
13934        cx: &mut Context<Self>,
13935    ) {
13936        if matches!(self.mode, EditorMode::SingleLine) {
13937            cx.propagate();
13938            return;
13939        }
13940        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13941        self.change_selections(Default::default(), window, cx, |s| {
13942            s.move_heads_with(|map, head, _| {
13943                (
13944                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13945                    SelectionGoal::None,
13946                )
13947            });
13948        })
13949    }
13950
13951    pub fn select_to_end_of_previous_excerpt(
13952        &mut self,
13953        _: &SelectToEndOfPreviousExcerpt,
13954        window: &mut Window,
13955        cx: &mut Context<Self>,
13956    ) {
13957        if matches!(self.mode, EditorMode::SingleLine) {
13958            cx.propagate();
13959            return;
13960        }
13961        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13962        self.change_selections(Default::default(), window, cx, |s| {
13963            s.move_heads_with(|map, head, _| {
13964                (
13965                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13966                    SelectionGoal::None,
13967                )
13968            });
13969        })
13970    }
13971
13972    pub fn move_to_beginning(
13973        &mut self,
13974        _: &MoveToBeginning,
13975        window: &mut Window,
13976        cx: &mut Context<Self>,
13977    ) {
13978        if matches!(self.mode, EditorMode::SingleLine) {
13979            cx.propagate();
13980            return;
13981        }
13982        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13983        self.change_selections(Default::default(), window, cx, |s| {
13984            s.select_ranges(vec![0..0]);
13985        });
13986    }
13987
13988    pub fn select_to_beginning(
13989        &mut self,
13990        _: &SelectToBeginning,
13991        window: &mut Window,
13992        cx: &mut Context<Self>,
13993    ) {
13994        let mut selection = self.selections.last::<Point>(cx);
13995        selection.set_head(Point::zero(), SelectionGoal::None);
13996        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13997        self.change_selections(Default::default(), window, cx, |s| {
13998            s.select(vec![selection]);
13999        });
14000    }
14001
14002    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14003        if matches!(self.mode, EditorMode::SingleLine) {
14004            cx.propagate();
14005            return;
14006        }
14007        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14008        let cursor = self.buffer.read(cx).read(cx).len();
14009        self.change_selections(Default::default(), window, cx, |s| {
14010            s.select_ranges(vec![cursor..cursor])
14011        });
14012    }
14013
14014    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14015        self.nav_history = nav_history;
14016    }
14017
14018    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14019        self.nav_history.as_ref()
14020    }
14021
14022    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14023        self.push_to_nav_history(
14024            self.selections.newest_anchor().head(),
14025            None,
14026            false,
14027            true,
14028            cx,
14029        );
14030    }
14031
14032    fn push_to_nav_history(
14033        &mut self,
14034        cursor_anchor: Anchor,
14035        new_position: Option<Point>,
14036        is_deactivate: bool,
14037        always: bool,
14038        cx: &mut Context<Self>,
14039    ) {
14040        if let Some(nav_history) = self.nav_history.as_mut() {
14041            let buffer = self.buffer.read(cx).read(cx);
14042            let cursor_position = cursor_anchor.to_point(&buffer);
14043            let scroll_state = self.scroll_manager.anchor();
14044            let scroll_top_row = scroll_state.top_row(&buffer);
14045            drop(buffer);
14046
14047            if let Some(new_position) = new_position {
14048                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14049                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14050                    return;
14051                }
14052            }
14053
14054            nav_history.push(
14055                Some(NavigationData {
14056                    cursor_anchor,
14057                    cursor_position,
14058                    scroll_anchor: scroll_state,
14059                    scroll_top_row,
14060                }),
14061                cx,
14062            );
14063            cx.emit(EditorEvent::PushedToNavHistory {
14064                anchor: cursor_anchor,
14065                is_deactivate,
14066            })
14067        }
14068    }
14069
14070    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14071        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14072        let buffer = self.buffer.read(cx).snapshot(cx);
14073        let mut selection = self.selections.first::<usize>(cx);
14074        selection.set_head(buffer.len(), SelectionGoal::None);
14075        self.change_selections(Default::default(), window, cx, |s| {
14076            s.select(vec![selection]);
14077        });
14078    }
14079
14080    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14081        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14082        let end = self.buffer.read(cx).read(cx).len();
14083        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14084            s.select_ranges(vec![0..end]);
14085        });
14086    }
14087
14088    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14089        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14090        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14091        let mut selections = self.selections.all::<Point>(cx);
14092        let max_point = display_map.buffer_snapshot.max_point();
14093        for selection in &mut selections {
14094            let rows = selection.spanned_rows(true, &display_map);
14095            selection.start = Point::new(rows.start.0, 0);
14096            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14097            selection.reversed = false;
14098        }
14099        self.change_selections(Default::default(), window, cx, |s| {
14100            s.select(selections);
14101        });
14102    }
14103
14104    pub fn split_selection_into_lines(
14105        &mut self,
14106        action: &SplitSelectionIntoLines,
14107        window: &mut Window,
14108        cx: &mut Context<Self>,
14109    ) {
14110        let selections = self
14111            .selections
14112            .all::<Point>(cx)
14113            .into_iter()
14114            .map(|selection| selection.start..selection.end)
14115            .collect::<Vec<_>>();
14116        self.unfold_ranges(&selections, true, true, cx);
14117
14118        let mut new_selection_ranges = Vec::new();
14119        {
14120            let buffer = self.buffer.read(cx).read(cx);
14121            for selection in selections {
14122                for row in selection.start.row..selection.end.row {
14123                    let line_start = Point::new(row, 0);
14124                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14125
14126                    if action.keep_selections {
14127                        // Keep the selection range for each line
14128                        let selection_start = if row == selection.start.row {
14129                            selection.start
14130                        } else {
14131                            line_start
14132                        };
14133                        new_selection_ranges.push(selection_start..line_end);
14134                    } else {
14135                        // Collapse to cursor at end of line
14136                        new_selection_ranges.push(line_end..line_end);
14137                    }
14138                }
14139
14140                let is_multiline_selection = selection.start.row != selection.end.row;
14141                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14142                // so this action feels more ergonomic when paired with other selection operations
14143                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14144                if !should_skip_last {
14145                    if action.keep_selections {
14146                        if is_multiline_selection {
14147                            let line_start = Point::new(selection.end.row, 0);
14148                            new_selection_ranges.push(line_start..selection.end);
14149                        } else {
14150                            new_selection_ranges.push(selection.start..selection.end);
14151                        }
14152                    } else {
14153                        new_selection_ranges.push(selection.end..selection.end);
14154                    }
14155                }
14156            }
14157        }
14158        self.change_selections(Default::default(), window, cx, |s| {
14159            s.select_ranges(new_selection_ranges);
14160        });
14161    }
14162
14163    pub fn add_selection_above(
14164        &mut self,
14165        _: &AddSelectionAbove,
14166        window: &mut Window,
14167        cx: &mut Context<Self>,
14168    ) {
14169        self.add_selection(true, window, cx);
14170    }
14171
14172    pub fn add_selection_below(
14173        &mut self,
14174        _: &AddSelectionBelow,
14175        window: &mut Window,
14176        cx: &mut Context<Self>,
14177    ) {
14178        self.add_selection(false, window, cx);
14179    }
14180
14181    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14183
14184        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14185        let all_selections = self.selections.all::<Point>(cx);
14186        let text_layout_details = self.text_layout_details(window);
14187
14188        let (mut columnar_selections, new_selections_to_columnarize) = {
14189            if let Some(state) = self.add_selections_state.as_ref() {
14190                let columnar_selection_ids: HashSet<_> = state
14191                    .groups
14192                    .iter()
14193                    .flat_map(|group| group.stack.iter())
14194                    .copied()
14195                    .collect();
14196
14197                all_selections
14198                    .into_iter()
14199                    .partition(|s| columnar_selection_ids.contains(&s.id))
14200            } else {
14201                (Vec::new(), all_selections)
14202            }
14203        };
14204
14205        let mut state = self
14206            .add_selections_state
14207            .take()
14208            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14209
14210        for selection in new_selections_to_columnarize {
14211            let range = selection.display_range(&display_map).sorted();
14212            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14213            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14214            let positions = start_x.min(end_x)..start_x.max(end_x);
14215            let mut stack = Vec::new();
14216            for row in range.start.row().0..=range.end.row().0 {
14217                if let Some(selection) = self.selections.build_columnar_selection(
14218                    &display_map,
14219                    DisplayRow(row),
14220                    &positions,
14221                    selection.reversed,
14222                    &text_layout_details,
14223                ) {
14224                    stack.push(selection.id);
14225                    columnar_selections.push(selection);
14226                }
14227            }
14228            if !stack.is_empty() {
14229                if above {
14230                    stack.reverse();
14231                }
14232                state.groups.push(AddSelectionsGroup { above, stack });
14233            }
14234        }
14235
14236        let mut final_selections = Vec::new();
14237        let end_row = if above {
14238            DisplayRow(0)
14239        } else {
14240            display_map.max_point().row()
14241        };
14242
14243        let mut last_added_item_per_group = HashMap::default();
14244        for group in state.groups.iter_mut() {
14245            if let Some(last_id) = group.stack.last() {
14246                last_added_item_per_group.insert(*last_id, group);
14247            }
14248        }
14249
14250        for selection in columnar_selections {
14251            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14252                if above == group.above {
14253                    let range = selection.display_range(&display_map).sorted();
14254                    debug_assert_eq!(range.start.row(), range.end.row());
14255                    let mut row = range.start.row();
14256                    let positions =
14257                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14258                            px(start)..px(end)
14259                        } else {
14260                            let start_x =
14261                                display_map.x_for_display_point(range.start, &text_layout_details);
14262                            let end_x =
14263                                display_map.x_for_display_point(range.end, &text_layout_details);
14264                            start_x.min(end_x)..start_x.max(end_x)
14265                        };
14266
14267                    let mut maybe_new_selection = None;
14268                    while row != end_row {
14269                        if above {
14270                            row.0 -= 1;
14271                        } else {
14272                            row.0 += 1;
14273                        }
14274                        if let Some(new_selection) = self.selections.build_columnar_selection(
14275                            &display_map,
14276                            row,
14277                            &positions,
14278                            selection.reversed,
14279                            &text_layout_details,
14280                        ) {
14281                            maybe_new_selection = Some(new_selection);
14282                            break;
14283                        }
14284                    }
14285
14286                    if let Some(new_selection) = maybe_new_selection {
14287                        group.stack.push(new_selection.id);
14288                        if above {
14289                            final_selections.push(new_selection);
14290                            final_selections.push(selection);
14291                        } else {
14292                            final_selections.push(selection);
14293                            final_selections.push(new_selection);
14294                        }
14295                    } else {
14296                        final_selections.push(selection);
14297                    }
14298                } else {
14299                    group.stack.pop();
14300                }
14301            } else {
14302                final_selections.push(selection);
14303            }
14304        }
14305
14306        self.change_selections(Default::default(), window, cx, |s| {
14307            s.select(final_selections);
14308        });
14309
14310        let final_selection_ids: HashSet<_> = self
14311            .selections
14312            .all::<Point>(cx)
14313            .iter()
14314            .map(|s| s.id)
14315            .collect();
14316        state.groups.retain_mut(|group| {
14317            // selections might get merged above so we remove invalid items from stacks
14318            group.stack.retain(|id| final_selection_ids.contains(id));
14319
14320            // single selection in stack can be treated as initial state
14321            group.stack.len() > 1
14322        });
14323
14324        if !state.groups.is_empty() {
14325            self.add_selections_state = Some(state);
14326        }
14327    }
14328
14329    fn select_match_ranges(
14330        &mut self,
14331        range: Range<usize>,
14332        reversed: bool,
14333        replace_newest: bool,
14334        auto_scroll: Option<Autoscroll>,
14335        window: &mut Window,
14336        cx: &mut Context<Editor>,
14337    ) {
14338        self.unfold_ranges(
14339            std::slice::from_ref(&range),
14340            false,
14341            auto_scroll.is_some(),
14342            cx,
14343        );
14344        let effects = if let Some(scroll) = auto_scroll {
14345            SelectionEffects::scroll(scroll)
14346        } else {
14347            SelectionEffects::no_scroll()
14348        };
14349        self.change_selections(effects, window, cx, |s| {
14350            if replace_newest {
14351                s.delete(s.newest_anchor().id);
14352            }
14353            if reversed {
14354                s.insert_range(range.end..range.start);
14355            } else {
14356                s.insert_range(range);
14357            }
14358        });
14359    }
14360
14361    pub fn select_next_match_internal(
14362        &mut self,
14363        display_map: &DisplaySnapshot,
14364        replace_newest: bool,
14365        autoscroll: Option<Autoscroll>,
14366        window: &mut Window,
14367        cx: &mut Context<Self>,
14368    ) -> Result<()> {
14369        let buffer = &display_map.buffer_snapshot;
14370        let mut selections = self.selections.all::<usize>(cx);
14371        if let Some(mut select_next_state) = self.select_next_state.take() {
14372            let query = &select_next_state.query;
14373            if !select_next_state.done {
14374                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14375                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14376                let mut next_selected_range = None;
14377
14378                let bytes_after_last_selection =
14379                    buffer.bytes_in_range(last_selection.end..buffer.len());
14380                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14381                let query_matches = query
14382                    .stream_find_iter(bytes_after_last_selection)
14383                    .map(|result| (last_selection.end, result))
14384                    .chain(
14385                        query
14386                            .stream_find_iter(bytes_before_first_selection)
14387                            .map(|result| (0, result)),
14388                    );
14389
14390                for (start_offset, query_match) in query_matches {
14391                    let query_match = query_match.unwrap(); // can only fail due to I/O
14392                    let offset_range =
14393                        start_offset + query_match.start()..start_offset + query_match.end();
14394
14395                    if !select_next_state.wordwise
14396                        || (!buffer.is_inside_word(offset_range.start, None)
14397                            && !buffer.is_inside_word(offset_range.end, None))
14398                    {
14399                        // TODO: This is n^2, because we might check all the selections
14400                        if !selections
14401                            .iter()
14402                            .any(|selection| selection.range().overlaps(&offset_range))
14403                        {
14404                            next_selected_range = Some(offset_range);
14405                            break;
14406                        }
14407                    }
14408                }
14409
14410                if let Some(next_selected_range) = next_selected_range {
14411                    self.select_match_ranges(
14412                        next_selected_range,
14413                        last_selection.reversed,
14414                        replace_newest,
14415                        autoscroll,
14416                        window,
14417                        cx,
14418                    );
14419                } else {
14420                    select_next_state.done = true;
14421                }
14422            }
14423
14424            self.select_next_state = Some(select_next_state);
14425        } else {
14426            let mut only_carets = true;
14427            let mut same_text_selected = true;
14428            let mut selected_text = None;
14429
14430            let mut selections_iter = selections.iter().peekable();
14431            while let Some(selection) = selections_iter.next() {
14432                if selection.start != selection.end {
14433                    only_carets = false;
14434                }
14435
14436                if same_text_selected {
14437                    if selected_text.is_none() {
14438                        selected_text =
14439                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14440                    }
14441
14442                    if let Some(next_selection) = selections_iter.peek() {
14443                        if next_selection.range().len() == selection.range().len() {
14444                            let next_selected_text = buffer
14445                                .text_for_range(next_selection.range())
14446                                .collect::<String>();
14447                            if Some(next_selected_text) != selected_text {
14448                                same_text_selected = false;
14449                                selected_text = None;
14450                            }
14451                        } else {
14452                            same_text_selected = false;
14453                            selected_text = None;
14454                        }
14455                    }
14456                }
14457            }
14458
14459            if only_carets {
14460                for selection in &mut selections {
14461                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14462                    selection.start = word_range.start;
14463                    selection.end = word_range.end;
14464                    selection.goal = SelectionGoal::None;
14465                    selection.reversed = false;
14466                    self.select_match_ranges(
14467                        selection.start..selection.end,
14468                        selection.reversed,
14469                        replace_newest,
14470                        autoscroll,
14471                        window,
14472                        cx,
14473                    );
14474                }
14475
14476                if selections.len() == 1 {
14477                    let selection = selections
14478                        .last()
14479                        .expect("ensured that there's only one selection");
14480                    let query = buffer
14481                        .text_for_range(selection.start..selection.end)
14482                        .collect::<String>();
14483                    let is_empty = query.is_empty();
14484                    let select_state = SelectNextState {
14485                        query: AhoCorasick::new(&[query])?,
14486                        wordwise: true,
14487                        done: is_empty,
14488                    };
14489                    self.select_next_state = Some(select_state);
14490                } else {
14491                    self.select_next_state = None;
14492                }
14493            } else if let Some(selected_text) = selected_text {
14494                self.select_next_state = Some(SelectNextState {
14495                    query: AhoCorasick::new(&[selected_text])?,
14496                    wordwise: false,
14497                    done: false,
14498                });
14499                self.select_next_match_internal(
14500                    display_map,
14501                    replace_newest,
14502                    autoscroll,
14503                    window,
14504                    cx,
14505                )?;
14506            }
14507        }
14508        Ok(())
14509    }
14510
14511    pub fn select_all_matches(
14512        &mut self,
14513        _action: &SelectAllMatches,
14514        window: &mut Window,
14515        cx: &mut Context<Self>,
14516    ) -> Result<()> {
14517        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14518
14519        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14520
14521        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14522        let Some(select_next_state) = self.select_next_state.as_mut() else {
14523            return Ok(());
14524        };
14525        if select_next_state.done {
14526            return Ok(());
14527        }
14528
14529        let mut new_selections = Vec::new();
14530
14531        let reversed = self.selections.oldest::<usize>(cx).reversed;
14532        let buffer = &display_map.buffer_snapshot;
14533        let query_matches = select_next_state
14534            .query
14535            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14536
14537        for query_match in query_matches.into_iter() {
14538            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14539            let offset_range = if reversed {
14540                query_match.end()..query_match.start()
14541            } else {
14542                query_match.start()..query_match.end()
14543            };
14544
14545            if !select_next_state.wordwise
14546                || (!buffer.is_inside_word(offset_range.start, None)
14547                    && !buffer.is_inside_word(offset_range.end, None))
14548            {
14549                new_selections.push(offset_range.start..offset_range.end);
14550            }
14551        }
14552
14553        select_next_state.done = true;
14554
14555        if new_selections.is_empty() {
14556            log::error!("bug: new_selections is empty in select_all_matches");
14557            return Ok(());
14558        }
14559
14560        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14561        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14562            selections.select_ranges(new_selections)
14563        });
14564
14565        Ok(())
14566    }
14567
14568    pub fn select_next(
14569        &mut self,
14570        action: &SelectNext,
14571        window: &mut Window,
14572        cx: &mut Context<Self>,
14573    ) -> Result<()> {
14574        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14575        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14576        self.select_next_match_internal(
14577            &display_map,
14578            action.replace_newest,
14579            Some(Autoscroll::newest()),
14580            window,
14581            cx,
14582        )?;
14583        Ok(())
14584    }
14585
14586    pub fn select_previous(
14587        &mut self,
14588        action: &SelectPrevious,
14589        window: &mut Window,
14590        cx: &mut Context<Self>,
14591    ) -> Result<()> {
14592        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14593        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14594        let buffer = &display_map.buffer_snapshot;
14595        let mut selections = self.selections.all::<usize>(cx);
14596        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14597            let query = &select_prev_state.query;
14598            if !select_prev_state.done {
14599                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14600                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14601                let mut next_selected_range = None;
14602                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14603                let bytes_before_last_selection =
14604                    buffer.reversed_bytes_in_range(0..last_selection.start);
14605                let bytes_after_first_selection =
14606                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14607                let query_matches = query
14608                    .stream_find_iter(bytes_before_last_selection)
14609                    .map(|result| (last_selection.start, result))
14610                    .chain(
14611                        query
14612                            .stream_find_iter(bytes_after_first_selection)
14613                            .map(|result| (buffer.len(), result)),
14614                    );
14615                for (end_offset, query_match) in query_matches {
14616                    let query_match = query_match.unwrap(); // can only fail due to I/O
14617                    let offset_range =
14618                        end_offset - query_match.end()..end_offset - query_match.start();
14619
14620                    if !select_prev_state.wordwise
14621                        || (!buffer.is_inside_word(offset_range.start, None)
14622                            && !buffer.is_inside_word(offset_range.end, None))
14623                    {
14624                        next_selected_range = Some(offset_range);
14625                        break;
14626                    }
14627                }
14628
14629                if let Some(next_selected_range) = next_selected_range {
14630                    self.select_match_ranges(
14631                        next_selected_range,
14632                        last_selection.reversed,
14633                        action.replace_newest,
14634                        Some(Autoscroll::newest()),
14635                        window,
14636                        cx,
14637                    );
14638                } else {
14639                    select_prev_state.done = true;
14640                }
14641            }
14642
14643            self.select_prev_state = Some(select_prev_state);
14644        } else {
14645            let mut only_carets = true;
14646            let mut same_text_selected = true;
14647            let mut selected_text = None;
14648
14649            let mut selections_iter = selections.iter().peekable();
14650            while let Some(selection) = selections_iter.next() {
14651                if selection.start != selection.end {
14652                    only_carets = false;
14653                }
14654
14655                if same_text_selected {
14656                    if selected_text.is_none() {
14657                        selected_text =
14658                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14659                    }
14660
14661                    if let Some(next_selection) = selections_iter.peek() {
14662                        if next_selection.range().len() == selection.range().len() {
14663                            let next_selected_text = buffer
14664                                .text_for_range(next_selection.range())
14665                                .collect::<String>();
14666                            if Some(next_selected_text) != selected_text {
14667                                same_text_selected = false;
14668                                selected_text = None;
14669                            }
14670                        } else {
14671                            same_text_selected = false;
14672                            selected_text = None;
14673                        }
14674                    }
14675                }
14676            }
14677
14678            if only_carets {
14679                for selection in &mut selections {
14680                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14681                    selection.start = word_range.start;
14682                    selection.end = word_range.end;
14683                    selection.goal = SelectionGoal::None;
14684                    selection.reversed = false;
14685                    self.select_match_ranges(
14686                        selection.start..selection.end,
14687                        selection.reversed,
14688                        action.replace_newest,
14689                        Some(Autoscroll::newest()),
14690                        window,
14691                        cx,
14692                    );
14693                }
14694                if selections.len() == 1 {
14695                    let selection = selections
14696                        .last()
14697                        .expect("ensured that there's only one selection");
14698                    let query = buffer
14699                        .text_for_range(selection.start..selection.end)
14700                        .collect::<String>();
14701                    let is_empty = query.is_empty();
14702                    let select_state = SelectNextState {
14703                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14704                        wordwise: true,
14705                        done: is_empty,
14706                    };
14707                    self.select_prev_state = Some(select_state);
14708                } else {
14709                    self.select_prev_state = None;
14710                }
14711            } else if let Some(selected_text) = selected_text {
14712                self.select_prev_state = Some(SelectNextState {
14713                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14714                    wordwise: false,
14715                    done: false,
14716                });
14717                self.select_previous(action, window, cx)?;
14718            }
14719        }
14720        Ok(())
14721    }
14722
14723    pub fn find_next_match(
14724        &mut self,
14725        _: &FindNextMatch,
14726        window: &mut Window,
14727        cx: &mut Context<Self>,
14728    ) -> Result<()> {
14729        let selections = self.selections.disjoint_anchors_arc();
14730        match selections.first() {
14731            Some(first) if selections.len() >= 2 => {
14732                self.change_selections(Default::default(), window, cx, |s| {
14733                    s.select_ranges([first.range()]);
14734                });
14735            }
14736            _ => self.select_next(
14737                &SelectNext {
14738                    replace_newest: true,
14739                },
14740                window,
14741                cx,
14742            )?,
14743        }
14744        Ok(())
14745    }
14746
14747    pub fn find_previous_match(
14748        &mut self,
14749        _: &FindPreviousMatch,
14750        window: &mut Window,
14751        cx: &mut Context<Self>,
14752    ) -> Result<()> {
14753        let selections = self.selections.disjoint_anchors_arc();
14754        match selections.last() {
14755            Some(last) if selections.len() >= 2 => {
14756                self.change_selections(Default::default(), window, cx, |s| {
14757                    s.select_ranges([last.range()]);
14758                });
14759            }
14760            _ => self.select_previous(
14761                &SelectPrevious {
14762                    replace_newest: true,
14763                },
14764                window,
14765                cx,
14766            )?,
14767        }
14768        Ok(())
14769    }
14770
14771    pub fn toggle_comments(
14772        &mut self,
14773        action: &ToggleComments,
14774        window: &mut Window,
14775        cx: &mut Context<Self>,
14776    ) {
14777        if self.read_only(cx) {
14778            return;
14779        }
14780        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14781        let text_layout_details = &self.text_layout_details(window);
14782        self.transact(window, cx, |this, window, cx| {
14783            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14784            let mut edits = Vec::new();
14785            let mut selection_edit_ranges = Vec::new();
14786            let mut last_toggled_row = None;
14787            let snapshot = this.buffer.read(cx).read(cx);
14788            let empty_str: Arc<str> = Arc::default();
14789            let mut suffixes_inserted = Vec::new();
14790            let ignore_indent = action.ignore_indent;
14791
14792            fn comment_prefix_range(
14793                snapshot: &MultiBufferSnapshot,
14794                row: MultiBufferRow,
14795                comment_prefix: &str,
14796                comment_prefix_whitespace: &str,
14797                ignore_indent: bool,
14798            ) -> Range<Point> {
14799                let indent_size = if ignore_indent {
14800                    0
14801                } else {
14802                    snapshot.indent_size_for_line(row).len
14803                };
14804
14805                let start = Point::new(row.0, indent_size);
14806
14807                let mut line_bytes = snapshot
14808                    .bytes_in_range(start..snapshot.max_point())
14809                    .flatten()
14810                    .copied();
14811
14812                // If this line currently begins with the line comment prefix, then record
14813                // the range containing the prefix.
14814                if line_bytes
14815                    .by_ref()
14816                    .take(comment_prefix.len())
14817                    .eq(comment_prefix.bytes())
14818                {
14819                    // Include any whitespace that matches the comment prefix.
14820                    let matching_whitespace_len = line_bytes
14821                        .zip(comment_prefix_whitespace.bytes())
14822                        .take_while(|(a, b)| a == b)
14823                        .count() as u32;
14824                    let end = Point::new(
14825                        start.row,
14826                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14827                    );
14828                    start..end
14829                } else {
14830                    start..start
14831                }
14832            }
14833
14834            fn comment_suffix_range(
14835                snapshot: &MultiBufferSnapshot,
14836                row: MultiBufferRow,
14837                comment_suffix: &str,
14838                comment_suffix_has_leading_space: bool,
14839            ) -> Range<Point> {
14840                let end = Point::new(row.0, snapshot.line_len(row));
14841                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14842
14843                let mut line_end_bytes = snapshot
14844                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14845                    .flatten()
14846                    .copied();
14847
14848                let leading_space_len = if suffix_start_column > 0
14849                    && line_end_bytes.next() == Some(b' ')
14850                    && comment_suffix_has_leading_space
14851                {
14852                    1
14853                } else {
14854                    0
14855                };
14856
14857                // If this line currently begins with the line comment prefix, then record
14858                // the range containing the prefix.
14859                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14860                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14861                    start..end
14862                } else {
14863                    end..end
14864                }
14865            }
14866
14867            // TODO: Handle selections that cross excerpts
14868            for selection in &mut selections {
14869                let start_column = snapshot
14870                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14871                    .len;
14872                let language = if let Some(language) =
14873                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14874                {
14875                    language
14876                } else {
14877                    continue;
14878                };
14879
14880                selection_edit_ranges.clear();
14881
14882                // If multiple selections contain a given row, avoid processing that
14883                // row more than once.
14884                let mut start_row = MultiBufferRow(selection.start.row);
14885                if last_toggled_row == Some(start_row) {
14886                    start_row = start_row.next_row();
14887                }
14888                let end_row =
14889                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14890                        MultiBufferRow(selection.end.row - 1)
14891                    } else {
14892                        MultiBufferRow(selection.end.row)
14893                    };
14894                last_toggled_row = Some(end_row);
14895
14896                if start_row > end_row {
14897                    continue;
14898                }
14899
14900                // If the language has line comments, toggle those.
14901                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14902
14903                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14904                if ignore_indent {
14905                    full_comment_prefixes = full_comment_prefixes
14906                        .into_iter()
14907                        .map(|s| Arc::from(s.trim_end()))
14908                        .collect();
14909                }
14910
14911                if !full_comment_prefixes.is_empty() {
14912                    let first_prefix = full_comment_prefixes
14913                        .first()
14914                        .expect("prefixes is non-empty");
14915                    let prefix_trimmed_lengths = full_comment_prefixes
14916                        .iter()
14917                        .map(|p| p.trim_end_matches(' ').len())
14918                        .collect::<SmallVec<[usize; 4]>>();
14919
14920                    let mut all_selection_lines_are_comments = true;
14921
14922                    for row in start_row.0..=end_row.0 {
14923                        let row = MultiBufferRow(row);
14924                        if start_row < end_row && snapshot.is_line_blank(row) {
14925                            continue;
14926                        }
14927
14928                        let prefix_range = full_comment_prefixes
14929                            .iter()
14930                            .zip(prefix_trimmed_lengths.iter().copied())
14931                            .map(|(prefix, trimmed_prefix_len)| {
14932                                comment_prefix_range(
14933                                    snapshot.deref(),
14934                                    row,
14935                                    &prefix[..trimmed_prefix_len],
14936                                    &prefix[trimmed_prefix_len..],
14937                                    ignore_indent,
14938                                )
14939                            })
14940                            .max_by_key(|range| range.end.column - range.start.column)
14941                            .expect("prefixes is non-empty");
14942
14943                        if prefix_range.is_empty() {
14944                            all_selection_lines_are_comments = false;
14945                        }
14946
14947                        selection_edit_ranges.push(prefix_range);
14948                    }
14949
14950                    if all_selection_lines_are_comments {
14951                        edits.extend(
14952                            selection_edit_ranges
14953                                .iter()
14954                                .cloned()
14955                                .map(|range| (range, empty_str.clone())),
14956                        );
14957                    } else {
14958                        let min_column = selection_edit_ranges
14959                            .iter()
14960                            .map(|range| range.start.column)
14961                            .min()
14962                            .unwrap_or(0);
14963                        edits.extend(selection_edit_ranges.iter().map(|range| {
14964                            let position = Point::new(range.start.row, min_column);
14965                            (position..position, first_prefix.clone())
14966                        }));
14967                    }
14968                } else if let Some(BlockCommentConfig {
14969                    start: full_comment_prefix,
14970                    end: comment_suffix,
14971                    ..
14972                }) = language.block_comment()
14973                {
14974                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14975                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14976                    let prefix_range = comment_prefix_range(
14977                        snapshot.deref(),
14978                        start_row,
14979                        comment_prefix,
14980                        comment_prefix_whitespace,
14981                        ignore_indent,
14982                    );
14983                    let suffix_range = comment_suffix_range(
14984                        snapshot.deref(),
14985                        end_row,
14986                        comment_suffix.trim_start_matches(' '),
14987                        comment_suffix.starts_with(' '),
14988                    );
14989
14990                    if prefix_range.is_empty() || suffix_range.is_empty() {
14991                        edits.push((
14992                            prefix_range.start..prefix_range.start,
14993                            full_comment_prefix.clone(),
14994                        ));
14995                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14996                        suffixes_inserted.push((end_row, comment_suffix.len()));
14997                    } else {
14998                        edits.push((prefix_range, empty_str.clone()));
14999                        edits.push((suffix_range, empty_str.clone()));
15000                    }
15001                } else {
15002                    continue;
15003                }
15004            }
15005
15006            drop(snapshot);
15007            this.buffer.update(cx, |buffer, cx| {
15008                buffer.edit(edits, None, cx);
15009            });
15010
15011            // Adjust selections so that they end before any comment suffixes that
15012            // were inserted.
15013            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15014            let mut selections = this.selections.all::<Point>(cx);
15015            let snapshot = this.buffer.read(cx).read(cx);
15016            for selection in &mut selections {
15017                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15018                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15019                        Ordering::Less => {
15020                            suffixes_inserted.next();
15021                            continue;
15022                        }
15023                        Ordering::Greater => break,
15024                        Ordering::Equal => {
15025                            if selection.end.column == snapshot.line_len(row) {
15026                                if selection.is_empty() {
15027                                    selection.start.column -= suffix_len as u32;
15028                                }
15029                                selection.end.column -= suffix_len as u32;
15030                            }
15031                            break;
15032                        }
15033                    }
15034                }
15035            }
15036
15037            drop(snapshot);
15038            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15039
15040            let selections = this.selections.all::<Point>(cx);
15041            let selections_on_single_row = selections.windows(2).all(|selections| {
15042                selections[0].start.row == selections[1].start.row
15043                    && selections[0].end.row == selections[1].end.row
15044                    && selections[0].start.row == selections[0].end.row
15045            });
15046            let selections_selecting = selections
15047                .iter()
15048                .any(|selection| selection.start != selection.end);
15049            let advance_downwards = action.advance_downwards
15050                && selections_on_single_row
15051                && !selections_selecting
15052                && !matches!(this.mode, EditorMode::SingleLine);
15053
15054            if advance_downwards {
15055                let snapshot = this.buffer.read(cx).snapshot(cx);
15056
15057                this.change_selections(Default::default(), window, cx, |s| {
15058                    s.move_cursors_with(|display_snapshot, display_point, _| {
15059                        let mut point = display_point.to_point(display_snapshot);
15060                        point.row += 1;
15061                        point = snapshot.clip_point(point, Bias::Left);
15062                        let display_point = point.to_display_point(display_snapshot);
15063                        let goal = SelectionGoal::HorizontalPosition(
15064                            display_snapshot
15065                                .x_for_display_point(display_point, text_layout_details)
15066                                .into(),
15067                        );
15068                        (display_point, goal)
15069                    })
15070                });
15071            }
15072        });
15073    }
15074
15075    pub fn select_enclosing_symbol(
15076        &mut self,
15077        _: &SelectEnclosingSymbol,
15078        window: &mut Window,
15079        cx: &mut Context<Self>,
15080    ) {
15081        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15082
15083        let buffer = self.buffer.read(cx).snapshot(cx);
15084        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15085
15086        fn update_selection(
15087            selection: &Selection<usize>,
15088            buffer_snap: &MultiBufferSnapshot,
15089        ) -> Option<Selection<usize>> {
15090            let cursor = selection.head();
15091            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15092            for symbol in symbols.iter().rev() {
15093                let start = symbol.range.start.to_offset(buffer_snap);
15094                let end = symbol.range.end.to_offset(buffer_snap);
15095                let new_range = start..end;
15096                if start < selection.start || end > selection.end {
15097                    return Some(Selection {
15098                        id: selection.id,
15099                        start: new_range.start,
15100                        end: new_range.end,
15101                        goal: SelectionGoal::None,
15102                        reversed: selection.reversed,
15103                    });
15104                }
15105            }
15106            None
15107        }
15108
15109        let mut selected_larger_symbol = false;
15110        let new_selections = old_selections
15111            .iter()
15112            .map(|selection| match update_selection(selection, &buffer) {
15113                Some(new_selection) => {
15114                    if new_selection.range() != selection.range() {
15115                        selected_larger_symbol = true;
15116                    }
15117                    new_selection
15118                }
15119                None => selection.clone(),
15120            })
15121            .collect::<Vec<_>>();
15122
15123        if selected_larger_symbol {
15124            self.change_selections(Default::default(), window, cx, |s| {
15125                s.select(new_selections);
15126            });
15127        }
15128    }
15129
15130    pub fn select_larger_syntax_node(
15131        &mut self,
15132        _: &SelectLargerSyntaxNode,
15133        window: &mut Window,
15134        cx: &mut Context<Self>,
15135    ) {
15136        let Some(visible_row_count) = self.visible_row_count() else {
15137            return;
15138        };
15139        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15140        if old_selections.is_empty() {
15141            return;
15142        }
15143
15144        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15145
15146        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15147        let buffer = self.buffer.read(cx).snapshot(cx);
15148
15149        let mut selected_larger_node = false;
15150        let mut new_selections = old_selections
15151            .iter()
15152            .map(|selection| {
15153                let old_range = selection.start..selection.end;
15154
15155                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15156                    // manually select word at selection
15157                    if ["string_content", "inline"].contains(&node.kind()) {
15158                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15159                        // ignore if word is already selected
15160                        if !word_range.is_empty() && old_range != word_range {
15161                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15162                            // only select word if start and end point belongs to same word
15163                            if word_range == last_word_range {
15164                                selected_larger_node = true;
15165                                return Selection {
15166                                    id: selection.id,
15167                                    start: word_range.start,
15168                                    end: word_range.end,
15169                                    goal: SelectionGoal::None,
15170                                    reversed: selection.reversed,
15171                                };
15172                            }
15173                        }
15174                    }
15175                }
15176
15177                let mut new_range = old_range.clone();
15178                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15179                    new_range = range;
15180                    if !node.is_named() {
15181                        continue;
15182                    }
15183                    if !display_map.intersects_fold(new_range.start)
15184                        && !display_map.intersects_fold(new_range.end)
15185                    {
15186                        break;
15187                    }
15188                }
15189
15190                selected_larger_node |= new_range != old_range;
15191                Selection {
15192                    id: selection.id,
15193                    start: new_range.start,
15194                    end: new_range.end,
15195                    goal: SelectionGoal::None,
15196                    reversed: selection.reversed,
15197                }
15198            })
15199            .collect::<Vec<_>>();
15200
15201        if !selected_larger_node {
15202            return; // don't put this call in the history
15203        }
15204
15205        // scroll based on transformation done to the last selection created by the user
15206        let (last_old, last_new) = old_selections
15207            .last()
15208            .zip(new_selections.last().cloned())
15209            .expect("old_selections isn't empty");
15210
15211        // revert selection
15212        let is_selection_reversed = {
15213            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15214            new_selections.last_mut().expect("checked above").reversed =
15215                should_newest_selection_be_reversed;
15216            should_newest_selection_be_reversed
15217        };
15218
15219        if selected_larger_node {
15220            self.select_syntax_node_history.disable_clearing = true;
15221            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15222                s.select(new_selections.clone());
15223            });
15224            self.select_syntax_node_history.disable_clearing = false;
15225        }
15226
15227        let start_row = last_new.start.to_display_point(&display_map).row().0;
15228        let end_row = last_new.end.to_display_point(&display_map).row().0;
15229        let selection_height = end_row - start_row + 1;
15230        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15231
15232        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15233        let scroll_behavior = if fits_on_the_screen {
15234            self.request_autoscroll(Autoscroll::fit(), cx);
15235            SelectSyntaxNodeScrollBehavior::FitSelection
15236        } else if is_selection_reversed {
15237            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15238            SelectSyntaxNodeScrollBehavior::CursorTop
15239        } else {
15240            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15241            SelectSyntaxNodeScrollBehavior::CursorBottom
15242        };
15243
15244        self.select_syntax_node_history.push((
15245            old_selections,
15246            scroll_behavior,
15247            is_selection_reversed,
15248        ));
15249    }
15250
15251    pub fn select_smaller_syntax_node(
15252        &mut self,
15253        _: &SelectSmallerSyntaxNode,
15254        window: &mut Window,
15255        cx: &mut Context<Self>,
15256    ) {
15257        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15258
15259        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15260            self.select_syntax_node_history.pop()
15261        {
15262            if let Some(selection) = selections.last_mut() {
15263                selection.reversed = is_selection_reversed;
15264            }
15265
15266            self.select_syntax_node_history.disable_clearing = true;
15267            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15268                s.select(selections.to_vec());
15269            });
15270            self.select_syntax_node_history.disable_clearing = false;
15271
15272            match scroll_behavior {
15273                SelectSyntaxNodeScrollBehavior::CursorTop => {
15274                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15275                }
15276                SelectSyntaxNodeScrollBehavior::FitSelection => {
15277                    self.request_autoscroll(Autoscroll::fit(), cx);
15278                }
15279                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15280                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15281                }
15282            }
15283        }
15284    }
15285
15286    pub fn unwrap_syntax_node(
15287        &mut self,
15288        _: &UnwrapSyntaxNode,
15289        window: &mut Window,
15290        cx: &mut Context<Self>,
15291    ) {
15292        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15293
15294        let buffer = self.buffer.read(cx).snapshot(cx);
15295        let selections = self
15296            .selections
15297            .all::<usize>(cx)
15298            .into_iter()
15299            // subtracting the offset requires sorting
15300            .sorted_by_key(|i| i.start);
15301
15302        let full_edits = selections
15303            .into_iter()
15304            .filter_map(|selection| {
15305                let child = if selection.is_empty()
15306                    && let Some((_, ancestor_range)) =
15307                        buffer.syntax_ancestor(selection.start..selection.end)
15308                {
15309                    ancestor_range
15310                } else {
15311                    selection.range()
15312                };
15313
15314                let mut parent = child.clone();
15315                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15316                    parent = ancestor_range;
15317                    if parent.start < child.start || parent.end > child.end {
15318                        break;
15319                    }
15320                }
15321
15322                if parent == child {
15323                    return None;
15324                }
15325                let text = buffer.text_for_range(child).collect::<String>();
15326                Some((selection.id, parent, text))
15327            })
15328            .collect::<Vec<_>>();
15329        if full_edits.is_empty() {
15330            return;
15331        }
15332
15333        self.transact(window, cx, |this, window, cx| {
15334            this.buffer.update(cx, |buffer, cx| {
15335                buffer.edit(
15336                    full_edits
15337                        .iter()
15338                        .map(|(_, p, t)| (p.clone(), t.clone()))
15339                        .collect::<Vec<_>>(),
15340                    None,
15341                    cx,
15342                );
15343            });
15344            this.change_selections(Default::default(), window, cx, |s| {
15345                let mut offset = 0;
15346                let mut selections = vec![];
15347                for (id, parent, text) in full_edits {
15348                    let start = parent.start - offset;
15349                    offset += parent.len() - text.len();
15350                    selections.push(Selection {
15351                        id,
15352                        start,
15353                        end: start + text.len(),
15354                        reversed: false,
15355                        goal: Default::default(),
15356                    });
15357                }
15358                s.select(selections);
15359            });
15360        });
15361    }
15362
15363    pub fn select_next_syntax_node(
15364        &mut self,
15365        _: &SelectNextSyntaxNode,
15366        window: &mut Window,
15367        cx: &mut Context<Self>,
15368    ) {
15369        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15370        if old_selections.is_empty() {
15371            return;
15372        }
15373
15374        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15375
15376        let buffer = self.buffer.read(cx).snapshot(cx);
15377        let mut selected_sibling = false;
15378
15379        let new_selections = old_selections
15380            .iter()
15381            .map(|selection| {
15382                let old_range = selection.start..selection.end;
15383
15384                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15385                    let new_range = node.byte_range();
15386                    selected_sibling = true;
15387                    Selection {
15388                        id: selection.id,
15389                        start: new_range.start,
15390                        end: new_range.end,
15391                        goal: SelectionGoal::None,
15392                        reversed: selection.reversed,
15393                    }
15394                } else {
15395                    selection.clone()
15396                }
15397            })
15398            .collect::<Vec<_>>();
15399
15400        if selected_sibling {
15401            self.change_selections(
15402                SelectionEffects::scroll(Autoscroll::fit()),
15403                window,
15404                cx,
15405                |s| {
15406                    s.select(new_selections);
15407                },
15408            );
15409        }
15410    }
15411
15412    pub fn select_prev_syntax_node(
15413        &mut self,
15414        _: &SelectPreviousSyntaxNode,
15415        window: &mut Window,
15416        cx: &mut Context<Self>,
15417    ) {
15418        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15419        if old_selections.is_empty() {
15420            return;
15421        }
15422
15423        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15424
15425        let buffer = self.buffer.read(cx).snapshot(cx);
15426        let mut selected_sibling = false;
15427
15428        let new_selections = old_selections
15429            .iter()
15430            .map(|selection| {
15431                let old_range = selection.start..selection.end;
15432
15433                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15434                    let new_range = node.byte_range();
15435                    selected_sibling = true;
15436                    Selection {
15437                        id: selection.id,
15438                        start: new_range.start,
15439                        end: new_range.end,
15440                        goal: SelectionGoal::None,
15441                        reversed: selection.reversed,
15442                    }
15443                } else {
15444                    selection.clone()
15445                }
15446            })
15447            .collect::<Vec<_>>();
15448
15449        if selected_sibling {
15450            self.change_selections(
15451                SelectionEffects::scroll(Autoscroll::fit()),
15452                window,
15453                cx,
15454                |s| {
15455                    s.select(new_selections);
15456                },
15457            );
15458        }
15459    }
15460
15461    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15462        if !EditorSettings::get_global(cx).gutter.runnables {
15463            self.clear_tasks();
15464            return Task::ready(());
15465        }
15466        let project = self.project().map(Entity::downgrade);
15467        let task_sources = self.lsp_task_sources(cx);
15468        let multi_buffer = self.buffer.downgrade();
15469        cx.spawn_in(window, async move |editor, cx| {
15470            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15471            let Some(project) = project.and_then(|p| p.upgrade()) else {
15472                return;
15473            };
15474            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15475                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15476            }) else {
15477                return;
15478            };
15479
15480            let hide_runnables = project
15481                .update(cx, |project, _| project.is_via_collab())
15482                .unwrap_or(true);
15483            if hide_runnables {
15484                return;
15485            }
15486            let new_rows =
15487                cx.background_spawn({
15488                    let snapshot = display_snapshot.clone();
15489                    async move {
15490                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15491                    }
15492                })
15493                    .await;
15494            let Ok(lsp_tasks) =
15495                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15496            else {
15497                return;
15498            };
15499            let lsp_tasks = lsp_tasks.await;
15500
15501            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15502                lsp_tasks
15503                    .into_iter()
15504                    .flat_map(|(kind, tasks)| {
15505                        tasks.into_iter().filter_map(move |(location, task)| {
15506                            Some((kind.clone(), location?, task))
15507                        })
15508                    })
15509                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15510                        let buffer = location.target.buffer;
15511                        let buffer_snapshot = buffer.read(cx).snapshot();
15512                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15513                            |(excerpt_id, snapshot, _)| {
15514                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15515                                    display_snapshot
15516                                        .buffer_snapshot
15517                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15518                                } else {
15519                                    None
15520                                }
15521                            },
15522                        );
15523                        if let Some(offset) = offset {
15524                            let task_buffer_range =
15525                                location.target.range.to_point(&buffer_snapshot);
15526                            let context_buffer_range =
15527                                task_buffer_range.to_offset(&buffer_snapshot);
15528                            let context_range = BufferOffset(context_buffer_range.start)
15529                                ..BufferOffset(context_buffer_range.end);
15530
15531                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15532                                .or_insert_with(|| RunnableTasks {
15533                                    templates: Vec::new(),
15534                                    offset,
15535                                    column: task_buffer_range.start.column,
15536                                    extra_variables: HashMap::default(),
15537                                    context_range,
15538                                })
15539                                .templates
15540                                .push((kind, task.original_task().clone()));
15541                        }
15542
15543                        acc
15544                    })
15545            }) else {
15546                return;
15547            };
15548
15549            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15550                buffer.language_settings(cx).tasks.prefer_lsp
15551            }) else {
15552                return;
15553            };
15554
15555            let rows = Self::runnable_rows(
15556                project,
15557                display_snapshot,
15558                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15559                new_rows,
15560                cx.clone(),
15561            )
15562            .await;
15563            editor
15564                .update(cx, |editor, _| {
15565                    editor.clear_tasks();
15566                    for (key, mut value) in rows {
15567                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15568                            value.templates.extend(lsp_tasks.templates);
15569                        }
15570
15571                        editor.insert_tasks(key, value);
15572                    }
15573                    for (key, value) in lsp_tasks_by_rows {
15574                        editor.insert_tasks(key, value);
15575                    }
15576                })
15577                .ok();
15578        })
15579    }
15580    fn fetch_runnable_ranges(
15581        snapshot: &DisplaySnapshot,
15582        range: Range<Anchor>,
15583    ) -> Vec<language::RunnableRange> {
15584        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15585    }
15586
15587    fn runnable_rows(
15588        project: Entity<Project>,
15589        snapshot: DisplaySnapshot,
15590        prefer_lsp: bool,
15591        runnable_ranges: Vec<RunnableRange>,
15592        cx: AsyncWindowContext,
15593    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15594        cx.spawn(async move |cx| {
15595            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15596            for mut runnable in runnable_ranges {
15597                let Some(tasks) = cx
15598                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15599                    .ok()
15600                else {
15601                    continue;
15602                };
15603                let mut tasks = tasks.await;
15604
15605                if prefer_lsp {
15606                    tasks.retain(|(task_kind, _)| {
15607                        !matches!(task_kind, TaskSourceKind::Language { .. })
15608                    });
15609                }
15610                if tasks.is_empty() {
15611                    continue;
15612                }
15613
15614                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15615                let Some(row) = snapshot
15616                    .buffer_snapshot
15617                    .buffer_line_for_row(MultiBufferRow(point.row))
15618                    .map(|(_, range)| range.start.row)
15619                else {
15620                    continue;
15621                };
15622
15623                let context_range =
15624                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15625                runnable_rows.push((
15626                    (runnable.buffer_id, row),
15627                    RunnableTasks {
15628                        templates: tasks,
15629                        offset: snapshot
15630                            .buffer_snapshot
15631                            .anchor_before(runnable.run_range.start),
15632                        context_range,
15633                        column: point.column,
15634                        extra_variables: runnable.extra_captures,
15635                    },
15636                ));
15637            }
15638            runnable_rows
15639        })
15640    }
15641
15642    fn templates_with_tags(
15643        project: &Entity<Project>,
15644        runnable: &mut Runnable,
15645        cx: &mut App,
15646    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15647        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15648            let (worktree_id, file) = project
15649                .buffer_for_id(runnable.buffer, cx)
15650                .and_then(|buffer| buffer.read(cx).file())
15651                .map(|file| (file.worktree_id(cx), file.clone()))
15652                .unzip();
15653
15654            (
15655                project.task_store().read(cx).task_inventory().cloned(),
15656                worktree_id,
15657                file,
15658            )
15659        });
15660
15661        let tags = mem::take(&mut runnable.tags);
15662        let language = runnable.language.clone();
15663        cx.spawn(async move |cx| {
15664            let mut templates_with_tags = Vec::new();
15665            if let Some(inventory) = inventory {
15666                for RunnableTag(tag) in tags {
15667                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15668                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15669                    }) else {
15670                        return templates_with_tags;
15671                    };
15672                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15673                        move |(_, template)| {
15674                            template.tags.iter().any(|source_tag| source_tag == &tag)
15675                        },
15676                    ));
15677                }
15678            }
15679            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15680
15681            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15682                // Strongest source wins; if we have worktree tag binding, prefer that to
15683                // global and language bindings;
15684                // if we have a global binding, prefer that to language binding.
15685                let first_mismatch = templates_with_tags
15686                    .iter()
15687                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15688                if let Some(index) = first_mismatch {
15689                    templates_with_tags.truncate(index);
15690                }
15691            }
15692
15693            templates_with_tags
15694        })
15695    }
15696
15697    pub fn move_to_enclosing_bracket(
15698        &mut self,
15699        _: &MoveToEnclosingBracket,
15700        window: &mut Window,
15701        cx: &mut Context<Self>,
15702    ) {
15703        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15704        self.change_selections(Default::default(), window, cx, |s| {
15705            s.move_offsets_with(|snapshot, selection| {
15706                let Some(enclosing_bracket_ranges) =
15707                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15708                else {
15709                    return;
15710                };
15711
15712                let mut best_length = usize::MAX;
15713                let mut best_inside = false;
15714                let mut best_in_bracket_range = false;
15715                let mut best_destination = None;
15716                for (open, close) in enclosing_bracket_ranges {
15717                    let close = close.to_inclusive();
15718                    let length = close.end() - open.start;
15719                    let inside = selection.start >= open.end && selection.end <= *close.start();
15720                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15721                        || close.contains(&selection.head());
15722
15723                    // If best is next to a bracket and current isn't, skip
15724                    if !in_bracket_range && best_in_bracket_range {
15725                        continue;
15726                    }
15727
15728                    // Prefer smaller lengths unless best is inside and current isn't
15729                    if length > best_length && (best_inside || !inside) {
15730                        continue;
15731                    }
15732
15733                    best_length = length;
15734                    best_inside = inside;
15735                    best_in_bracket_range = in_bracket_range;
15736                    best_destination = Some(
15737                        if close.contains(&selection.start) && close.contains(&selection.end) {
15738                            if inside { open.end } else { open.start }
15739                        } else if inside {
15740                            *close.start()
15741                        } else {
15742                            *close.end()
15743                        },
15744                    );
15745                }
15746
15747                if let Some(destination) = best_destination {
15748                    selection.collapse_to(destination, SelectionGoal::None);
15749                }
15750            })
15751        });
15752    }
15753
15754    pub fn undo_selection(
15755        &mut self,
15756        _: &UndoSelection,
15757        window: &mut Window,
15758        cx: &mut Context<Self>,
15759    ) {
15760        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15761        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15762            self.selection_history.mode = SelectionHistoryMode::Undoing;
15763            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15764                this.end_selection(window, cx);
15765                this.change_selections(
15766                    SelectionEffects::scroll(Autoscroll::newest()),
15767                    window,
15768                    cx,
15769                    |s| s.select_anchors(entry.selections.to_vec()),
15770                );
15771            });
15772            self.selection_history.mode = SelectionHistoryMode::Normal;
15773
15774            self.select_next_state = entry.select_next_state;
15775            self.select_prev_state = entry.select_prev_state;
15776            self.add_selections_state = entry.add_selections_state;
15777        }
15778    }
15779
15780    pub fn redo_selection(
15781        &mut self,
15782        _: &RedoSelection,
15783        window: &mut Window,
15784        cx: &mut Context<Self>,
15785    ) {
15786        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15787        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15788            self.selection_history.mode = SelectionHistoryMode::Redoing;
15789            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15790                this.end_selection(window, cx);
15791                this.change_selections(
15792                    SelectionEffects::scroll(Autoscroll::newest()),
15793                    window,
15794                    cx,
15795                    |s| s.select_anchors(entry.selections.to_vec()),
15796                );
15797            });
15798            self.selection_history.mode = SelectionHistoryMode::Normal;
15799
15800            self.select_next_state = entry.select_next_state;
15801            self.select_prev_state = entry.select_prev_state;
15802            self.add_selections_state = entry.add_selections_state;
15803        }
15804    }
15805
15806    pub fn expand_excerpts(
15807        &mut self,
15808        action: &ExpandExcerpts,
15809        _: &mut Window,
15810        cx: &mut Context<Self>,
15811    ) {
15812        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15813    }
15814
15815    pub fn expand_excerpts_down(
15816        &mut self,
15817        action: &ExpandExcerptsDown,
15818        _: &mut Window,
15819        cx: &mut Context<Self>,
15820    ) {
15821        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15822    }
15823
15824    pub fn expand_excerpts_up(
15825        &mut self,
15826        action: &ExpandExcerptsUp,
15827        _: &mut Window,
15828        cx: &mut Context<Self>,
15829    ) {
15830        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15831    }
15832
15833    pub fn expand_excerpts_for_direction(
15834        &mut self,
15835        lines: u32,
15836        direction: ExpandExcerptDirection,
15837
15838        cx: &mut Context<Self>,
15839    ) {
15840        let selections = self.selections.disjoint_anchors_arc();
15841
15842        let lines = if lines == 0 {
15843            EditorSettings::get_global(cx).expand_excerpt_lines
15844        } else {
15845            lines
15846        };
15847
15848        self.buffer.update(cx, |buffer, cx| {
15849            let snapshot = buffer.snapshot(cx);
15850            let mut excerpt_ids = selections
15851                .iter()
15852                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15853                .collect::<Vec<_>>();
15854            excerpt_ids.sort();
15855            excerpt_ids.dedup();
15856            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15857        })
15858    }
15859
15860    pub fn expand_excerpt(
15861        &mut self,
15862        excerpt: ExcerptId,
15863        direction: ExpandExcerptDirection,
15864        window: &mut Window,
15865        cx: &mut Context<Self>,
15866    ) {
15867        let current_scroll_position = self.scroll_position(cx);
15868        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15869        let mut should_scroll_up = false;
15870
15871        if direction == ExpandExcerptDirection::Down {
15872            let multi_buffer = self.buffer.read(cx);
15873            let snapshot = multi_buffer.snapshot(cx);
15874            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15875                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15876                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15877            {
15878                let buffer_snapshot = buffer.read(cx).snapshot();
15879                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15880                let last_row = buffer_snapshot.max_point().row;
15881                let lines_below = last_row.saturating_sub(excerpt_end_row);
15882                should_scroll_up = lines_below >= lines_to_expand;
15883            }
15884        }
15885
15886        self.buffer.update(cx, |buffer, cx| {
15887            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15888        });
15889
15890        if should_scroll_up {
15891            let new_scroll_position =
15892                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15893            self.set_scroll_position(new_scroll_position, window, cx);
15894        }
15895    }
15896
15897    pub fn go_to_singleton_buffer_point(
15898        &mut self,
15899        point: Point,
15900        window: &mut Window,
15901        cx: &mut Context<Self>,
15902    ) {
15903        self.go_to_singleton_buffer_range(point..point, window, cx);
15904    }
15905
15906    pub fn go_to_singleton_buffer_range(
15907        &mut self,
15908        range: Range<Point>,
15909        window: &mut Window,
15910        cx: &mut Context<Self>,
15911    ) {
15912        let multibuffer = self.buffer().read(cx);
15913        let Some(buffer) = multibuffer.as_singleton() else {
15914            return;
15915        };
15916        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15917            return;
15918        };
15919        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15920            return;
15921        };
15922        self.change_selections(
15923            SelectionEffects::default().nav_history(true),
15924            window,
15925            cx,
15926            |s| s.select_anchor_ranges([start..end]),
15927        );
15928    }
15929
15930    pub fn go_to_diagnostic(
15931        &mut self,
15932        action: &GoToDiagnostic,
15933        window: &mut Window,
15934        cx: &mut Context<Self>,
15935    ) {
15936        if !self.diagnostics_enabled() {
15937            return;
15938        }
15939        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15940        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15941    }
15942
15943    pub fn go_to_prev_diagnostic(
15944        &mut self,
15945        action: &GoToPreviousDiagnostic,
15946        window: &mut Window,
15947        cx: &mut Context<Self>,
15948    ) {
15949        if !self.diagnostics_enabled() {
15950            return;
15951        }
15952        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15953        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15954    }
15955
15956    pub fn go_to_diagnostic_impl(
15957        &mut self,
15958        direction: Direction,
15959        severity: GoToDiagnosticSeverityFilter,
15960        window: &mut Window,
15961        cx: &mut Context<Self>,
15962    ) {
15963        let buffer = self.buffer.read(cx).snapshot(cx);
15964        let selection = self.selections.newest::<usize>(cx);
15965
15966        let mut active_group_id = None;
15967        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15968            && active_group.active_range.start.to_offset(&buffer) == selection.start
15969        {
15970            active_group_id = Some(active_group.group_id);
15971        }
15972
15973        fn filtered(
15974            snapshot: EditorSnapshot,
15975            severity: GoToDiagnosticSeverityFilter,
15976            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15977        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15978            diagnostics
15979                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15980                .filter(|entry| entry.range.start != entry.range.end)
15981                .filter(|entry| !entry.diagnostic.is_unnecessary)
15982                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15983        }
15984
15985        let snapshot = self.snapshot(window, cx);
15986        let before = filtered(
15987            snapshot.clone(),
15988            severity,
15989            buffer
15990                .diagnostics_in_range(0..selection.start)
15991                .filter(|entry| entry.range.start <= selection.start),
15992        );
15993        let after = filtered(
15994            snapshot,
15995            severity,
15996            buffer
15997                .diagnostics_in_range(selection.start..buffer.len())
15998                .filter(|entry| entry.range.start >= selection.start),
15999        );
16000
16001        let mut found: Option<DiagnosticEntry<usize>> = None;
16002        if direction == Direction::Prev {
16003            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16004            {
16005                for diagnostic in prev_diagnostics.into_iter().rev() {
16006                    if diagnostic.range.start != selection.start
16007                        || active_group_id
16008                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16009                    {
16010                        found = Some(diagnostic);
16011                        break 'outer;
16012                    }
16013                }
16014            }
16015        } else {
16016            for diagnostic in after.chain(before) {
16017                if diagnostic.range.start != selection.start
16018                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16019                {
16020                    found = Some(diagnostic);
16021                    break;
16022                }
16023            }
16024        }
16025        let Some(next_diagnostic) = found else {
16026            return;
16027        };
16028
16029        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16030        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16031            return;
16032        };
16033        self.change_selections(Default::default(), window, cx, |s| {
16034            s.select_ranges(vec![
16035                next_diagnostic.range.start..next_diagnostic.range.start,
16036            ])
16037        });
16038        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16039        self.refresh_edit_prediction(false, true, window, cx);
16040    }
16041
16042    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16044        let snapshot = self.snapshot(window, cx);
16045        let selection = self.selections.newest::<Point>(cx);
16046        self.go_to_hunk_before_or_after_position(
16047            &snapshot,
16048            selection.head(),
16049            Direction::Next,
16050            window,
16051            cx,
16052        );
16053    }
16054
16055    pub fn go_to_hunk_before_or_after_position(
16056        &mut self,
16057        snapshot: &EditorSnapshot,
16058        position: Point,
16059        direction: Direction,
16060        window: &mut Window,
16061        cx: &mut Context<Editor>,
16062    ) {
16063        let row = if direction == Direction::Next {
16064            self.hunk_after_position(snapshot, position)
16065                .map(|hunk| hunk.row_range.start)
16066        } else {
16067            self.hunk_before_position(snapshot, position)
16068        };
16069
16070        if let Some(row) = row {
16071            let destination = Point::new(row.0, 0);
16072            let autoscroll = Autoscroll::center();
16073
16074            self.unfold_ranges(&[destination..destination], false, false, cx);
16075            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16076                s.select_ranges([destination..destination]);
16077            });
16078        }
16079    }
16080
16081    fn hunk_after_position(
16082        &mut self,
16083        snapshot: &EditorSnapshot,
16084        position: Point,
16085    ) -> Option<MultiBufferDiffHunk> {
16086        snapshot
16087            .buffer_snapshot
16088            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16089            .find(|hunk| hunk.row_range.start.0 > position.row)
16090            .or_else(|| {
16091                snapshot
16092                    .buffer_snapshot
16093                    .diff_hunks_in_range(Point::zero()..position)
16094                    .find(|hunk| hunk.row_range.end.0 < position.row)
16095            })
16096    }
16097
16098    fn go_to_prev_hunk(
16099        &mut self,
16100        _: &GoToPreviousHunk,
16101        window: &mut Window,
16102        cx: &mut Context<Self>,
16103    ) {
16104        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16105        let snapshot = self.snapshot(window, cx);
16106        let selection = self.selections.newest::<Point>(cx);
16107        self.go_to_hunk_before_or_after_position(
16108            &snapshot,
16109            selection.head(),
16110            Direction::Prev,
16111            window,
16112            cx,
16113        );
16114    }
16115
16116    fn hunk_before_position(
16117        &mut self,
16118        snapshot: &EditorSnapshot,
16119        position: Point,
16120    ) -> Option<MultiBufferRow> {
16121        snapshot
16122            .buffer_snapshot
16123            .diff_hunk_before(position)
16124            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
16125    }
16126
16127    fn go_to_next_change(
16128        &mut self,
16129        _: &GoToNextChange,
16130        window: &mut Window,
16131        cx: &mut Context<Self>,
16132    ) {
16133        if let Some(selections) = self
16134            .change_list
16135            .next_change(1, Direction::Next)
16136            .map(|s| s.to_vec())
16137        {
16138            self.change_selections(Default::default(), window, cx, |s| {
16139                let map = s.display_map();
16140                s.select_display_ranges(selections.iter().map(|a| {
16141                    let point = a.to_display_point(&map);
16142                    point..point
16143                }))
16144            })
16145        }
16146    }
16147
16148    fn go_to_previous_change(
16149        &mut self,
16150        _: &GoToPreviousChange,
16151        window: &mut Window,
16152        cx: &mut Context<Self>,
16153    ) {
16154        if let Some(selections) = self
16155            .change_list
16156            .next_change(1, Direction::Prev)
16157            .map(|s| s.to_vec())
16158        {
16159            self.change_selections(Default::default(), window, cx, |s| {
16160                let map = s.display_map();
16161                s.select_display_ranges(selections.iter().map(|a| {
16162                    let point = a.to_display_point(&map);
16163                    point..point
16164                }))
16165            })
16166        }
16167    }
16168
16169    pub fn go_to_next_document_highlight(
16170        &mut self,
16171        _: &GoToNextDocumentHighlight,
16172        window: &mut Window,
16173        cx: &mut Context<Self>,
16174    ) {
16175        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16176    }
16177
16178    pub fn go_to_prev_document_highlight(
16179        &mut self,
16180        _: &GoToPreviousDocumentHighlight,
16181        window: &mut Window,
16182        cx: &mut Context<Self>,
16183    ) {
16184        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16185    }
16186
16187    pub fn go_to_document_highlight_before_or_after_position(
16188        &mut self,
16189        direction: Direction,
16190        window: &mut Window,
16191        cx: &mut Context<Editor>,
16192    ) {
16193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16194        let snapshot = self.snapshot(window, cx);
16195        let buffer = &snapshot.buffer_snapshot;
16196        let position = self.selections.newest::<Point>(cx).head();
16197        let anchor_position = buffer.anchor_after(position);
16198
16199        // Get all document highlights (both read and write)
16200        let mut all_highlights = Vec::new();
16201
16202        if let Some((_, read_highlights)) = self
16203            .background_highlights
16204            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16205        {
16206            all_highlights.extend(read_highlights.iter());
16207        }
16208
16209        if let Some((_, write_highlights)) = self
16210            .background_highlights
16211            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16212        {
16213            all_highlights.extend(write_highlights.iter());
16214        }
16215
16216        if all_highlights.is_empty() {
16217            return;
16218        }
16219
16220        // Sort highlights by position
16221        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16222
16223        let target_highlight = match direction {
16224            Direction::Next => {
16225                // Find the first highlight after the current position
16226                all_highlights
16227                    .iter()
16228                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16229            }
16230            Direction::Prev => {
16231                // Find the last highlight before the current position
16232                all_highlights
16233                    .iter()
16234                    .rev()
16235                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16236            }
16237        };
16238
16239        if let Some(highlight) = target_highlight {
16240            let destination = highlight.start.to_point(buffer);
16241            let autoscroll = Autoscroll::center();
16242
16243            self.unfold_ranges(&[destination..destination], false, false, cx);
16244            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16245                s.select_ranges([destination..destination]);
16246            });
16247        }
16248    }
16249
16250    fn go_to_line<T: 'static>(
16251        &mut self,
16252        position: Anchor,
16253        highlight_color: Option<Hsla>,
16254        window: &mut Window,
16255        cx: &mut Context<Self>,
16256    ) {
16257        let snapshot = self.snapshot(window, cx).display_snapshot;
16258        let position = position.to_point(&snapshot.buffer_snapshot);
16259        let start = snapshot
16260            .buffer_snapshot
16261            .clip_point(Point::new(position.row, 0), Bias::Left);
16262        let end = start + Point::new(1, 0);
16263        let start = snapshot.buffer_snapshot.anchor_before(start);
16264        let end = snapshot.buffer_snapshot.anchor_before(end);
16265
16266        self.highlight_rows::<T>(
16267            start..end,
16268            highlight_color
16269                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16270            Default::default(),
16271            cx,
16272        );
16273
16274        if self.buffer.read(cx).is_singleton() {
16275            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16276        }
16277    }
16278
16279    pub fn go_to_definition(
16280        &mut self,
16281        _: &GoToDefinition,
16282        window: &mut Window,
16283        cx: &mut Context<Self>,
16284    ) -> Task<Result<Navigated>> {
16285        let definition =
16286            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16287        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16288        cx.spawn_in(window, async move |editor, cx| {
16289            if definition.await? == Navigated::Yes {
16290                return Ok(Navigated::Yes);
16291            }
16292            match fallback_strategy {
16293                GoToDefinitionFallback::None => Ok(Navigated::No),
16294                GoToDefinitionFallback::FindAllReferences => {
16295                    match editor.update_in(cx, |editor, window, cx| {
16296                        editor.find_all_references(&FindAllReferences, window, cx)
16297                    })? {
16298                        Some(references) => references.await,
16299                        None => Ok(Navigated::No),
16300                    }
16301                }
16302            }
16303        })
16304    }
16305
16306    pub fn go_to_declaration(
16307        &mut self,
16308        _: &GoToDeclaration,
16309        window: &mut Window,
16310        cx: &mut Context<Self>,
16311    ) -> Task<Result<Navigated>> {
16312        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16313    }
16314
16315    pub fn go_to_declaration_split(
16316        &mut self,
16317        _: &GoToDeclaration,
16318        window: &mut Window,
16319        cx: &mut Context<Self>,
16320    ) -> Task<Result<Navigated>> {
16321        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16322    }
16323
16324    pub fn go_to_implementation(
16325        &mut self,
16326        _: &GoToImplementation,
16327        window: &mut Window,
16328        cx: &mut Context<Self>,
16329    ) -> Task<Result<Navigated>> {
16330        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16331    }
16332
16333    pub fn go_to_implementation_split(
16334        &mut self,
16335        _: &GoToImplementationSplit,
16336        window: &mut Window,
16337        cx: &mut Context<Self>,
16338    ) -> Task<Result<Navigated>> {
16339        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16340    }
16341
16342    pub fn go_to_type_definition(
16343        &mut self,
16344        _: &GoToTypeDefinition,
16345        window: &mut Window,
16346        cx: &mut Context<Self>,
16347    ) -> Task<Result<Navigated>> {
16348        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16349    }
16350
16351    pub fn go_to_definition_split(
16352        &mut self,
16353        _: &GoToDefinitionSplit,
16354        window: &mut Window,
16355        cx: &mut Context<Self>,
16356    ) -> Task<Result<Navigated>> {
16357        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16358    }
16359
16360    pub fn go_to_type_definition_split(
16361        &mut self,
16362        _: &GoToTypeDefinitionSplit,
16363        window: &mut Window,
16364        cx: &mut Context<Self>,
16365    ) -> Task<Result<Navigated>> {
16366        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16367    }
16368
16369    fn go_to_definition_of_kind(
16370        &mut self,
16371        kind: GotoDefinitionKind,
16372        split: bool,
16373        window: &mut Window,
16374        cx: &mut Context<Self>,
16375    ) -> Task<Result<Navigated>> {
16376        let Some(provider) = self.semantics_provider.clone() else {
16377            return Task::ready(Ok(Navigated::No));
16378        };
16379        let head = self.selections.newest::<usize>(cx).head();
16380        let buffer = self.buffer.read(cx);
16381        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16382            return Task::ready(Ok(Navigated::No));
16383        };
16384        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16385            return Task::ready(Ok(Navigated::No));
16386        };
16387
16388        cx.spawn_in(window, async move |editor, cx| {
16389            let Some(definitions) = definitions.await? else {
16390                return Ok(Navigated::No);
16391            };
16392            let navigated = editor
16393                .update_in(cx, |editor, window, cx| {
16394                    editor.navigate_to_hover_links(
16395                        Some(kind),
16396                        definitions
16397                            .into_iter()
16398                            .filter(|location| {
16399                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16400                            })
16401                            .map(HoverLink::Text)
16402                            .collect::<Vec<_>>(),
16403                        split,
16404                        window,
16405                        cx,
16406                    )
16407                })?
16408                .await?;
16409            anyhow::Ok(navigated)
16410        })
16411    }
16412
16413    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16414        let selection = self.selections.newest_anchor();
16415        let head = selection.head();
16416        let tail = selection.tail();
16417
16418        let Some((buffer, start_position)) =
16419            self.buffer.read(cx).text_anchor_for_position(head, cx)
16420        else {
16421            return;
16422        };
16423
16424        let end_position = if head != tail {
16425            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16426                return;
16427            };
16428            Some(pos)
16429        } else {
16430            None
16431        };
16432
16433        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16434            let url = if let Some(end_pos) = end_position {
16435                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16436            } else {
16437                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16438            };
16439
16440            if let Some(url) = url {
16441                cx.update(|window, cx| {
16442                    if parse_zed_link(&url, cx).is_some() {
16443                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16444                    } else {
16445                        cx.open_url(&url);
16446                    }
16447                })?;
16448            }
16449
16450            anyhow::Ok(())
16451        });
16452
16453        url_finder.detach();
16454    }
16455
16456    pub fn open_selected_filename(
16457        &mut self,
16458        _: &OpenSelectedFilename,
16459        window: &mut Window,
16460        cx: &mut Context<Self>,
16461    ) {
16462        let Some(workspace) = self.workspace() else {
16463            return;
16464        };
16465
16466        let position = self.selections.newest_anchor().head();
16467
16468        let Some((buffer, buffer_position)) =
16469            self.buffer.read(cx).text_anchor_for_position(position, cx)
16470        else {
16471            return;
16472        };
16473
16474        let project = self.project.clone();
16475
16476        cx.spawn_in(window, async move |_, cx| {
16477            let result = find_file(&buffer, project, buffer_position, cx).await;
16478
16479            if let Some((_, path)) = result {
16480                workspace
16481                    .update_in(cx, |workspace, window, cx| {
16482                        workspace.open_resolved_path(path, window, cx)
16483                    })?
16484                    .await?;
16485            }
16486            anyhow::Ok(())
16487        })
16488        .detach();
16489    }
16490
16491    pub(crate) fn navigate_to_hover_links(
16492        &mut self,
16493        kind: Option<GotoDefinitionKind>,
16494        definitions: Vec<HoverLink>,
16495        split: bool,
16496        window: &mut Window,
16497        cx: &mut Context<Editor>,
16498    ) -> Task<Result<Navigated>> {
16499        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16500        let mut first_url_or_file = None;
16501        let definitions: Vec<_> = definitions
16502            .into_iter()
16503            .filter_map(|def| match def {
16504                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16505                HoverLink::InlayHint(lsp_location, server_id) => {
16506                    let computation =
16507                        self.compute_target_location(lsp_location, server_id, window, cx);
16508                    Some(cx.background_spawn(computation))
16509                }
16510                HoverLink::Url(url) => {
16511                    first_url_or_file = Some(Either::Left(url));
16512                    None
16513                }
16514                HoverLink::File(path) => {
16515                    first_url_or_file = Some(Either::Right(path));
16516                    None
16517                }
16518            })
16519            .collect();
16520
16521        let workspace = self.workspace();
16522
16523        cx.spawn_in(window, async move |editor, cx| {
16524            let locations: Vec<Location> = future::join_all(definitions)
16525                .await
16526                .into_iter()
16527                .filter_map(|location| location.transpose())
16528                .collect::<Result<_>>()
16529                .context("location tasks")?;
16530            let mut locations = cx.update(|_, cx| {
16531                locations
16532                    .into_iter()
16533                    .map(|location| {
16534                        let buffer = location.buffer.read(cx);
16535                        (location.buffer, location.range.to_point(buffer))
16536                    })
16537                    .into_group_map()
16538            })?;
16539            let mut num_locations = 0;
16540            for ranges in locations.values_mut() {
16541                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16542                ranges.dedup();
16543                num_locations += ranges.len();
16544            }
16545
16546            if num_locations > 1 {
16547                let Some(workspace) = workspace else {
16548                    return Ok(Navigated::No);
16549                };
16550
16551                let tab_kind = match kind {
16552                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16553                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16554                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16555                    Some(GotoDefinitionKind::Type) => "Types",
16556                };
16557                let title = editor
16558                    .update_in(cx, |_, _, cx| {
16559                        let target = locations
16560                            .iter()
16561                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16562                            .map(|(buffer, location)| {
16563                                buffer
16564                                    .read(cx)
16565                                    .text_for_range(location.clone())
16566                                    .collect::<String>()
16567                            })
16568                            .filter(|text| !text.contains('\n'))
16569                            .unique()
16570                            .take(3)
16571                            .join(", ");
16572                        if target.is_empty() {
16573                            tab_kind.to_owned()
16574                        } else {
16575                            format!("{tab_kind} for {target}")
16576                        }
16577                    })
16578                    .context("buffer title")?;
16579
16580                let opened = workspace
16581                    .update_in(cx, |workspace, window, cx| {
16582                        Self::open_locations_in_multibuffer(
16583                            workspace,
16584                            locations,
16585                            title,
16586                            split,
16587                            MultibufferSelectionMode::First,
16588                            window,
16589                            cx,
16590                        )
16591                    })
16592                    .is_ok();
16593
16594                anyhow::Ok(Navigated::from_bool(opened))
16595            } else if num_locations == 0 {
16596                // If there is one url or file, open it directly
16597                match first_url_or_file {
16598                    Some(Either::Left(url)) => {
16599                        cx.update(|_, cx| cx.open_url(&url))?;
16600                        Ok(Navigated::Yes)
16601                    }
16602                    Some(Either::Right(path)) => {
16603                        let Some(workspace) = workspace else {
16604                            return Ok(Navigated::No);
16605                        };
16606
16607                        workspace
16608                            .update_in(cx, |workspace, window, cx| {
16609                                workspace.open_resolved_path(path, window, cx)
16610                            })?
16611                            .await?;
16612                        Ok(Navigated::Yes)
16613                    }
16614                    None => Ok(Navigated::No),
16615                }
16616            } else {
16617                let Some(workspace) = workspace else {
16618                    return Ok(Navigated::No);
16619                };
16620
16621                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16622                let target_range = target_ranges.first().unwrap().clone();
16623
16624                editor.update_in(cx, |editor, window, cx| {
16625                    let range = target_range.to_point(target_buffer.read(cx));
16626                    let range = editor.range_for_match(&range);
16627                    let range = collapse_multiline_range(range);
16628
16629                    if !split
16630                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16631                    {
16632                        editor.go_to_singleton_buffer_range(range, window, cx);
16633                    } else {
16634                        let pane = workspace.read(cx).active_pane().clone();
16635                        window.defer(cx, move |window, cx| {
16636                            let target_editor: Entity<Self> =
16637                                workspace.update(cx, |workspace, cx| {
16638                                    let pane = if split {
16639                                        workspace.adjacent_pane(window, cx)
16640                                    } else {
16641                                        workspace.active_pane().clone()
16642                                    };
16643
16644                                    workspace.open_project_item(
16645                                        pane,
16646                                        target_buffer.clone(),
16647                                        true,
16648                                        true,
16649                                        window,
16650                                        cx,
16651                                    )
16652                                });
16653                            target_editor.update(cx, |target_editor, cx| {
16654                                // When selecting a definition in a different buffer, disable the nav history
16655                                // to avoid creating a history entry at the previous cursor location.
16656                                pane.update(cx, |pane, _| pane.disable_history());
16657                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16658                                pane.update(cx, |pane, _| pane.enable_history());
16659                            });
16660                        });
16661                    }
16662                    Navigated::Yes
16663                })
16664            }
16665        })
16666    }
16667
16668    fn compute_target_location(
16669        &self,
16670        lsp_location: lsp::Location,
16671        server_id: LanguageServerId,
16672        window: &mut Window,
16673        cx: &mut Context<Self>,
16674    ) -> Task<anyhow::Result<Option<Location>>> {
16675        let Some(project) = self.project.clone() else {
16676            return Task::ready(Ok(None));
16677        };
16678
16679        cx.spawn_in(window, async move |editor, cx| {
16680            let location_task = editor.update(cx, |_, cx| {
16681                project.update(cx, |project, cx| {
16682                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16683                })
16684            })?;
16685            let location = Some({
16686                let target_buffer_handle = location_task.await.context("open local buffer")?;
16687                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16688                    let target_start = target_buffer
16689                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16690                    let target_end = target_buffer
16691                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16692                    target_buffer.anchor_after(target_start)
16693                        ..target_buffer.anchor_before(target_end)
16694                })?;
16695                Location {
16696                    buffer: target_buffer_handle,
16697                    range,
16698                }
16699            });
16700            Ok(location)
16701        })
16702    }
16703
16704    pub fn find_all_references(
16705        &mut self,
16706        _: &FindAllReferences,
16707        window: &mut Window,
16708        cx: &mut Context<Self>,
16709    ) -> Option<Task<Result<Navigated>>> {
16710        let selection = self.selections.newest::<usize>(cx);
16711        let multi_buffer = self.buffer.read(cx);
16712        let head = selection.head();
16713
16714        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16715        let head_anchor = multi_buffer_snapshot.anchor_at(
16716            head,
16717            if head < selection.tail() {
16718                Bias::Right
16719            } else {
16720                Bias::Left
16721            },
16722        );
16723
16724        match self
16725            .find_all_references_task_sources
16726            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16727        {
16728            Ok(_) => {
16729                log::info!(
16730                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16731                );
16732                return None;
16733            }
16734            Err(i) => {
16735                self.find_all_references_task_sources.insert(i, head_anchor);
16736            }
16737        }
16738
16739        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16740        let workspace = self.workspace()?;
16741        let project = workspace.read(cx).project().clone();
16742        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16743        Some(cx.spawn_in(window, async move |editor, cx| {
16744            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16745                if let Ok(i) = editor
16746                    .find_all_references_task_sources
16747                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16748                {
16749                    editor.find_all_references_task_sources.remove(i);
16750                }
16751            });
16752
16753            let Some(locations) = references.await? else {
16754                return anyhow::Ok(Navigated::No);
16755            };
16756            let mut locations = cx.update(|_, cx| {
16757                locations
16758                    .into_iter()
16759                    .map(|location| {
16760                        let buffer = location.buffer.read(cx);
16761                        (location.buffer, location.range.to_point(buffer))
16762                    })
16763                    .into_group_map()
16764            })?;
16765            if locations.is_empty() {
16766                return anyhow::Ok(Navigated::No);
16767            }
16768            for ranges in locations.values_mut() {
16769                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16770                ranges.dedup();
16771            }
16772
16773            workspace.update_in(cx, |workspace, window, cx| {
16774                let target = locations
16775                    .iter()
16776                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16777                    .map(|(buffer, location)| {
16778                        buffer
16779                            .read(cx)
16780                            .text_for_range(location.clone())
16781                            .collect::<String>()
16782                    })
16783                    .filter(|text| !text.contains('\n'))
16784                    .unique()
16785                    .take(3)
16786                    .join(", ");
16787                let title = if target.is_empty() {
16788                    "References".to_owned()
16789                } else {
16790                    format!("References to {target}")
16791                };
16792                Self::open_locations_in_multibuffer(
16793                    workspace,
16794                    locations,
16795                    title,
16796                    false,
16797                    MultibufferSelectionMode::First,
16798                    window,
16799                    cx,
16800                );
16801                Navigated::Yes
16802            })
16803        }))
16804    }
16805
16806    /// Opens a multibuffer with the given project locations in it
16807    pub fn open_locations_in_multibuffer(
16808        workspace: &mut Workspace,
16809        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16810        title: String,
16811        split: bool,
16812        multibuffer_selection_mode: MultibufferSelectionMode,
16813        window: &mut Window,
16814        cx: &mut Context<Workspace>,
16815    ) {
16816        if locations.is_empty() {
16817            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16818            return;
16819        }
16820
16821        let capability = workspace.project().read(cx).capability();
16822        let mut ranges = <Vec<Range<Anchor>>>::new();
16823
16824        // a key to find existing multibuffer editors with the same set of locations
16825        // to prevent us from opening more and more multibuffer tabs for searches and the like
16826        let mut key = (title.clone(), vec![]);
16827        let excerpt_buffer = cx.new(|cx| {
16828            let key = &mut key.1;
16829            let mut multibuffer = MultiBuffer::new(capability);
16830            for (buffer, mut ranges_for_buffer) in locations {
16831                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16832                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16833                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16834                    PathKey::for_buffer(&buffer, cx),
16835                    buffer.clone(),
16836                    ranges_for_buffer,
16837                    multibuffer_context_lines(cx),
16838                    cx,
16839                );
16840                ranges.extend(new_ranges)
16841            }
16842
16843            multibuffer.with_title(title)
16844        });
16845        let existing = workspace.active_pane().update(cx, |pane, cx| {
16846            pane.items()
16847                .filter_map(|item| item.downcast::<Editor>())
16848                .find(|editor| {
16849                    editor
16850                        .read(cx)
16851                        .lookup_key
16852                        .as_ref()
16853                        .and_then(|it| {
16854                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16855                        })
16856                        .is_some_and(|it| *it == key)
16857                })
16858        });
16859        let editor = existing.unwrap_or_else(|| {
16860            cx.new(|cx| {
16861                let mut editor = Editor::for_multibuffer(
16862                    excerpt_buffer,
16863                    Some(workspace.project().clone()),
16864                    window,
16865                    cx,
16866                );
16867                editor.lookup_key = Some(Box::new(key));
16868                editor
16869            })
16870        });
16871        editor.update(cx, |editor, cx| {
16872            match multibuffer_selection_mode {
16873                MultibufferSelectionMode::First => {
16874                    if let Some(first_range) = ranges.first() {
16875                        editor.change_selections(
16876                            SelectionEffects::no_scroll(),
16877                            window,
16878                            cx,
16879                            |selections| {
16880                                selections.clear_disjoint();
16881                                selections
16882                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16883                            },
16884                        );
16885                    }
16886                    editor.highlight_background::<Self>(
16887                        &ranges,
16888                        |theme| theme.colors().editor_highlighted_line_background,
16889                        cx,
16890                    );
16891                }
16892                MultibufferSelectionMode::All => {
16893                    editor.change_selections(
16894                        SelectionEffects::no_scroll(),
16895                        window,
16896                        cx,
16897                        |selections| {
16898                            selections.clear_disjoint();
16899                            selections.select_anchor_ranges(ranges);
16900                        },
16901                    );
16902                }
16903            }
16904            editor.register_buffers_with_language_servers(cx);
16905        });
16906
16907        let item = Box::new(editor);
16908        let item_id = item.item_id();
16909
16910        if split {
16911            let pane = workspace.adjacent_pane(window, cx);
16912            workspace.add_item(pane, item, None, true, true, window, cx);
16913        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16914            let (preview_item_id, preview_item_idx) =
16915                workspace.active_pane().read_with(cx, |pane, _| {
16916                    (pane.preview_item_id(), pane.preview_item_idx())
16917                });
16918
16919            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16920
16921            if let Some(preview_item_id) = preview_item_id {
16922                workspace.active_pane().update(cx, |pane, cx| {
16923                    pane.remove_item(preview_item_id, false, false, window, cx);
16924                });
16925            }
16926        } else {
16927            workspace.add_item_to_active_pane(item, None, true, window, cx);
16928        }
16929        workspace.active_pane().update(cx, |pane, cx| {
16930            pane.set_preview_item_id(Some(item_id), cx);
16931        });
16932    }
16933
16934    pub fn rename(
16935        &mut self,
16936        _: &Rename,
16937        window: &mut Window,
16938        cx: &mut Context<Self>,
16939    ) -> Option<Task<Result<()>>> {
16940        use language::ToOffset as _;
16941
16942        let provider = self.semantics_provider.clone()?;
16943        let selection = self.selections.newest_anchor().clone();
16944        let (cursor_buffer, cursor_buffer_position) = self
16945            .buffer
16946            .read(cx)
16947            .text_anchor_for_position(selection.head(), cx)?;
16948        let (tail_buffer, cursor_buffer_position_end) = self
16949            .buffer
16950            .read(cx)
16951            .text_anchor_for_position(selection.tail(), cx)?;
16952        if tail_buffer != cursor_buffer {
16953            return None;
16954        }
16955
16956        let snapshot = cursor_buffer.read(cx).snapshot();
16957        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16958        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16959        let prepare_rename = provider
16960            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16961            .unwrap_or_else(|| Task::ready(Ok(None)));
16962        drop(snapshot);
16963
16964        Some(cx.spawn_in(window, async move |this, cx| {
16965            let rename_range = if let Some(range) = prepare_rename.await? {
16966                Some(range)
16967            } else {
16968                this.update(cx, |this, cx| {
16969                    let buffer = this.buffer.read(cx).snapshot(cx);
16970                    let mut buffer_highlights = this
16971                        .document_highlights_for_position(selection.head(), &buffer)
16972                        .filter(|highlight| {
16973                            highlight.start.excerpt_id == selection.head().excerpt_id
16974                                && highlight.end.excerpt_id == selection.head().excerpt_id
16975                        });
16976                    buffer_highlights
16977                        .next()
16978                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16979                })?
16980            };
16981            if let Some(rename_range) = rename_range {
16982                this.update_in(cx, |this, window, cx| {
16983                    let snapshot = cursor_buffer.read(cx).snapshot();
16984                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16985                    let cursor_offset_in_rename_range =
16986                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16987                    let cursor_offset_in_rename_range_end =
16988                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16989
16990                    this.take_rename(false, window, cx);
16991                    let buffer = this.buffer.read(cx).read(cx);
16992                    let cursor_offset = selection.head().to_offset(&buffer);
16993                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16994                    let rename_end = rename_start + rename_buffer_range.len();
16995                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16996                    let mut old_highlight_id = None;
16997                    let old_name: Arc<str> = buffer
16998                        .chunks(rename_start..rename_end, true)
16999                        .map(|chunk| {
17000                            if old_highlight_id.is_none() {
17001                                old_highlight_id = chunk.syntax_highlight_id;
17002                            }
17003                            chunk.text
17004                        })
17005                        .collect::<String>()
17006                        .into();
17007
17008                    drop(buffer);
17009
17010                    // Position the selection in the rename editor so that it matches the current selection.
17011                    this.show_local_selections = false;
17012                    let rename_editor = cx.new(|cx| {
17013                        let mut editor = Editor::single_line(window, cx);
17014                        editor.buffer.update(cx, |buffer, cx| {
17015                            buffer.edit([(0..0, old_name.clone())], None, cx)
17016                        });
17017                        let rename_selection_range = match cursor_offset_in_rename_range
17018                            .cmp(&cursor_offset_in_rename_range_end)
17019                        {
17020                            Ordering::Equal => {
17021                                editor.select_all(&SelectAll, window, cx);
17022                                return editor;
17023                            }
17024                            Ordering::Less => {
17025                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17026                            }
17027                            Ordering::Greater => {
17028                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17029                            }
17030                        };
17031                        if rename_selection_range.end > old_name.len() {
17032                            editor.select_all(&SelectAll, window, cx);
17033                        } else {
17034                            editor.change_selections(Default::default(), window, cx, |s| {
17035                                s.select_ranges([rename_selection_range]);
17036                            });
17037                        }
17038                        editor
17039                    });
17040                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17041                        if e == &EditorEvent::Focused {
17042                            cx.emit(EditorEvent::FocusedIn)
17043                        }
17044                    })
17045                    .detach();
17046
17047                    let write_highlights =
17048                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17049                    let read_highlights =
17050                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17051                    let ranges = write_highlights
17052                        .iter()
17053                        .flat_map(|(_, ranges)| ranges.iter())
17054                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17055                        .cloned()
17056                        .collect();
17057
17058                    this.highlight_text::<Rename>(
17059                        ranges,
17060                        HighlightStyle {
17061                            fade_out: Some(0.6),
17062                            ..Default::default()
17063                        },
17064                        cx,
17065                    );
17066                    let rename_focus_handle = rename_editor.focus_handle(cx);
17067                    window.focus(&rename_focus_handle);
17068                    let block_id = this.insert_blocks(
17069                        [BlockProperties {
17070                            style: BlockStyle::Flex,
17071                            placement: BlockPlacement::Below(range.start),
17072                            height: Some(1),
17073                            render: Arc::new({
17074                                let rename_editor = rename_editor.clone();
17075                                move |cx: &mut BlockContext| {
17076                                    let mut text_style = cx.editor_style.text.clone();
17077                                    if let Some(highlight_style) = old_highlight_id
17078                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17079                                    {
17080                                        text_style = text_style.highlight(highlight_style);
17081                                    }
17082                                    div()
17083                                        .block_mouse_except_scroll()
17084                                        .pl(cx.anchor_x)
17085                                        .child(EditorElement::new(
17086                                            &rename_editor,
17087                                            EditorStyle {
17088                                                background: cx.theme().system().transparent,
17089                                                local_player: cx.editor_style.local_player,
17090                                                text: text_style,
17091                                                scrollbar_width: cx.editor_style.scrollbar_width,
17092                                                syntax: cx.editor_style.syntax.clone(),
17093                                                status: cx.editor_style.status.clone(),
17094                                                inlay_hints_style: HighlightStyle {
17095                                                    font_weight: Some(FontWeight::BOLD),
17096                                                    ..make_inlay_hints_style(cx.app)
17097                                                },
17098                                                edit_prediction_styles: make_suggestion_styles(
17099                                                    cx.app,
17100                                                ),
17101                                                ..EditorStyle::default()
17102                                            },
17103                                        ))
17104                                        .into_any_element()
17105                                }
17106                            }),
17107                            priority: 0,
17108                        }],
17109                        Some(Autoscroll::fit()),
17110                        cx,
17111                    )[0];
17112                    this.pending_rename = Some(RenameState {
17113                        range,
17114                        old_name,
17115                        editor: rename_editor,
17116                        block_id,
17117                    });
17118                })?;
17119            }
17120
17121            Ok(())
17122        }))
17123    }
17124
17125    pub fn confirm_rename(
17126        &mut self,
17127        _: &ConfirmRename,
17128        window: &mut Window,
17129        cx: &mut Context<Self>,
17130    ) -> Option<Task<Result<()>>> {
17131        let rename = self.take_rename(false, window, cx)?;
17132        let workspace = self.workspace()?.downgrade();
17133        let (buffer, start) = self
17134            .buffer
17135            .read(cx)
17136            .text_anchor_for_position(rename.range.start, cx)?;
17137        let (end_buffer, _) = self
17138            .buffer
17139            .read(cx)
17140            .text_anchor_for_position(rename.range.end, cx)?;
17141        if buffer != end_buffer {
17142            return None;
17143        }
17144
17145        let old_name = rename.old_name;
17146        let new_name = rename.editor.read(cx).text(cx);
17147
17148        let rename = self.semantics_provider.as_ref()?.perform_rename(
17149            &buffer,
17150            start,
17151            new_name.clone(),
17152            cx,
17153        )?;
17154
17155        Some(cx.spawn_in(window, async move |editor, cx| {
17156            let project_transaction = rename.await?;
17157            Self::open_project_transaction(
17158                &editor,
17159                workspace,
17160                project_transaction,
17161                format!("Rename: {}{}", old_name, new_name),
17162                cx,
17163            )
17164            .await?;
17165
17166            editor.update(cx, |editor, cx| {
17167                editor.refresh_document_highlights(cx);
17168            })?;
17169            Ok(())
17170        }))
17171    }
17172
17173    fn take_rename(
17174        &mut self,
17175        moving_cursor: bool,
17176        window: &mut Window,
17177        cx: &mut Context<Self>,
17178    ) -> Option<RenameState> {
17179        let rename = self.pending_rename.take()?;
17180        if rename.editor.focus_handle(cx).is_focused(window) {
17181            window.focus(&self.focus_handle);
17182        }
17183
17184        self.remove_blocks(
17185            [rename.block_id].into_iter().collect(),
17186            Some(Autoscroll::fit()),
17187            cx,
17188        );
17189        self.clear_highlights::<Rename>(cx);
17190        self.show_local_selections = true;
17191
17192        if moving_cursor {
17193            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17194                editor.selections.newest::<usize>(cx).head()
17195            });
17196
17197            // Update the selection to match the position of the selection inside
17198            // the rename editor.
17199            let snapshot = self.buffer.read(cx).read(cx);
17200            let rename_range = rename.range.to_offset(&snapshot);
17201            let cursor_in_editor = snapshot
17202                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17203                .min(rename_range.end);
17204            drop(snapshot);
17205
17206            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17207                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17208            });
17209        } else {
17210            self.refresh_document_highlights(cx);
17211        }
17212
17213        Some(rename)
17214    }
17215
17216    pub fn pending_rename(&self) -> Option<&RenameState> {
17217        self.pending_rename.as_ref()
17218    }
17219
17220    fn format(
17221        &mut self,
17222        _: &Format,
17223        window: &mut Window,
17224        cx: &mut Context<Self>,
17225    ) -> Option<Task<Result<()>>> {
17226        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17227
17228        let project = match &self.project {
17229            Some(project) => project.clone(),
17230            None => return None,
17231        };
17232
17233        Some(self.perform_format(
17234            project,
17235            FormatTrigger::Manual,
17236            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17237            window,
17238            cx,
17239        ))
17240    }
17241
17242    fn format_selections(
17243        &mut self,
17244        _: &FormatSelections,
17245        window: &mut Window,
17246        cx: &mut Context<Self>,
17247    ) -> Option<Task<Result<()>>> {
17248        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17249
17250        let project = match &self.project {
17251            Some(project) => project.clone(),
17252            None => return None,
17253        };
17254
17255        let ranges = self
17256            .selections
17257            .all_adjusted(cx)
17258            .into_iter()
17259            .map(|selection| selection.range())
17260            .collect_vec();
17261
17262        Some(self.perform_format(
17263            project,
17264            FormatTrigger::Manual,
17265            FormatTarget::Ranges(ranges),
17266            window,
17267            cx,
17268        ))
17269    }
17270
17271    fn perform_format(
17272        &mut self,
17273        project: Entity<Project>,
17274        trigger: FormatTrigger,
17275        target: FormatTarget,
17276        window: &mut Window,
17277        cx: &mut Context<Self>,
17278    ) -> Task<Result<()>> {
17279        let buffer = self.buffer.clone();
17280        let (buffers, target) = match target {
17281            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17282            FormatTarget::Ranges(selection_ranges) => {
17283                let multi_buffer = buffer.read(cx);
17284                let snapshot = multi_buffer.read(cx);
17285                let mut buffers = HashSet::default();
17286                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17287                    BTreeMap::new();
17288                for selection_range in selection_ranges {
17289                    for (buffer, buffer_range, _) in
17290                        snapshot.range_to_buffer_ranges(selection_range)
17291                    {
17292                        let buffer_id = buffer.remote_id();
17293                        let start = buffer.anchor_before(buffer_range.start);
17294                        let end = buffer.anchor_after(buffer_range.end);
17295                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17296                        buffer_id_to_ranges
17297                            .entry(buffer_id)
17298                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17299                            .or_insert_with(|| vec![start..end]);
17300                    }
17301                }
17302                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17303            }
17304        };
17305
17306        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17307        let selections_prev = transaction_id_prev
17308            .and_then(|transaction_id_prev| {
17309                // default to selections as they were after the last edit, if we have them,
17310                // instead of how they are now.
17311                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17312                // will take you back to where you made the last edit, instead of staying where you scrolled
17313                self.selection_history
17314                    .transaction(transaction_id_prev)
17315                    .map(|t| t.0.clone())
17316            })
17317            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17318
17319        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17320        let format = project.update(cx, |project, cx| {
17321            project.format(buffers, target, true, trigger, cx)
17322        });
17323
17324        cx.spawn_in(window, async move |editor, cx| {
17325            let transaction = futures::select_biased! {
17326                transaction = format.log_err().fuse() => transaction,
17327                () = timeout => {
17328                    log::warn!("timed out waiting for formatting");
17329                    None
17330                }
17331            };
17332
17333            buffer
17334                .update(cx, |buffer, cx| {
17335                    if let Some(transaction) = transaction
17336                        && !buffer.is_singleton()
17337                    {
17338                        buffer.push_transaction(&transaction.0, cx);
17339                    }
17340                    cx.notify();
17341                })
17342                .ok();
17343
17344            if let Some(transaction_id_now) =
17345                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17346            {
17347                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17348                if has_new_transaction {
17349                    _ = editor.update(cx, |editor, _| {
17350                        editor
17351                            .selection_history
17352                            .insert_transaction(transaction_id_now, selections_prev);
17353                    });
17354                }
17355            }
17356
17357            Ok(())
17358        })
17359    }
17360
17361    fn organize_imports(
17362        &mut self,
17363        _: &OrganizeImports,
17364        window: &mut Window,
17365        cx: &mut Context<Self>,
17366    ) -> Option<Task<Result<()>>> {
17367        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17368        let project = match &self.project {
17369            Some(project) => project.clone(),
17370            None => return None,
17371        };
17372        Some(self.perform_code_action_kind(
17373            project,
17374            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17375            window,
17376            cx,
17377        ))
17378    }
17379
17380    fn perform_code_action_kind(
17381        &mut self,
17382        project: Entity<Project>,
17383        kind: CodeActionKind,
17384        window: &mut Window,
17385        cx: &mut Context<Self>,
17386    ) -> Task<Result<()>> {
17387        let buffer = self.buffer.clone();
17388        let buffers = buffer.read(cx).all_buffers();
17389        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17390        let apply_action = project.update(cx, |project, cx| {
17391            project.apply_code_action_kind(buffers, kind, true, cx)
17392        });
17393        cx.spawn_in(window, async move |_, cx| {
17394            let transaction = futures::select_biased! {
17395                () = timeout => {
17396                    log::warn!("timed out waiting for executing code action");
17397                    None
17398                }
17399                transaction = apply_action.log_err().fuse() => transaction,
17400            };
17401            buffer
17402                .update(cx, |buffer, cx| {
17403                    // check if we need this
17404                    if let Some(transaction) = transaction
17405                        && !buffer.is_singleton()
17406                    {
17407                        buffer.push_transaction(&transaction.0, cx);
17408                    }
17409                    cx.notify();
17410                })
17411                .ok();
17412            Ok(())
17413        })
17414    }
17415
17416    pub fn restart_language_server(
17417        &mut self,
17418        _: &RestartLanguageServer,
17419        _: &mut Window,
17420        cx: &mut Context<Self>,
17421    ) {
17422        if let Some(project) = self.project.clone() {
17423            self.buffer.update(cx, |multi_buffer, cx| {
17424                project.update(cx, |project, cx| {
17425                    project.restart_language_servers_for_buffers(
17426                        multi_buffer.all_buffers().into_iter().collect(),
17427                        HashSet::default(),
17428                        cx,
17429                    );
17430                });
17431            })
17432        }
17433    }
17434
17435    pub fn stop_language_server(
17436        &mut self,
17437        _: &StopLanguageServer,
17438        _: &mut Window,
17439        cx: &mut Context<Self>,
17440    ) {
17441        if let Some(project) = self.project.clone() {
17442            self.buffer.update(cx, |multi_buffer, cx| {
17443                project.update(cx, |project, cx| {
17444                    project.stop_language_servers_for_buffers(
17445                        multi_buffer.all_buffers().into_iter().collect(),
17446                        HashSet::default(),
17447                        cx,
17448                    );
17449                    cx.emit(project::Event::RefreshInlayHints);
17450                });
17451            });
17452        }
17453    }
17454
17455    fn cancel_language_server_work(
17456        workspace: &mut Workspace,
17457        _: &actions::CancelLanguageServerWork,
17458        _: &mut Window,
17459        cx: &mut Context<Workspace>,
17460    ) {
17461        let project = workspace.project();
17462        let buffers = workspace
17463            .active_item(cx)
17464            .and_then(|item| item.act_as::<Editor>(cx))
17465            .map_or(HashSet::default(), |editor| {
17466                editor.read(cx).buffer.read(cx).all_buffers()
17467            });
17468        project.update(cx, |project, cx| {
17469            project.cancel_language_server_work_for_buffers(buffers, cx);
17470        });
17471    }
17472
17473    fn show_character_palette(
17474        &mut self,
17475        _: &ShowCharacterPalette,
17476        window: &mut Window,
17477        _: &mut Context<Self>,
17478    ) {
17479        window.show_character_palette();
17480    }
17481
17482    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17483        if !self.diagnostics_enabled() {
17484            return;
17485        }
17486
17487        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17488            let buffer = self.buffer.read(cx).snapshot(cx);
17489            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17490            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17491            let is_valid = buffer
17492                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17493                .any(|entry| {
17494                    entry.diagnostic.is_primary
17495                        && !entry.range.is_empty()
17496                        && entry.range.start == primary_range_start
17497                        && entry.diagnostic.message == active_diagnostics.active_message
17498                });
17499
17500            if !is_valid {
17501                self.dismiss_diagnostics(cx);
17502            }
17503        }
17504    }
17505
17506    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17507        match &self.active_diagnostics {
17508            ActiveDiagnostic::Group(group) => Some(group),
17509            _ => None,
17510        }
17511    }
17512
17513    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17514        if !self.diagnostics_enabled() {
17515            return;
17516        }
17517        self.dismiss_diagnostics(cx);
17518        self.active_diagnostics = ActiveDiagnostic::All;
17519    }
17520
17521    fn activate_diagnostics(
17522        &mut self,
17523        buffer_id: BufferId,
17524        diagnostic: DiagnosticEntry<usize>,
17525        window: &mut Window,
17526        cx: &mut Context<Self>,
17527    ) {
17528        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17529            return;
17530        }
17531        self.dismiss_diagnostics(cx);
17532        let snapshot = self.snapshot(window, cx);
17533        let buffer = self.buffer.read(cx).snapshot(cx);
17534        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17535            return;
17536        };
17537
17538        let diagnostic_group = buffer
17539            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17540            .collect::<Vec<_>>();
17541
17542        let blocks =
17543            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17544
17545        let blocks = self.display_map.update(cx, |display_map, cx| {
17546            display_map.insert_blocks(blocks, cx).into_iter().collect()
17547        });
17548        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17549            active_range: buffer.anchor_before(diagnostic.range.start)
17550                ..buffer.anchor_after(diagnostic.range.end),
17551            active_message: diagnostic.diagnostic.message.clone(),
17552            group_id: diagnostic.diagnostic.group_id,
17553            blocks,
17554        });
17555        cx.notify();
17556    }
17557
17558    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17559        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17560            return;
17561        };
17562
17563        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17564        if let ActiveDiagnostic::Group(group) = prev {
17565            self.display_map.update(cx, |display_map, cx| {
17566                display_map.remove_blocks(group.blocks, cx);
17567            });
17568            cx.notify();
17569        }
17570    }
17571
17572    /// Disable inline diagnostics rendering for this editor.
17573    pub fn disable_inline_diagnostics(&mut self) {
17574        self.inline_diagnostics_enabled = false;
17575        self.inline_diagnostics_update = Task::ready(());
17576        self.inline_diagnostics.clear();
17577    }
17578
17579    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17580        self.diagnostics_enabled = false;
17581        self.dismiss_diagnostics(cx);
17582        self.inline_diagnostics_update = Task::ready(());
17583        self.inline_diagnostics.clear();
17584    }
17585
17586    pub fn disable_word_completions(&mut self) {
17587        self.word_completions_enabled = false;
17588    }
17589
17590    pub fn diagnostics_enabled(&self) -> bool {
17591        self.diagnostics_enabled && self.mode.is_full()
17592    }
17593
17594    pub fn inline_diagnostics_enabled(&self) -> bool {
17595        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17596    }
17597
17598    pub fn show_inline_diagnostics(&self) -> bool {
17599        self.show_inline_diagnostics
17600    }
17601
17602    pub fn toggle_inline_diagnostics(
17603        &mut self,
17604        _: &ToggleInlineDiagnostics,
17605        window: &mut Window,
17606        cx: &mut Context<Editor>,
17607    ) {
17608        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17609        self.refresh_inline_diagnostics(false, window, cx);
17610    }
17611
17612    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17613        self.diagnostics_max_severity = severity;
17614        self.display_map.update(cx, |display_map, _| {
17615            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17616        });
17617    }
17618
17619    pub fn toggle_diagnostics(
17620        &mut self,
17621        _: &ToggleDiagnostics,
17622        window: &mut Window,
17623        cx: &mut Context<Editor>,
17624    ) {
17625        if !self.diagnostics_enabled() {
17626            return;
17627        }
17628
17629        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17630            EditorSettings::get_global(cx)
17631                .diagnostics_max_severity
17632                .filter(|severity| severity != &DiagnosticSeverity::Off)
17633                .unwrap_or(DiagnosticSeverity::Hint)
17634        } else {
17635            DiagnosticSeverity::Off
17636        };
17637        self.set_max_diagnostics_severity(new_severity, cx);
17638        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17639            self.active_diagnostics = ActiveDiagnostic::None;
17640            self.inline_diagnostics_update = Task::ready(());
17641            self.inline_diagnostics.clear();
17642        } else {
17643            self.refresh_inline_diagnostics(false, window, cx);
17644        }
17645
17646        cx.notify();
17647    }
17648
17649    pub fn toggle_minimap(
17650        &mut self,
17651        _: &ToggleMinimap,
17652        window: &mut Window,
17653        cx: &mut Context<Editor>,
17654    ) {
17655        if self.supports_minimap(cx) {
17656            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17657        }
17658    }
17659
17660    fn refresh_inline_diagnostics(
17661        &mut self,
17662        debounce: bool,
17663        window: &mut Window,
17664        cx: &mut Context<Self>,
17665    ) {
17666        let max_severity = ProjectSettings::get_global(cx)
17667            .diagnostics
17668            .inline
17669            .max_severity
17670            .unwrap_or(self.diagnostics_max_severity);
17671
17672        if !self.inline_diagnostics_enabled()
17673            || !self.show_inline_diagnostics
17674            || max_severity == DiagnosticSeverity::Off
17675        {
17676            self.inline_diagnostics_update = Task::ready(());
17677            self.inline_diagnostics.clear();
17678            return;
17679        }
17680
17681        let debounce_ms = ProjectSettings::get_global(cx)
17682            .diagnostics
17683            .inline
17684            .update_debounce_ms;
17685        let debounce = if debounce && debounce_ms > 0 {
17686            Some(Duration::from_millis(debounce_ms))
17687        } else {
17688            None
17689        };
17690        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17691            if let Some(debounce) = debounce {
17692                cx.background_executor().timer(debounce).await;
17693            }
17694            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17695                editor
17696                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17697                    .ok()
17698            }) else {
17699                return;
17700            };
17701
17702            let new_inline_diagnostics = cx
17703                .background_spawn(async move {
17704                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17705                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17706                        let message = diagnostic_entry
17707                            .diagnostic
17708                            .message
17709                            .split_once('\n')
17710                            .map(|(line, _)| line)
17711                            .map(SharedString::new)
17712                            .unwrap_or_else(|| {
17713                                SharedString::from(diagnostic_entry.diagnostic.message)
17714                            });
17715                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17716                        let (Ok(i) | Err(i)) = inline_diagnostics
17717                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17718                        inline_diagnostics.insert(
17719                            i,
17720                            (
17721                                start_anchor,
17722                                InlineDiagnostic {
17723                                    message,
17724                                    group_id: diagnostic_entry.diagnostic.group_id,
17725                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17726                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17727                                    severity: diagnostic_entry.diagnostic.severity,
17728                                },
17729                            ),
17730                        );
17731                    }
17732                    inline_diagnostics
17733                })
17734                .await;
17735
17736            editor
17737                .update(cx, |editor, cx| {
17738                    editor.inline_diagnostics = new_inline_diagnostics;
17739                    cx.notify();
17740                })
17741                .ok();
17742        });
17743    }
17744
17745    fn pull_diagnostics(
17746        &mut self,
17747        buffer_id: Option<BufferId>,
17748        window: &Window,
17749        cx: &mut Context<Self>,
17750    ) -> Option<()> {
17751        if !self.mode().is_full() {
17752            return None;
17753        }
17754        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17755            .diagnostics
17756            .lsp_pull_diagnostics;
17757        if !pull_diagnostics_settings.enabled {
17758            return None;
17759        }
17760        let project = self.project()?.downgrade();
17761        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17762        let mut buffers = self.buffer.read(cx).all_buffers();
17763        if let Some(buffer_id) = buffer_id {
17764            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17765        }
17766
17767        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17768            cx.background_executor().timer(debounce).await;
17769
17770            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17771                buffers
17772                    .into_iter()
17773                    .filter_map(|buffer| {
17774                        project
17775                            .update(cx, |project, cx| {
17776                                project.lsp_store().update(cx, |lsp_store, cx| {
17777                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17778                                })
17779                            })
17780                            .ok()
17781                    })
17782                    .collect::<FuturesUnordered<_>>()
17783            }) else {
17784                return;
17785            };
17786
17787            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17788                match pull_task {
17789                    Ok(()) => {
17790                        if editor
17791                            .update_in(cx, |editor, window, cx| {
17792                                editor.update_diagnostics_state(window, cx);
17793                            })
17794                            .is_err()
17795                        {
17796                            return;
17797                        }
17798                    }
17799                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17800                }
17801            }
17802        });
17803
17804        Some(())
17805    }
17806
17807    pub fn set_selections_from_remote(
17808        &mut self,
17809        selections: Vec<Selection<Anchor>>,
17810        pending_selection: Option<Selection<Anchor>>,
17811        window: &mut Window,
17812        cx: &mut Context<Self>,
17813    ) {
17814        let old_cursor_position = self.selections.newest_anchor().head();
17815        self.selections.change_with(cx, |s| {
17816            s.select_anchors(selections);
17817            if let Some(pending_selection) = pending_selection {
17818                s.set_pending(pending_selection, SelectMode::Character);
17819            } else {
17820                s.clear_pending();
17821            }
17822        });
17823        self.selections_did_change(
17824            false,
17825            &old_cursor_position,
17826            SelectionEffects::default(),
17827            window,
17828            cx,
17829        );
17830    }
17831
17832    pub fn transact(
17833        &mut self,
17834        window: &mut Window,
17835        cx: &mut Context<Self>,
17836        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17837    ) -> Option<TransactionId> {
17838        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17839            this.start_transaction_at(Instant::now(), window, cx);
17840            update(this, window, cx);
17841            this.end_transaction_at(Instant::now(), cx)
17842        })
17843    }
17844
17845    pub fn start_transaction_at(
17846        &mut self,
17847        now: Instant,
17848        window: &mut Window,
17849        cx: &mut Context<Self>,
17850    ) -> Option<TransactionId> {
17851        self.end_selection(window, cx);
17852        if let Some(tx_id) = self
17853            .buffer
17854            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17855        {
17856            self.selection_history
17857                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17858            cx.emit(EditorEvent::TransactionBegun {
17859                transaction_id: tx_id,
17860            });
17861            Some(tx_id)
17862        } else {
17863            None
17864        }
17865    }
17866
17867    pub fn end_transaction_at(
17868        &mut self,
17869        now: Instant,
17870        cx: &mut Context<Self>,
17871    ) -> Option<TransactionId> {
17872        if let Some(transaction_id) = self
17873            .buffer
17874            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17875        {
17876            if let Some((_, end_selections)) =
17877                self.selection_history.transaction_mut(transaction_id)
17878            {
17879                *end_selections = Some(self.selections.disjoint_anchors_arc());
17880            } else {
17881                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17882            }
17883
17884            cx.emit(EditorEvent::Edited { transaction_id });
17885            Some(transaction_id)
17886        } else {
17887            None
17888        }
17889    }
17890
17891    pub fn modify_transaction_selection_history(
17892        &mut self,
17893        transaction_id: TransactionId,
17894        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17895    ) -> bool {
17896        self.selection_history
17897            .transaction_mut(transaction_id)
17898            .map(modify)
17899            .is_some()
17900    }
17901
17902    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17903        if self.selection_mark_mode {
17904            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17905                s.move_with(|_, sel| {
17906                    sel.collapse_to(sel.head(), SelectionGoal::None);
17907                });
17908            })
17909        }
17910        self.selection_mark_mode = true;
17911        cx.notify();
17912    }
17913
17914    pub fn swap_selection_ends(
17915        &mut self,
17916        _: &actions::SwapSelectionEnds,
17917        window: &mut Window,
17918        cx: &mut Context<Self>,
17919    ) {
17920        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17921            s.move_with(|_, sel| {
17922                if sel.start != sel.end {
17923                    sel.reversed = !sel.reversed
17924                }
17925            });
17926        });
17927        self.request_autoscroll(Autoscroll::newest(), cx);
17928        cx.notify();
17929    }
17930
17931    pub fn toggle_focus(
17932        workspace: &mut Workspace,
17933        _: &actions::ToggleFocus,
17934        window: &mut Window,
17935        cx: &mut Context<Workspace>,
17936    ) {
17937        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17938            return;
17939        };
17940        workspace.activate_item(&item, true, true, window, cx);
17941    }
17942
17943    pub fn toggle_fold(
17944        &mut self,
17945        _: &actions::ToggleFold,
17946        window: &mut Window,
17947        cx: &mut Context<Self>,
17948    ) {
17949        if self.is_singleton(cx) {
17950            let selection = self.selections.newest::<Point>(cx);
17951
17952            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17953            let range = if selection.is_empty() {
17954                let point = selection.head().to_display_point(&display_map);
17955                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17956                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17957                    .to_point(&display_map);
17958                start..end
17959            } else {
17960                selection.range()
17961            };
17962            if display_map.folds_in_range(range).next().is_some() {
17963                self.unfold_lines(&Default::default(), window, cx)
17964            } else {
17965                self.fold(&Default::default(), window, cx)
17966            }
17967        } else {
17968            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17969            let buffer_ids: HashSet<_> = self
17970                .selections
17971                .disjoint_anchor_ranges()
17972                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17973                .collect();
17974
17975            let should_unfold = buffer_ids
17976                .iter()
17977                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17978
17979            for buffer_id in buffer_ids {
17980                if should_unfold {
17981                    self.unfold_buffer(buffer_id, cx);
17982                } else {
17983                    self.fold_buffer(buffer_id, cx);
17984                }
17985            }
17986        }
17987    }
17988
17989    pub fn toggle_fold_recursive(
17990        &mut self,
17991        _: &actions::ToggleFoldRecursive,
17992        window: &mut Window,
17993        cx: &mut Context<Self>,
17994    ) {
17995        let selection = self.selections.newest::<Point>(cx);
17996
17997        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17998        let range = if selection.is_empty() {
17999            let point = selection.head().to_display_point(&display_map);
18000            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18001            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18002                .to_point(&display_map);
18003            start..end
18004        } else {
18005            selection.range()
18006        };
18007        if display_map.folds_in_range(range).next().is_some() {
18008            self.unfold_recursive(&Default::default(), window, cx)
18009        } else {
18010            self.fold_recursive(&Default::default(), window, cx)
18011        }
18012    }
18013
18014    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18015        if self.is_singleton(cx) {
18016            let mut to_fold = Vec::new();
18017            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18018            let selections = self.selections.all_adjusted(cx);
18019
18020            for selection in selections {
18021                let range = selection.range().sorted();
18022                let buffer_start_row = range.start.row;
18023
18024                if range.start.row != range.end.row {
18025                    let mut found = false;
18026                    let mut row = range.start.row;
18027                    while row <= range.end.row {
18028                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18029                        {
18030                            found = true;
18031                            row = crease.range().end.row + 1;
18032                            to_fold.push(crease);
18033                        } else {
18034                            row += 1
18035                        }
18036                    }
18037                    if found {
18038                        continue;
18039                    }
18040                }
18041
18042                for row in (0..=range.start.row).rev() {
18043                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18044                        && crease.range().end.row >= buffer_start_row
18045                    {
18046                        to_fold.push(crease);
18047                        if row <= range.start.row {
18048                            break;
18049                        }
18050                    }
18051                }
18052            }
18053
18054            self.fold_creases(to_fold, true, window, cx);
18055        } else {
18056            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18057            let buffer_ids = self
18058                .selections
18059                .disjoint_anchor_ranges()
18060                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18061                .collect::<HashSet<_>>();
18062            for buffer_id in buffer_ids {
18063                self.fold_buffer(buffer_id, cx);
18064            }
18065        }
18066    }
18067
18068    pub fn toggle_fold_all(
18069        &mut self,
18070        _: &actions::ToggleFoldAll,
18071        window: &mut Window,
18072        cx: &mut Context<Self>,
18073    ) {
18074        if self.buffer.read(cx).is_singleton() {
18075            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18076            let has_folds = display_map
18077                .folds_in_range(0..display_map.buffer_snapshot.len())
18078                .next()
18079                .is_some();
18080
18081            if has_folds {
18082                self.unfold_all(&actions::UnfoldAll, window, cx);
18083            } else {
18084                self.fold_all(&actions::FoldAll, window, cx);
18085            }
18086        } else {
18087            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18088            let should_unfold = buffer_ids
18089                .iter()
18090                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18091
18092            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18093                editor
18094                    .update_in(cx, |editor, _, cx| {
18095                        for buffer_id in buffer_ids {
18096                            if should_unfold {
18097                                editor.unfold_buffer(buffer_id, cx);
18098                            } else {
18099                                editor.fold_buffer(buffer_id, cx);
18100                            }
18101                        }
18102                    })
18103                    .ok();
18104            });
18105        }
18106    }
18107
18108    fn fold_at_level(
18109        &mut self,
18110        fold_at: &FoldAtLevel,
18111        window: &mut Window,
18112        cx: &mut Context<Self>,
18113    ) {
18114        if !self.buffer.read(cx).is_singleton() {
18115            return;
18116        }
18117
18118        let fold_at_level = fold_at.0;
18119        let snapshot = self.buffer.read(cx).snapshot(cx);
18120        let mut to_fold = Vec::new();
18121        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18122
18123        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18124            while start_row < end_row {
18125                match self
18126                    .snapshot(window, cx)
18127                    .crease_for_buffer_row(MultiBufferRow(start_row))
18128                {
18129                    Some(crease) => {
18130                        let nested_start_row = crease.range().start.row + 1;
18131                        let nested_end_row = crease.range().end.row;
18132
18133                        if current_level < fold_at_level {
18134                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18135                        } else if current_level == fold_at_level {
18136                            to_fold.push(crease);
18137                        }
18138
18139                        start_row = nested_end_row + 1;
18140                    }
18141                    None => start_row += 1,
18142                }
18143            }
18144        }
18145
18146        self.fold_creases(to_fold, true, window, cx);
18147    }
18148
18149    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18150        if self.buffer.read(cx).is_singleton() {
18151            let mut fold_ranges = Vec::new();
18152            let snapshot = self.buffer.read(cx).snapshot(cx);
18153
18154            for row in 0..snapshot.max_row().0 {
18155                if let Some(foldable_range) = self
18156                    .snapshot(window, cx)
18157                    .crease_for_buffer_row(MultiBufferRow(row))
18158                {
18159                    fold_ranges.push(foldable_range);
18160                }
18161            }
18162
18163            self.fold_creases(fold_ranges, true, window, cx);
18164        } else {
18165            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18166                editor
18167                    .update_in(cx, |editor, _, cx| {
18168                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18169                            editor.fold_buffer(buffer_id, cx);
18170                        }
18171                    })
18172                    .ok();
18173            });
18174        }
18175    }
18176
18177    pub fn fold_function_bodies(
18178        &mut self,
18179        _: &actions::FoldFunctionBodies,
18180        window: &mut Window,
18181        cx: &mut Context<Self>,
18182    ) {
18183        let snapshot = self.buffer.read(cx).snapshot(cx);
18184
18185        let ranges = snapshot
18186            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18187            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18188            .collect::<Vec<_>>();
18189
18190        let creases = ranges
18191            .into_iter()
18192            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18193            .collect();
18194
18195        self.fold_creases(creases, true, window, cx);
18196    }
18197
18198    pub fn fold_recursive(
18199        &mut self,
18200        _: &actions::FoldRecursive,
18201        window: &mut Window,
18202        cx: &mut Context<Self>,
18203    ) {
18204        let mut to_fold = Vec::new();
18205        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18206        let selections = self.selections.all_adjusted(cx);
18207
18208        for selection in selections {
18209            let range = selection.range().sorted();
18210            let buffer_start_row = range.start.row;
18211
18212            if range.start.row != range.end.row {
18213                let mut found = false;
18214                for row in range.start.row..=range.end.row {
18215                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18216                        found = true;
18217                        to_fold.push(crease);
18218                    }
18219                }
18220                if found {
18221                    continue;
18222                }
18223            }
18224
18225            for row in (0..=range.start.row).rev() {
18226                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18227                    if crease.range().end.row >= buffer_start_row {
18228                        to_fold.push(crease);
18229                    } else {
18230                        break;
18231                    }
18232                }
18233            }
18234        }
18235
18236        self.fold_creases(to_fold, true, window, cx);
18237    }
18238
18239    pub fn fold_at(
18240        &mut self,
18241        buffer_row: MultiBufferRow,
18242        window: &mut Window,
18243        cx: &mut Context<Self>,
18244    ) {
18245        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18246
18247        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18248            let autoscroll = self
18249                .selections
18250                .all::<Point>(cx)
18251                .iter()
18252                .any(|selection| crease.range().overlaps(&selection.range()));
18253
18254            self.fold_creases(vec![crease], autoscroll, window, cx);
18255        }
18256    }
18257
18258    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18259        if self.is_singleton(cx) {
18260            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18261            let buffer = &display_map.buffer_snapshot;
18262            let selections = self.selections.all::<Point>(cx);
18263            let ranges = selections
18264                .iter()
18265                .map(|s| {
18266                    let range = s.display_range(&display_map).sorted();
18267                    let mut start = range.start.to_point(&display_map);
18268                    let mut end = range.end.to_point(&display_map);
18269                    start.column = 0;
18270                    end.column = buffer.line_len(MultiBufferRow(end.row));
18271                    start..end
18272                })
18273                .collect::<Vec<_>>();
18274
18275            self.unfold_ranges(&ranges, true, true, cx);
18276        } else {
18277            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18278            let buffer_ids = self
18279                .selections
18280                .disjoint_anchor_ranges()
18281                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18282                .collect::<HashSet<_>>();
18283            for buffer_id in buffer_ids {
18284                self.unfold_buffer(buffer_id, cx);
18285            }
18286        }
18287    }
18288
18289    pub fn unfold_recursive(
18290        &mut self,
18291        _: &UnfoldRecursive,
18292        _window: &mut Window,
18293        cx: &mut Context<Self>,
18294    ) {
18295        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18296        let selections = self.selections.all::<Point>(cx);
18297        let ranges = selections
18298            .iter()
18299            .map(|s| {
18300                let mut range = s.display_range(&display_map).sorted();
18301                *range.start.column_mut() = 0;
18302                *range.end.column_mut() = display_map.line_len(range.end.row());
18303                let start = range.start.to_point(&display_map);
18304                let end = range.end.to_point(&display_map);
18305                start..end
18306            })
18307            .collect::<Vec<_>>();
18308
18309        self.unfold_ranges(&ranges, true, true, cx);
18310    }
18311
18312    pub fn unfold_at(
18313        &mut self,
18314        buffer_row: MultiBufferRow,
18315        _window: &mut Window,
18316        cx: &mut Context<Self>,
18317    ) {
18318        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18319
18320        let intersection_range = Point::new(buffer_row.0, 0)
18321            ..Point::new(
18322                buffer_row.0,
18323                display_map.buffer_snapshot.line_len(buffer_row),
18324            );
18325
18326        let autoscroll = self
18327            .selections
18328            .all::<Point>(cx)
18329            .iter()
18330            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18331
18332        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18333    }
18334
18335    pub fn unfold_all(
18336        &mut self,
18337        _: &actions::UnfoldAll,
18338        _window: &mut Window,
18339        cx: &mut Context<Self>,
18340    ) {
18341        if self.buffer.read(cx).is_singleton() {
18342            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18343            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18344        } else {
18345            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18346                editor
18347                    .update(cx, |editor, cx| {
18348                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18349                            editor.unfold_buffer(buffer_id, cx);
18350                        }
18351                    })
18352                    .ok();
18353            });
18354        }
18355    }
18356
18357    pub fn fold_selected_ranges(
18358        &mut self,
18359        _: &FoldSelectedRanges,
18360        window: &mut Window,
18361        cx: &mut Context<Self>,
18362    ) {
18363        let selections = self.selections.all_adjusted(cx);
18364        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18365        let ranges = selections
18366            .into_iter()
18367            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18368            .collect::<Vec<_>>();
18369        self.fold_creases(ranges, true, window, cx);
18370    }
18371
18372    pub fn fold_ranges<T: ToOffset + Clone>(
18373        &mut self,
18374        ranges: Vec<Range<T>>,
18375        auto_scroll: bool,
18376        window: &mut Window,
18377        cx: &mut Context<Self>,
18378    ) {
18379        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18380        let ranges = ranges
18381            .into_iter()
18382            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18383            .collect::<Vec<_>>();
18384        self.fold_creases(ranges, auto_scroll, window, cx);
18385    }
18386
18387    pub fn fold_creases<T: ToOffset + Clone>(
18388        &mut self,
18389        creases: Vec<Crease<T>>,
18390        auto_scroll: bool,
18391        _window: &mut Window,
18392        cx: &mut Context<Self>,
18393    ) {
18394        if creases.is_empty() {
18395            return;
18396        }
18397
18398        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18399
18400        if auto_scroll {
18401            self.request_autoscroll(Autoscroll::fit(), cx);
18402        }
18403
18404        cx.notify();
18405
18406        self.scrollbar_marker_state.dirty = true;
18407        self.folds_did_change(cx);
18408    }
18409
18410    /// Removes any folds whose ranges intersect any of the given ranges.
18411    pub fn unfold_ranges<T: ToOffset + Clone>(
18412        &mut self,
18413        ranges: &[Range<T>],
18414        inclusive: bool,
18415        auto_scroll: bool,
18416        cx: &mut Context<Self>,
18417    ) {
18418        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18419            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18420        });
18421        self.folds_did_change(cx);
18422    }
18423
18424    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18425        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18426            return;
18427        }
18428        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18429        self.display_map.update(cx, |display_map, cx| {
18430            display_map.fold_buffers([buffer_id], cx)
18431        });
18432        cx.emit(EditorEvent::BufferFoldToggled {
18433            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18434            folded: true,
18435        });
18436        cx.notify();
18437    }
18438
18439    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18440        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18441            return;
18442        }
18443        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18444        self.display_map.update(cx, |display_map, cx| {
18445            display_map.unfold_buffers([buffer_id], cx);
18446        });
18447        cx.emit(EditorEvent::BufferFoldToggled {
18448            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18449            folded: false,
18450        });
18451        cx.notify();
18452    }
18453
18454    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18455        self.display_map.read(cx).is_buffer_folded(buffer)
18456    }
18457
18458    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18459        self.display_map.read(cx).folded_buffers()
18460    }
18461
18462    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18463        self.display_map.update(cx, |display_map, cx| {
18464            display_map.disable_header_for_buffer(buffer_id, cx);
18465        });
18466        cx.notify();
18467    }
18468
18469    /// Removes any folds with the given ranges.
18470    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18471        &mut self,
18472        ranges: &[Range<T>],
18473        type_id: TypeId,
18474        auto_scroll: bool,
18475        cx: &mut Context<Self>,
18476    ) {
18477        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18478            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18479        });
18480        self.folds_did_change(cx);
18481    }
18482
18483    fn remove_folds_with<T: ToOffset + Clone>(
18484        &mut self,
18485        ranges: &[Range<T>],
18486        auto_scroll: bool,
18487        cx: &mut Context<Self>,
18488        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18489    ) {
18490        if ranges.is_empty() {
18491            return;
18492        }
18493
18494        let mut buffers_affected = HashSet::default();
18495        let multi_buffer = self.buffer().read(cx);
18496        for range in ranges {
18497            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18498                buffers_affected.insert(buffer.read(cx).remote_id());
18499            };
18500        }
18501
18502        self.display_map.update(cx, update);
18503
18504        if auto_scroll {
18505            self.request_autoscroll(Autoscroll::fit(), cx);
18506        }
18507
18508        cx.notify();
18509        self.scrollbar_marker_state.dirty = true;
18510        self.active_indent_guides_state.dirty = true;
18511    }
18512
18513    pub fn update_renderer_widths(
18514        &mut self,
18515        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18516        cx: &mut Context<Self>,
18517    ) -> bool {
18518        self.display_map
18519            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18520    }
18521
18522    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18523        self.display_map.read(cx).fold_placeholder.clone()
18524    }
18525
18526    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18527        self.buffer.update(cx, |buffer, cx| {
18528            buffer.set_all_diff_hunks_expanded(cx);
18529        });
18530    }
18531
18532    pub fn expand_all_diff_hunks(
18533        &mut self,
18534        _: &ExpandAllDiffHunks,
18535        _window: &mut Window,
18536        cx: &mut Context<Self>,
18537    ) {
18538        self.buffer.update(cx, |buffer, cx| {
18539            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18540        });
18541    }
18542
18543    pub fn toggle_selected_diff_hunks(
18544        &mut self,
18545        _: &ToggleSelectedDiffHunks,
18546        _window: &mut Window,
18547        cx: &mut Context<Self>,
18548    ) {
18549        let ranges: Vec<_> = self
18550            .selections
18551            .disjoint_anchors()
18552            .iter()
18553            .map(|s| s.range())
18554            .collect();
18555        self.toggle_diff_hunks_in_ranges(ranges, cx);
18556    }
18557
18558    pub fn diff_hunks_in_ranges<'a>(
18559        &'a self,
18560        ranges: &'a [Range<Anchor>],
18561        buffer: &'a MultiBufferSnapshot,
18562    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18563        ranges.iter().flat_map(move |range| {
18564            let end_excerpt_id = range.end.excerpt_id;
18565            let range = range.to_point(buffer);
18566            let mut peek_end = range.end;
18567            if range.end.row < buffer.max_row().0 {
18568                peek_end = Point::new(range.end.row + 1, 0);
18569            }
18570            buffer
18571                .diff_hunks_in_range(range.start..peek_end)
18572                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18573        })
18574    }
18575
18576    pub fn has_stageable_diff_hunks_in_ranges(
18577        &self,
18578        ranges: &[Range<Anchor>],
18579        snapshot: &MultiBufferSnapshot,
18580    ) -> bool {
18581        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18582        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18583    }
18584
18585    pub fn toggle_staged_selected_diff_hunks(
18586        &mut self,
18587        _: &::git::ToggleStaged,
18588        _: &mut Window,
18589        cx: &mut Context<Self>,
18590    ) {
18591        let snapshot = self.buffer.read(cx).snapshot(cx);
18592        let ranges: Vec<_> = self
18593            .selections
18594            .disjoint_anchors()
18595            .iter()
18596            .map(|s| s.range())
18597            .collect();
18598        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18599        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18600    }
18601
18602    pub fn set_render_diff_hunk_controls(
18603        &mut self,
18604        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18605        cx: &mut Context<Self>,
18606    ) {
18607        self.render_diff_hunk_controls = render_diff_hunk_controls;
18608        cx.notify();
18609    }
18610
18611    pub fn stage_and_next(
18612        &mut self,
18613        _: &::git::StageAndNext,
18614        window: &mut Window,
18615        cx: &mut Context<Self>,
18616    ) {
18617        self.do_stage_or_unstage_and_next(true, window, cx);
18618    }
18619
18620    pub fn unstage_and_next(
18621        &mut self,
18622        _: &::git::UnstageAndNext,
18623        window: &mut Window,
18624        cx: &mut Context<Self>,
18625    ) {
18626        self.do_stage_or_unstage_and_next(false, window, cx);
18627    }
18628
18629    pub fn stage_or_unstage_diff_hunks(
18630        &mut self,
18631        stage: bool,
18632        ranges: Vec<Range<Anchor>>,
18633        cx: &mut Context<Self>,
18634    ) {
18635        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18636        cx.spawn(async move |this, cx| {
18637            task.await?;
18638            this.update(cx, |this, cx| {
18639                let snapshot = this.buffer.read(cx).snapshot(cx);
18640                let chunk_by = this
18641                    .diff_hunks_in_ranges(&ranges, &snapshot)
18642                    .chunk_by(|hunk| hunk.buffer_id);
18643                for (buffer_id, hunks) in &chunk_by {
18644                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18645                }
18646            })
18647        })
18648        .detach_and_log_err(cx);
18649    }
18650
18651    fn save_buffers_for_ranges_if_needed(
18652        &mut self,
18653        ranges: &[Range<Anchor>],
18654        cx: &mut Context<Editor>,
18655    ) -> Task<Result<()>> {
18656        let multibuffer = self.buffer.read(cx);
18657        let snapshot = multibuffer.read(cx);
18658        let buffer_ids: HashSet<_> = ranges
18659            .iter()
18660            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18661            .collect();
18662        drop(snapshot);
18663
18664        let mut buffers = HashSet::default();
18665        for buffer_id in buffer_ids {
18666            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18667                let buffer = buffer_entity.read(cx);
18668                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18669                {
18670                    buffers.insert(buffer_entity);
18671                }
18672            }
18673        }
18674
18675        if let Some(project) = &self.project {
18676            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18677        } else {
18678            Task::ready(Ok(()))
18679        }
18680    }
18681
18682    fn do_stage_or_unstage_and_next(
18683        &mut self,
18684        stage: bool,
18685        window: &mut Window,
18686        cx: &mut Context<Self>,
18687    ) {
18688        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18689
18690        if ranges.iter().any(|range| range.start != range.end) {
18691            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18692            return;
18693        }
18694
18695        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18696        let snapshot = self.snapshot(window, cx);
18697        let position = self.selections.newest::<Point>(cx).head();
18698        let mut row = snapshot
18699            .buffer_snapshot
18700            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18701            .find(|hunk| hunk.row_range.start.0 > position.row)
18702            .map(|hunk| hunk.row_range.start);
18703
18704        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18705        // Outside of the project diff editor, wrap around to the beginning.
18706        if !all_diff_hunks_expanded {
18707            row = row.or_else(|| {
18708                snapshot
18709                    .buffer_snapshot
18710                    .diff_hunks_in_range(Point::zero()..position)
18711                    .find(|hunk| hunk.row_range.end.0 < position.row)
18712                    .map(|hunk| hunk.row_range.start)
18713            });
18714        }
18715
18716        if let Some(row) = row {
18717            let destination = Point::new(row.0, 0);
18718            let autoscroll = Autoscroll::center();
18719
18720            self.unfold_ranges(&[destination..destination], false, false, cx);
18721            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18722                s.select_ranges([destination..destination]);
18723            });
18724        }
18725    }
18726
18727    fn do_stage_or_unstage(
18728        &self,
18729        stage: bool,
18730        buffer_id: BufferId,
18731        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18732        cx: &mut App,
18733    ) -> Option<()> {
18734        let project = self.project()?;
18735        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18736        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18737        let buffer_snapshot = buffer.read(cx).snapshot();
18738        let file_exists = buffer_snapshot
18739            .file()
18740            .is_some_and(|file| file.disk_state().exists());
18741        diff.update(cx, |diff, cx| {
18742            diff.stage_or_unstage_hunks(
18743                stage,
18744                &hunks
18745                    .map(|hunk| buffer_diff::DiffHunk {
18746                        buffer_range: hunk.buffer_range,
18747                        diff_base_byte_range: hunk.diff_base_byte_range,
18748                        secondary_status: hunk.secondary_status,
18749                        range: Point::zero()..Point::zero(), // unused
18750                    })
18751                    .collect::<Vec<_>>(),
18752                &buffer_snapshot,
18753                file_exists,
18754                cx,
18755            )
18756        });
18757        None
18758    }
18759
18760    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18761        let ranges: Vec<_> = self
18762            .selections
18763            .disjoint_anchors()
18764            .iter()
18765            .map(|s| s.range())
18766            .collect();
18767        self.buffer
18768            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18769    }
18770
18771    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18772        self.buffer.update(cx, |buffer, cx| {
18773            let ranges = vec![Anchor::min()..Anchor::max()];
18774            if !buffer.all_diff_hunks_expanded()
18775                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18776            {
18777                buffer.collapse_diff_hunks(ranges, cx);
18778                true
18779            } else {
18780                false
18781            }
18782        })
18783    }
18784
18785    fn toggle_diff_hunks_in_ranges(
18786        &mut self,
18787        ranges: Vec<Range<Anchor>>,
18788        cx: &mut Context<Editor>,
18789    ) {
18790        self.buffer.update(cx, |buffer, cx| {
18791            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18792            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18793        })
18794    }
18795
18796    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18797        self.buffer.update(cx, |buffer, cx| {
18798            let snapshot = buffer.snapshot(cx);
18799            let excerpt_id = range.end.excerpt_id;
18800            let point_range = range.to_point(&snapshot);
18801            let expand = !buffer.single_hunk_is_expanded(range, cx);
18802            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18803        })
18804    }
18805
18806    pub(crate) fn apply_all_diff_hunks(
18807        &mut self,
18808        _: &ApplyAllDiffHunks,
18809        window: &mut Window,
18810        cx: &mut Context<Self>,
18811    ) {
18812        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18813
18814        let buffers = self.buffer.read(cx).all_buffers();
18815        for branch_buffer in buffers {
18816            branch_buffer.update(cx, |branch_buffer, cx| {
18817                branch_buffer.merge_into_base(Vec::new(), cx);
18818            });
18819        }
18820
18821        if let Some(project) = self.project.clone() {
18822            self.save(
18823                SaveOptions {
18824                    format: true,
18825                    autosave: false,
18826                },
18827                project,
18828                window,
18829                cx,
18830            )
18831            .detach_and_log_err(cx);
18832        }
18833    }
18834
18835    pub(crate) fn apply_selected_diff_hunks(
18836        &mut self,
18837        _: &ApplyDiffHunk,
18838        window: &mut Window,
18839        cx: &mut Context<Self>,
18840    ) {
18841        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18842        let snapshot = self.snapshot(window, cx);
18843        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18844        let mut ranges_by_buffer = HashMap::default();
18845        self.transact(window, cx, |editor, _window, cx| {
18846            for hunk in hunks {
18847                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18848                    ranges_by_buffer
18849                        .entry(buffer.clone())
18850                        .or_insert_with(Vec::new)
18851                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18852                }
18853            }
18854
18855            for (buffer, ranges) in ranges_by_buffer {
18856                buffer.update(cx, |buffer, cx| {
18857                    buffer.merge_into_base(ranges, cx);
18858                });
18859            }
18860        });
18861
18862        if let Some(project) = self.project.clone() {
18863            self.save(
18864                SaveOptions {
18865                    format: true,
18866                    autosave: false,
18867                },
18868                project,
18869                window,
18870                cx,
18871            )
18872            .detach_and_log_err(cx);
18873        }
18874    }
18875
18876    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18877        if hovered != self.gutter_hovered {
18878            self.gutter_hovered = hovered;
18879            cx.notify();
18880        }
18881    }
18882
18883    pub fn insert_blocks(
18884        &mut self,
18885        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18886        autoscroll: Option<Autoscroll>,
18887        cx: &mut Context<Self>,
18888    ) -> Vec<CustomBlockId> {
18889        let blocks = self
18890            .display_map
18891            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18892        if let Some(autoscroll) = autoscroll {
18893            self.request_autoscroll(autoscroll, cx);
18894        }
18895        cx.notify();
18896        blocks
18897    }
18898
18899    pub fn resize_blocks(
18900        &mut self,
18901        heights: HashMap<CustomBlockId, u32>,
18902        autoscroll: Option<Autoscroll>,
18903        cx: &mut Context<Self>,
18904    ) {
18905        self.display_map
18906            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18907        if let Some(autoscroll) = autoscroll {
18908            self.request_autoscroll(autoscroll, cx);
18909        }
18910        cx.notify();
18911    }
18912
18913    pub fn replace_blocks(
18914        &mut self,
18915        renderers: HashMap<CustomBlockId, RenderBlock>,
18916        autoscroll: Option<Autoscroll>,
18917        cx: &mut Context<Self>,
18918    ) {
18919        self.display_map
18920            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18921        if let Some(autoscroll) = autoscroll {
18922            self.request_autoscroll(autoscroll, cx);
18923        }
18924        cx.notify();
18925    }
18926
18927    pub fn remove_blocks(
18928        &mut self,
18929        block_ids: HashSet<CustomBlockId>,
18930        autoscroll: Option<Autoscroll>,
18931        cx: &mut Context<Self>,
18932    ) {
18933        self.display_map.update(cx, |display_map, cx| {
18934            display_map.remove_blocks(block_ids, cx)
18935        });
18936        if let Some(autoscroll) = autoscroll {
18937            self.request_autoscroll(autoscroll, cx);
18938        }
18939        cx.notify();
18940    }
18941
18942    pub fn row_for_block(
18943        &self,
18944        block_id: CustomBlockId,
18945        cx: &mut Context<Self>,
18946    ) -> Option<DisplayRow> {
18947        self.display_map
18948            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18949    }
18950
18951    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18952        self.focused_block = Some(focused_block);
18953    }
18954
18955    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18956        self.focused_block.take()
18957    }
18958
18959    pub fn insert_creases(
18960        &mut self,
18961        creases: impl IntoIterator<Item = Crease<Anchor>>,
18962        cx: &mut Context<Self>,
18963    ) -> Vec<CreaseId> {
18964        self.display_map
18965            .update(cx, |map, cx| map.insert_creases(creases, cx))
18966    }
18967
18968    pub fn remove_creases(
18969        &mut self,
18970        ids: impl IntoIterator<Item = CreaseId>,
18971        cx: &mut Context<Self>,
18972    ) -> Vec<(CreaseId, Range<Anchor>)> {
18973        self.display_map
18974            .update(cx, |map, cx| map.remove_creases(ids, cx))
18975    }
18976
18977    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18978        self.display_map
18979            .update(cx, |map, cx| map.snapshot(cx))
18980            .longest_row()
18981    }
18982
18983    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18984        self.display_map
18985            .update(cx, |map, cx| map.snapshot(cx))
18986            .max_point()
18987    }
18988
18989    pub fn text(&self, cx: &App) -> String {
18990        self.buffer.read(cx).read(cx).text()
18991    }
18992
18993    pub fn is_empty(&self, cx: &App) -> bool {
18994        self.buffer.read(cx).read(cx).is_empty()
18995    }
18996
18997    pub fn text_option(&self, cx: &App) -> Option<String> {
18998        let text = self.text(cx);
18999        let text = text.trim();
19000
19001        if text.is_empty() {
19002            return None;
19003        }
19004
19005        Some(text.to_string())
19006    }
19007
19008    pub fn set_text(
19009        &mut self,
19010        text: impl Into<Arc<str>>,
19011        window: &mut Window,
19012        cx: &mut Context<Self>,
19013    ) {
19014        self.transact(window, cx, |this, _, cx| {
19015            this.buffer
19016                .read(cx)
19017                .as_singleton()
19018                .expect("you can only call set_text on editors for singleton buffers")
19019                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19020        });
19021    }
19022
19023    pub fn display_text(&self, cx: &mut App) -> String {
19024        self.display_map
19025            .update(cx, |map, cx| map.snapshot(cx))
19026            .text()
19027    }
19028
19029    fn create_minimap(
19030        &self,
19031        minimap_settings: MinimapSettings,
19032        window: &mut Window,
19033        cx: &mut Context<Self>,
19034    ) -> Option<Entity<Self>> {
19035        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
19036            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19037    }
19038
19039    fn initialize_new_minimap(
19040        &self,
19041        minimap_settings: MinimapSettings,
19042        window: &mut Window,
19043        cx: &mut Context<Self>,
19044    ) -> Entity<Self> {
19045        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19046
19047        let mut minimap = Editor::new_internal(
19048            EditorMode::Minimap {
19049                parent: cx.weak_entity(),
19050            },
19051            self.buffer.clone(),
19052            None,
19053            Some(self.display_map.clone()),
19054            window,
19055            cx,
19056        );
19057        minimap.scroll_manager.clone_state(&self.scroll_manager);
19058        minimap.set_text_style_refinement(TextStyleRefinement {
19059            font_size: Some(MINIMAP_FONT_SIZE),
19060            font_weight: Some(MINIMAP_FONT_WEIGHT),
19061            ..Default::default()
19062        });
19063        minimap.update_minimap_configuration(minimap_settings, cx);
19064        cx.new(|_| minimap)
19065    }
19066
19067    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19068        let current_line_highlight = minimap_settings
19069            .current_line_highlight
19070            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19071        self.set_current_line_highlight(Some(current_line_highlight));
19072    }
19073
19074    pub fn minimap(&self) -> Option<&Entity<Self>> {
19075        self.minimap
19076            .as_ref()
19077            .filter(|_| self.minimap_visibility.visible())
19078    }
19079
19080    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19081        let mut wrap_guides = smallvec![];
19082
19083        if self.show_wrap_guides == Some(false) {
19084            return wrap_guides;
19085        }
19086
19087        let settings = self.buffer.read(cx).language_settings(cx);
19088        if settings.show_wrap_guides {
19089            match self.soft_wrap_mode(cx) {
19090                SoftWrap::Column(soft_wrap) => {
19091                    wrap_guides.push((soft_wrap as usize, true));
19092                }
19093                SoftWrap::Bounded(soft_wrap) => {
19094                    wrap_guides.push((soft_wrap as usize, true));
19095                }
19096                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19097            }
19098            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19099        }
19100
19101        wrap_guides
19102    }
19103
19104    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19105        let settings = self.buffer.read(cx).language_settings(cx);
19106        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19107        match mode {
19108            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19109                SoftWrap::None
19110            }
19111            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19112            language_settings::SoftWrap::PreferredLineLength => {
19113                SoftWrap::Column(settings.preferred_line_length)
19114            }
19115            language_settings::SoftWrap::Bounded => {
19116                SoftWrap::Bounded(settings.preferred_line_length)
19117            }
19118        }
19119    }
19120
19121    pub fn set_soft_wrap_mode(
19122        &mut self,
19123        mode: language_settings::SoftWrap,
19124
19125        cx: &mut Context<Self>,
19126    ) {
19127        self.soft_wrap_mode_override = Some(mode);
19128        cx.notify();
19129    }
19130
19131    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19132        self.hard_wrap = hard_wrap;
19133        cx.notify();
19134    }
19135
19136    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19137        self.text_style_refinement = Some(style);
19138    }
19139
19140    /// called by the Element so we know what style we were most recently rendered with.
19141    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19142        // We intentionally do not inform the display map about the minimap style
19143        // so that wrapping is not recalculated and stays consistent for the editor
19144        // and its linked minimap.
19145        if !self.mode.is_minimap() {
19146            let font = style.text.font();
19147            let font_size = style.text.font_size.to_pixels(window.rem_size());
19148            let display_map = self
19149                .placeholder_display_map
19150                .as_ref()
19151                .filter(|_| self.is_empty(cx))
19152                .unwrap_or(&self.display_map);
19153
19154            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19155        }
19156        self.style = Some(style);
19157    }
19158
19159    pub fn style(&self) -> Option<&EditorStyle> {
19160        self.style.as_ref()
19161    }
19162
19163    // Called by the element. This method is not designed to be called outside of the editor
19164    // element's layout code because it does not notify when rewrapping is computed synchronously.
19165    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19166        if self.is_empty(cx) {
19167            self.placeholder_display_map
19168                .as_ref()
19169                .map_or(false, |display_map| {
19170                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19171                })
19172        } else {
19173            self.display_map
19174                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19175        }
19176    }
19177
19178    pub fn set_soft_wrap(&mut self) {
19179        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19180    }
19181
19182    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19183        if self.soft_wrap_mode_override.is_some() {
19184            self.soft_wrap_mode_override.take();
19185        } else {
19186            let soft_wrap = match self.soft_wrap_mode(cx) {
19187                SoftWrap::GitDiff => return,
19188                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19189                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19190                    language_settings::SoftWrap::None
19191                }
19192            };
19193            self.soft_wrap_mode_override = Some(soft_wrap);
19194        }
19195        cx.notify();
19196    }
19197
19198    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19199        let Some(workspace) = self.workspace() else {
19200            return;
19201        };
19202        let fs = workspace.read(cx).app_state().fs.clone();
19203        let current_show = TabBarSettings::get_global(cx).show;
19204        update_settings_file(fs, cx, move |setting, _| {
19205            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19206        });
19207    }
19208
19209    pub fn toggle_indent_guides(
19210        &mut self,
19211        _: &ToggleIndentGuides,
19212        _: &mut Window,
19213        cx: &mut Context<Self>,
19214    ) {
19215        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19216            self.buffer
19217                .read(cx)
19218                .language_settings(cx)
19219                .indent_guides
19220                .enabled
19221        });
19222        self.show_indent_guides = Some(!currently_enabled);
19223        cx.notify();
19224    }
19225
19226    fn should_show_indent_guides(&self) -> Option<bool> {
19227        self.show_indent_guides
19228    }
19229
19230    pub fn toggle_line_numbers(
19231        &mut self,
19232        _: &ToggleLineNumbers,
19233        _: &mut Window,
19234        cx: &mut Context<Self>,
19235    ) {
19236        let mut editor_settings = EditorSettings::get_global(cx).clone();
19237        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19238        EditorSettings::override_global(editor_settings, cx);
19239    }
19240
19241    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19242        if let Some(show_line_numbers) = self.show_line_numbers {
19243            return show_line_numbers;
19244        }
19245        EditorSettings::get_global(cx).gutter.line_numbers
19246    }
19247
19248    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19249        self.use_relative_line_numbers
19250            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19251    }
19252
19253    pub fn toggle_relative_line_numbers(
19254        &mut self,
19255        _: &ToggleRelativeLineNumbers,
19256        _: &mut Window,
19257        cx: &mut Context<Self>,
19258    ) {
19259        let is_relative = self.should_use_relative_line_numbers(cx);
19260        self.set_relative_line_number(Some(!is_relative), cx)
19261    }
19262
19263    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19264        self.use_relative_line_numbers = is_relative;
19265        cx.notify();
19266    }
19267
19268    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19269        self.show_gutter = show_gutter;
19270        cx.notify();
19271    }
19272
19273    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19274        self.show_scrollbars = ScrollbarAxes {
19275            horizontal: show,
19276            vertical: show,
19277        };
19278        cx.notify();
19279    }
19280
19281    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19282        self.show_scrollbars.vertical = show;
19283        cx.notify();
19284    }
19285
19286    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19287        self.show_scrollbars.horizontal = show;
19288        cx.notify();
19289    }
19290
19291    pub fn set_minimap_visibility(
19292        &mut self,
19293        minimap_visibility: MinimapVisibility,
19294        window: &mut Window,
19295        cx: &mut Context<Self>,
19296    ) {
19297        if self.minimap_visibility != minimap_visibility {
19298            if minimap_visibility.visible() && self.minimap.is_none() {
19299                let minimap_settings = EditorSettings::get_global(cx).minimap;
19300                self.minimap =
19301                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19302            }
19303            self.minimap_visibility = minimap_visibility;
19304            cx.notify();
19305        }
19306    }
19307
19308    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19309        self.set_show_scrollbars(false, cx);
19310        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19311    }
19312
19313    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19314        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19315    }
19316
19317    /// Normally the text in full mode and auto height editors is padded on the
19318    /// left side by roughly half a character width for improved hit testing.
19319    ///
19320    /// Use this method to disable this for cases where this is not wanted (e.g.
19321    /// if you want to align the editor text with some other text above or below)
19322    /// or if you want to add this padding to single-line editors.
19323    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19324        self.offset_content = offset_content;
19325        cx.notify();
19326    }
19327
19328    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19329        self.show_line_numbers = Some(show_line_numbers);
19330        cx.notify();
19331    }
19332
19333    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19334        self.disable_expand_excerpt_buttons = true;
19335        cx.notify();
19336    }
19337
19338    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19339        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19340        cx.notify();
19341    }
19342
19343    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19344        self.show_code_actions = Some(show_code_actions);
19345        cx.notify();
19346    }
19347
19348    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19349        self.show_runnables = Some(show_runnables);
19350        cx.notify();
19351    }
19352
19353    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19354        self.show_breakpoints = Some(show_breakpoints);
19355        cx.notify();
19356    }
19357
19358    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19359        if self.display_map.read(cx).masked != masked {
19360            self.display_map.update(cx, |map, _| map.masked = masked);
19361        }
19362        cx.notify()
19363    }
19364
19365    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19366        self.show_wrap_guides = Some(show_wrap_guides);
19367        cx.notify();
19368    }
19369
19370    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19371        self.show_indent_guides = Some(show_indent_guides);
19372        cx.notify();
19373    }
19374
19375    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19376        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19377            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19378                && let Some(dir) = file.abs_path(cx).parent()
19379            {
19380                return Some(dir.to_owned());
19381            }
19382        }
19383
19384        None
19385    }
19386
19387    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19388        self.active_excerpt(cx)?
19389            .1
19390            .read(cx)
19391            .file()
19392            .and_then(|f| f.as_local())
19393    }
19394
19395    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19396        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19397            let buffer = buffer.read(cx);
19398            if let Some(project_path) = buffer.project_path(cx) {
19399                let project = self.project()?.read(cx);
19400                project.absolute_path(&project_path, cx)
19401            } else {
19402                buffer
19403                    .file()
19404                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19405            }
19406        })
19407    }
19408
19409    pub fn reveal_in_finder(
19410        &mut self,
19411        _: &RevealInFileManager,
19412        _window: &mut Window,
19413        cx: &mut Context<Self>,
19414    ) {
19415        if let Some(target) = self.target_file(cx) {
19416            cx.reveal_path(&target.abs_path(cx));
19417        }
19418    }
19419
19420    pub fn copy_path(
19421        &mut self,
19422        _: &zed_actions::workspace::CopyPath,
19423        _window: &mut Window,
19424        cx: &mut Context<Self>,
19425    ) {
19426        if let Some(path) = self.target_file_abs_path(cx)
19427            && let Some(path) = path.to_str()
19428        {
19429            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19430        } else {
19431            cx.propagate();
19432        }
19433    }
19434
19435    pub fn copy_relative_path(
19436        &mut self,
19437        _: &zed_actions::workspace::CopyRelativePath,
19438        _window: &mut Window,
19439        cx: &mut Context<Self>,
19440    ) {
19441        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19442            let project = self.project()?.read(cx);
19443            let path = buffer.read(cx).file()?.path();
19444            let path = path.display(project.path_style(cx));
19445            Some(path)
19446        }) {
19447            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19448        } else {
19449            cx.propagate();
19450        }
19451    }
19452
19453    /// Returns the project path for the editor's buffer, if any buffer is
19454    /// opened in the editor.
19455    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19456        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19457            buffer.read(cx).project_path(cx)
19458        } else {
19459            None
19460        }
19461    }
19462
19463    // Returns true if the editor handled a go-to-line request
19464    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19465        maybe!({
19466            let breakpoint_store = self.breakpoint_store.as_ref()?;
19467
19468            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19469            else {
19470                self.clear_row_highlights::<ActiveDebugLine>();
19471                return None;
19472            };
19473
19474            let position = active_stack_frame.position;
19475            let buffer_id = position.buffer_id?;
19476            let snapshot = self
19477                .project
19478                .as_ref()?
19479                .read(cx)
19480                .buffer_for_id(buffer_id, cx)?
19481                .read(cx)
19482                .snapshot();
19483
19484            let mut handled = false;
19485            for (id, ExcerptRange { context, .. }) in
19486                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19487            {
19488                if context.start.cmp(&position, &snapshot).is_ge()
19489                    || context.end.cmp(&position, &snapshot).is_lt()
19490                {
19491                    continue;
19492                }
19493                let snapshot = self.buffer.read(cx).snapshot(cx);
19494                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19495
19496                handled = true;
19497                self.clear_row_highlights::<ActiveDebugLine>();
19498
19499                self.go_to_line::<ActiveDebugLine>(
19500                    multibuffer_anchor,
19501                    Some(cx.theme().colors().editor_debugger_active_line_background),
19502                    window,
19503                    cx,
19504                );
19505
19506                cx.notify();
19507            }
19508
19509            handled.then_some(())
19510        })
19511        .is_some()
19512    }
19513
19514    pub fn copy_file_name_without_extension(
19515        &mut self,
19516        _: &CopyFileNameWithoutExtension,
19517        _: &mut Window,
19518        cx: &mut Context<Self>,
19519    ) {
19520        if let Some(file) = self.target_file(cx)
19521            && let Some(file_stem) = file.path().file_stem()
19522        {
19523            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19524        }
19525    }
19526
19527    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19528        if let Some(file) = self.target_file(cx)
19529            && let Some(name) = file.path().file_name()
19530        {
19531            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19532        }
19533    }
19534
19535    pub fn toggle_git_blame(
19536        &mut self,
19537        _: &::git::Blame,
19538        window: &mut Window,
19539        cx: &mut Context<Self>,
19540    ) {
19541        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19542
19543        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19544            self.start_git_blame(true, window, cx);
19545        }
19546
19547        cx.notify();
19548    }
19549
19550    pub fn toggle_git_blame_inline(
19551        &mut self,
19552        _: &ToggleGitBlameInline,
19553        window: &mut Window,
19554        cx: &mut Context<Self>,
19555    ) {
19556        self.toggle_git_blame_inline_internal(true, window, cx);
19557        cx.notify();
19558    }
19559
19560    pub fn open_git_blame_commit(
19561        &mut self,
19562        _: &OpenGitBlameCommit,
19563        window: &mut Window,
19564        cx: &mut Context<Self>,
19565    ) {
19566        self.open_git_blame_commit_internal(window, cx);
19567    }
19568
19569    fn open_git_blame_commit_internal(
19570        &mut self,
19571        window: &mut Window,
19572        cx: &mut Context<Self>,
19573    ) -> Option<()> {
19574        let blame = self.blame.as_ref()?;
19575        let snapshot = self.snapshot(window, cx);
19576        let cursor = self.selections.newest::<Point>(cx).head();
19577        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19578        let (_, blame_entry) = blame
19579            .update(cx, |blame, cx| {
19580                blame
19581                    .blame_for_rows(
19582                        &[RowInfo {
19583                            buffer_id: Some(buffer.remote_id()),
19584                            buffer_row: Some(point.row),
19585                            ..Default::default()
19586                        }],
19587                        cx,
19588                    )
19589                    .next()
19590            })
19591            .flatten()?;
19592        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19593        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19594        let workspace = self.workspace()?.downgrade();
19595        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19596        None
19597    }
19598
19599    pub fn git_blame_inline_enabled(&self) -> bool {
19600        self.git_blame_inline_enabled
19601    }
19602
19603    pub fn toggle_selection_menu(
19604        &mut self,
19605        _: &ToggleSelectionMenu,
19606        _: &mut Window,
19607        cx: &mut Context<Self>,
19608    ) {
19609        self.show_selection_menu = self
19610            .show_selection_menu
19611            .map(|show_selections_menu| !show_selections_menu)
19612            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19613
19614        cx.notify();
19615    }
19616
19617    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19618        self.show_selection_menu
19619            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19620    }
19621
19622    fn start_git_blame(
19623        &mut self,
19624        user_triggered: bool,
19625        window: &mut Window,
19626        cx: &mut Context<Self>,
19627    ) {
19628        if let Some(project) = self.project() {
19629            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19630                && buffer.read(cx).file().is_none()
19631            {
19632                return;
19633            }
19634
19635            let focused = self.focus_handle(cx).contains_focused(window, cx);
19636
19637            let project = project.clone();
19638            let blame = cx
19639                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19640            self.blame_subscription =
19641                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19642            self.blame = Some(blame);
19643        }
19644    }
19645
19646    fn toggle_git_blame_inline_internal(
19647        &mut self,
19648        user_triggered: bool,
19649        window: &mut Window,
19650        cx: &mut Context<Self>,
19651    ) {
19652        if self.git_blame_inline_enabled {
19653            self.git_blame_inline_enabled = false;
19654            self.show_git_blame_inline = false;
19655            self.show_git_blame_inline_delay_task.take();
19656        } else {
19657            self.git_blame_inline_enabled = true;
19658            self.start_git_blame_inline(user_triggered, window, cx);
19659        }
19660
19661        cx.notify();
19662    }
19663
19664    fn start_git_blame_inline(
19665        &mut self,
19666        user_triggered: bool,
19667        window: &mut Window,
19668        cx: &mut Context<Self>,
19669    ) {
19670        self.start_git_blame(user_triggered, window, cx);
19671
19672        if ProjectSettings::get_global(cx)
19673            .git
19674            .inline_blame_delay()
19675            .is_some()
19676        {
19677            self.start_inline_blame_timer(window, cx);
19678        } else {
19679            self.show_git_blame_inline = true
19680        }
19681    }
19682
19683    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19684        self.blame.as_ref()
19685    }
19686
19687    pub fn show_git_blame_gutter(&self) -> bool {
19688        self.show_git_blame_gutter
19689    }
19690
19691    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19692        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19693    }
19694
19695    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19696        self.show_git_blame_inline
19697            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19698            && !self.newest_selection_head_on_empty_line(cx)
19699            && self.has_blame_entries(cx)
19700    }
19701
19702    fn has_blame_entries(&self, cx: &App) -> bool {
19703        self.blame()
19704            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19705    }
19706
19707    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19708        let cursor_anchor = self.selections.newest_anchor().head();
19709
19710        let snapshot = self.buffer.read(cx).snapshot(cx);
19711        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19712
19713        snapshot.line_len(buffer_row) == 0
19714    }
19715
19716    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19717        let buffer_and_selection = maybe!({
19718            let selection = self.selections.newest::<Point>(cx);
19719            let selection_range = selection.range();
19720
19721            let multi_buffer = self.buffer().read(cx);
19722            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19723            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19724
19725            let (buffer, range, _) = if selection.reversed {
19726                buffer_ranges.first()
19727            } else {
19728                buffer_ranges.last()
19729            }?;
19730
19731            let selection = text::ToPoint::to_point(&range.start, buffer).row
19732                ..text::ToPoint::to_point(&range.end, buffer).row;
19733            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19734        });
19735
19736        let Some((buffer, selection)) = buffer_and_selection else {
19737            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19738        };
19739
19740        let Some(project) = self.project() else {
19741            return Task::ready(Err(anyhow!("editor does not have project")));
19742        };
19743
19744        project.update(cx, |project, cx| {
19745            project.get_permalink_to_line(&buffer, selection, cx)
19746        })
19747    }
19748
19749    pub fn copy_permalink_to_line(
19750        &mut self,
19751        _: &CopyPermalinkToLine,
19752        window: &mut Window,
19753        cx: &mut Context<Self>,
19754    ) {
19755        let permalink_task = self.get_permalink_to_line(cx);
19756        let workspace = self.workspace();
19757
19758        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19759            Ok(permalink) => {
19760                cx.update(|_, cx| {
19761                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19762                })
19763                .ok();
19764            }
19765            Err(err) => {
19766                let message = format!("Failed to copy permalink: {err}");
19767
19768                anyhow::Result::<()>::Err(err).log_err();
19769
19770                if let Some(workspace) = workspace {
19771                    workspace
19772                        .update_in(cx, |workspace, _, cx| {
19773                            struct CopyPermalinkToLine;
19774
19775                            workspace.show_toast(
19776                                Toast::new(
19777                                    NotificationId::unique::<CopyPermalinkToLine>(),
19778                                    message,
19779                                ),
19780                                cx,
19781                            )
19782                        })
19783                        .ok();
19784                }
19785            }
19786        })
19787        .detach();
19788    }
19789
19790    pub fn copy_file_location(
19791        &mut self,
19792        _: &CopyFileLocation,
19793        _: &mut Window,
19794        cx: &mut Context<Self>,
19795    ) {
19796        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19797        if let Some(file) = self.target_file(cx) {
19798            let path = file.path().display(file.path_style(cx));
19799            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19800        }
19801    }
19802
19803    pub fn open_permalink_to_line(
19804        &mut self,
19805        _: &OpenPermalinkToLine,
19806        window: &mut Window,
19807        cx: &mut Context<Self>,
19808    ) {
19809        let permalink_task = self.get_permalink_to_line(cx);
19810        let workspace = self.workspace();
19811
19812        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19813            Ok(permalink) => {
19814                cx.update(|_, cx| {
19815                    cx.open_url(permalink.as_ref());
19816                })
19817                .ok();
19818            }
19819            Err(err) => {
19820                let message = format!("Failed to open permalink: {err}");
19821
19822                anyhow::Result::<()>::Err(err).log_err();
19823
19824                if let Some(workspace) = workspace {
19825                    workspace
19826                        .update(cx, |workspace, cx| {
19827                            struct OpenPermalinkToLine;
19828
19829                            workspace.show_toast(
19830                                Toast::new(
19831                                    NotificationId::unique::<OpenPermalinkToLine>(),
19832                                    message,
19833                                ),
19834                                cx,
19835                            )
19836                        })
19837                        .ok();
19838                }
19839            }
19840        })
19841        .detach();
19842    }
19843
19844    pub fn insert_uuid_v4(
19845        &mut self,
19846        _: &InsertUuidV4,
19847        window: &mut Window,
19848        cx: &mut Context<Self>,
19849    ) {
19850        self.insert_uuid(UuidVersion::V4, window, cx);
19851    }
19852
19853    pub fn insert_uuid_v7(
19854        &mut self,
19855        _: &InsertUuidV7,
19856        window: &mut Window,
19857        cx: &mut Context<Self>,
19858    ) {
19859        self.insert_uuid(UuidVersion::V7, window, cx);
19860    }
19861
19862    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19863        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19864        self.transact(window, cx, |this, window, cx| {
19865            let edits = this
19866                .selections
19867                .all::<Point>(cx)
19868                .into_iter()
19869                .map(|selection| {
19870                    let uuid = match version {
19871                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19872                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19873                    };
19874
19875                    (selection.range(), uuid.to_string())
19876                });
19877            this.edit(edits, cx);
19878            this.refresh_edit_prediction(true, false, window, cx);
19879        });
19880    }
19881
19882    pub fn open_selections_in_multibuffer(
19883        &mut self,
19884        _: &OpenSelectionsInMultibuffer,
19885        window: &mut Window,
19886        cx: &mut Context<Self>,
19887    ) {
19888        let multibuffer = self.buffer.read(cx);
19889
19890        let Some(buffer) = multibuffer.as_singleton() else {
19891            return;
19892        };
19893
19894        let Some(workspace) = self.workspace() else {
19895            return;
19896        };
19897
19898        let title = multibuffer.title(cx).to_string();
19899
19900        let locations = self
19901            .selections
19902            .all_anchors(cx)
19903            .iter()
19904            .map(|selection| {
19905                (
19906                    buffer.clone(),
19907                    (selection.start.text_anchor..selection.end.text_anchor)
19908                        .to_point(buffer.read(cx)),
19909                )
19910            })
19911            .into_group_map();
19912
19913        cx.spawn_in(window, async move |_, cx| {
19914            workspace.update_in(cx, |workspace, window, cx| {
19915                Self::open_locations_in_multibuffer(
19916                    workspace,
19917                    locations,
19918                    format!("Selections for '{title}'"),
19919                    false,
19920                    MultibufferSelectionMode::All,
19921                    window,
19922                    cx,
19923                );
19924            })
19925        })
19926        .detach();
19927    }
19928
19929    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19930    /// last highlight added will be used.
19931    ///
19932    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19933    pub fn highlight_rows<T: 'static>(
19934        &mut self,
19935        range: Range<Anchor>,
19936        color: Hsla,
19937        options: RowHighlightOptions,
19938        cx: &mut Context<Self>,
19939    ) {
19940        let snapshot = self.buffer().read(cx).snapshot(cx);
19941        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19942        let ix = row_highlights.binary_search_by(|highlight| {
19943            Ordering::Equal
19944                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19945                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19946        });
19947
19948        if let Err(mut ix) = ix {
19949            let index = post_inc(&mut self.highlight_order);
19950
19951            // If this range intersects with the preceding highlight, then merge it with
19952            // the preceding highlight. Otherwise insert a new highlight.
19953            let mut merged = false;
19954            if ix > 0 {
19955                let prev_highlight = &mut row_highlights[ix - 1];
19956                if prev_highlight
19957                    .range
19958                    .end
19959                    .cmp(&range.start, &snapshot)
19960                    .is_ge()
19961                {
19962                    ix -= 1;
19963                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19964                        prev_highlight.range.end = range.end;
19965                    }
19966                    merged = true;
19967                    prev_highlight.index = index;
19968                    prev_highlight.color = color;
19969                    prev_highlight.options = options;
19970                }
19971            }
19972
19973            if !merged {
19974                row_highlights.insert(
19975                    ix,
19976                    RowHighlight {
19977                        range,
19978                        index,
19979                        color,
19980                        options,
19981                        type_id: TypeId::of::<T>(),
19982                    },
19983                );
19984            }
19985
19986            // If any of the following highlights intersect with this one, merge them.
19987            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19988                let highlight = &row_highlights[ix];
19989                if next_highlight
19990                    .range
19991                    .start
19992                    .cmp(&highlight.range.end, &snapshot)
19993                    .is_le()
19994                {
19995                    if next_highlight
19996                        .range
19997                        .end
19998                        .cmp(&highlight.range.end, &snapshot)
19999                        .is_gt()
20000                    {
20001                        row_highlights[ix].range.end = next_highlight.range.end;
20002                    }
20003                    row_highlights.remove(ix + 1);
20004                } else {
20005                    break;
20006                }
20007            }
20008        }
20009    }
20010
20011    /// Remove any highlighted row ranges of the given type that intersect the
20012    /// given ranges.
20013    pub fn remove_highlighted_rows<T: 'static>(
20014        &mut self,
20015        ranges_to_remove: Vec<Range<Anchor>>,
20016        cx: &mut Context<Self>,
20017    ) {
20018        let snapshot = self.buffer().read(cx).snapshot(cx);
20019        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20020        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20021        row_highlights.retain(|highlight| {
20022            while let Some(range_to_remove) = ranges_to_remove.peek() {
20023                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20024                    Ordering::Less | Ordering::Equal => {
20025                        ranges_to_remove.next();
20026                    }
20027                    Ordering::Greater => {
20028                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20029                            Ordering::Less | Ordering::Equal => {
20030                                return false;
20031                            }
20032                            Ordering::Greater => break,
20033                        }
20034                    }
20035                }
20036            }
20037
20038            true
20039        })
20040    }
20041
20042    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20043    pub fn clear_row_highlights<T: 'static>(&mut self) {
20044        self.highlighted_rows.remove(&TypeId::of::<T>());
20045    }
20046
20047    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20048    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20049        self.highlighted_rows
20050            .get(&TypeId::of::<T>())
20051            .map_or(&[] as &[_], |vec| vec.as_slice())
20052            .iter()
20053            .map(|highlight| (highlight.range.clone(), highlight.color))
20054    }
20055
20056    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20057    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20058    /// Allows to ignore certain kinds of highlights.
20059    pub fn highlighted_display_rows(
20060        &self,
20061        window: &mut Window,
20062        cx: &mut App,
20063    ) -> BTreeMap<DisplayRow, LineHighlight> {
20064        let snapshot = self.snapshot(window, cx);
20065        let mut used_highlight_orders = HashMap::default();
20066        self.highlighted_rows
20067            .iter()
20068            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20069            .fold(
20070                BTreeMap::<DisplayRow, LineHighlight>::new(),
20071                |mut unique_rows, highlight| {
20072                    let start = highlight.range.start.to_display_point(&snapshot);
20073                    let end = highlight.range.end.to_display_point(&snapshot);
20074                    let start_row = start.row().0;
20075                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20076                        && end.column() == 0
20077                    {
20078                        end.row().0.saturating_sub(1)
20079                    } else {
20080                        end.row().0
20081                    };
20082                    for row in start_row..=end_row {
20083                        let used_index =
20084                            used_highlight_orders.entry(row).or_insert(highlight.index);
20085                        if highlight.index >= *used_index {
20086                            *used_index = highlight.index;
20087                            unique_rows.insert(
20088                                DisplayRow(row),
20089                                LineHighlight {
20090                                    include_gutter: highlight.options.include_gutter,
20091                                    border: None,
20092                                    background: highlight.color.into(),
20093                                    type_id: Some(highlight.type_id),
20094                                },
20095                            );
20096                        }
20097                    }
20098                    unique_rows
20099                },
20100            )
20101    }
20102
20103    pub fn highlighted_display_row_for_autoscroll(
20104        &self,
20105        snapshot: &DisplaySnapshot,
20106    ) -> Option<DisplayRow> {
20107        self.highlighted_rows
20108            .values()
20109            .flat_map(|highlighted_rows| highlighted_rows.iter())
20110            .filter_map(|highlight| {
20111                if highlight.options.autoscroll {
20112                    Some(highlight.range.start.to_display_point(snapshot).row())
20113                } else {
20114                    None
20115                }
20116            })
20117            .min()
20118    }
20119
20120    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20121        self.highlight_background::<SearchWithinRange>(
20122            ranges,
20123            |colors| colors.colors().editor_document_highlight_read_background,
20124            cx,
20125        )
20126    }
20127
20128    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20129        self.breadcrumb_header = Some(new_header);
20130    }
20131
20132    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20133        self.clear_background_highlights::<SearchWithinRange>(cx);
20134    }
20135
20136    pub fn highlight_background<T: 'static>(
20137        &mut self,
20138        ranges: &[Range<Anchor>],
20139        color_fetcher: fn(&Theme) -> Hsla,
20140        cx: &mut Context<Self>,
20141    ) {
20142        self.background_highlights.insert(
20143            HighlightKey::Type(TypeId::of::<T>()),
20144            (color_fetcher, Arc::from(ranges)),
20145        );
20146        self.scrollbar_marker_state.dirty = true;
20147        cx.notify();
20148    }
20149
20150    pub fn highlight_background_key<T: 'static>(
20151        &mut self,
20152        key: usize,
20153        ranges: &[Range<Anchor>],
20154        color_fetcher: fn(&Theme) -> Hsla,
20155        cx: &mut Context<Self>,
20156    ) {
20157        self.background_highlights.insert(
20158            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20159            (color_fetcher, Arc::from(ranges)),
20160        );
20161        self.scrollbar_marker_state.dirty = true;
20162        cx.notify();
20163    }
20164
20165    pub fn clear_background_highlights<T: 'static>(
20166        &mut self,
20167        cx: &mut Context<Self>,
20168    ) -> Option<BackgroundHighlight> {
20169        let text_highlights = self
20170            .background_highlights
20171            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20172        if !text_highlights.1.is_empty() {
20173            self.scrollbar_marker_state.dirty = true;
20174            cx.notify();
20175        }
20176        Some(text_highlights)
20177    }
20178
20179    pub fn highlight_gutter<T: 'static>(
20180        &mut self,
20181        ranges: impl Into<Vec<Range<Anchor>>>,
20182        color_fetcher: fn(&App) -> Hsla,
20183        cx: &mut Context<Self>,
20184    ) {
20185        self.gutter_highlights
20186            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20187        cx.notify();
20188    }
20189
20190    pub fn clear_gutter_highlights<T: 'static>(
20191        &mut self,
20192        cx: &mut Context<Self>,
20193    ) -> Option<GutterHighlight> {
20194        cx.notify();
20195        self.gutter_highlights.remove(&TypeId::of::<T>())
20196    }
20197
20198    pub fn insert_gutter_highlight<T: 'static>(
20199        &mut self,
20200        range: Range<Anchor>,
20201        color_fetcher: fn(&App) -> Hsla,
20202        cx: &mut Context<Self>,
20203    ) {
20204        let snapshot = self.buffer().read(cx).snapshot(cx);
20205        let mut highlights = self
20206            .gutter_highlights
20207            .remove(&TypeId::of::<T>())
20208            .map(|(_, highlights)| highlights)
20209            .unwrap_or_default();
20210        let ix = highlights.binary_search_by(|highlight| {
20211            Ordering::Equal
20212                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20213                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20214        });
20215        if let Err(ix) = ix {
20216            highlights.insert(ix, range);
20217        }
20218        self.gutter_highlights
20219            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20220    }
20221
20222    pub fn remove_gutter_highlights<T: 'static>(
20223        &mut self,
20224        ranges_to_remove: Vec<Range<Anchor>>,
20225        cx: &mut Context<Self>,
20226    ) {
20227        let snapshot = self.buffer().read(cx).snapshot(cx);
20228        let Some((color_fetcher, mut gutter_highlights)) =
20229            self.gutter_highlights.remove(&TypeId::of::<T>())
20230        else {
20231            return;
20232        };
20233        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20234        gutter_highlights.retain(|highlight| {
20235            while let Some(range_to_remove) = ranges_to_remove.peek() {
20236                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20237                    Ordering::Less | Ordering::Equal => {
20238                        ranges_to_remove.next();
20239                    }
20240                    Ordering::Greater => {
20241                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20242                            Ordering::Less | Ordering::Equal => {
20243                                return false;
20244                            }
20245                            Ordering::Greater => break,
20246                        }
20247                    }
20248                }
20249            }
20250
20251            true
20252        });
20253        self.gutter_highlights
20254            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20255    }
20256
20257    #[cfg(feature = "test-support")]
20258    pub fn all_text_highlights(
20259        &self,
20260        window: &mut Window,
20261        cx: &mut Context<Self>,
20262    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20263        let snapshot = self.snapshot(window, cx);
20264        self.display_map.update(cx, |display_map, _| {
20265            display_map
20266                .all_text_highlights()
20267                .map(|highlight| {
20268                    let (style, ranges) = highlight.as_ref();
20269                    (
20270                        *style,
20271                        ranges
20272                            .iter()
20273                            .map(|range| range.clone().to_display_points(&snapshot))
20274                            .collect(),
20275                    )
20276                })
20277                .collect()
20278        })
20279    }
20280
20281    #[cfg(feature = "test-support")]
20282    pub fn all_text_background_highlights(
20283        &self,
20284        window: &mut Window,
20285        cx: &mut Context<Self>,
20286    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20287        let snapshot = self.snapshot(window, cx);
20288        let buffer = &snapshot.buffer_snapshot;
20289        let start = buffer.anchor_before(0);
20290        let end = buffer.anchor_after(buffer.len());
20291        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20292    }
20293
20294    #[cfg(any(test, feature = "test-support"))]
20295    pub fn sorted_background_highlights_in_range(
20296        &self,
20297        search_range: Range<Anchor>,
20298        display_snapshot: &DisplaySnapshot,
20299        theme: &Theme,
20300    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20301        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20302        res.sort_by(|a, b| {
20303            a.0.start
20304                .cmp(&b.0.start)
20305                .then_with(|| a.0.end.cmp(&b.0.end))
20306                .then_with(|| a.1.cmp(&b.1))
20307        });
20308        res
20309    }
20310
20311    #[cfg(feature = "test-support")]
20312    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20313        let snapshot = self.buffer().read(cx).snapshot(cx);
20314
20315        let highlights = self
20316            .background_highlights
20317            .get(&HighlightKey::Type(TypeId::of::<
20318                items::BufferSearchHighlights,
20319            >()));
20320
20321        if let Some((_color, ranges)) = highlights {
20322            ranges
20323                .iter()
20324                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20325                .collect_vec()
20326        } else {
20327            vec![]
20328        }
20329    }
20330
20331    fn document_highlights_for_position<'a>(
20332        &'a self,
20333        position: Anchor,
20334        buffer: &'a MultiBufferSnapshot,
20335    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20336        let read_highlights = self
20337            .background_highlights
20338            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20339            .map(|h| &h.1);
20340        let write_highlights = self
20341            .background_highlights
20342            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20343            .map(|h| &h.1);
20344        let left_position = position.bias_left(buffer);
20345        let right_position = position.bias_right(buffer);
20346        read_highlights
20347            .into_iter()
20348            .chain(write_highlights)
20349            .flat_map(move |ranges| {
20350                let start_ix = match ranges.binary_search_by(|probe| {
20351                    let cmp = probe.end.cmp(&left_position, buffer);
20352                    if cmp.is_ge() {
20353                        Ordering::Greater
20354                    } else {
20355                        Ordering::Less
20356                    }
20357                }) {
20358                    Ok(i) | Err(i) => i,
20359                };
20360
20361                ranges[start_ix..]
20362                    .iter()
20363                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20364            })
20365    }
20366
20367    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20368        self.background_highlights
20369            .get(&HighlightKey::Type(TypeId::of::<T>()))
20370            .is_some_and(|(_, highlights)| !highlights.is_empty())
20371    }
20372
20373    /// Returns all background highlights for a given range.
20374    ///
20375    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20376    pub fn background_highlights_in_range(
20377        &self,
20378        search_range: Range<Anchor>,
20379        display_snapshot: &DisplaySnapshot,
20380        theme: &Theme,
20381    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20382        let mut results = Vec::new();
20383        for (color_fetcher, ranges) in self.background_highlights.values() {
20384            let color = color_fetcher(theme);
20385            let start_ix = match ranges.binary_search_by(|probe| {
20386                let cmp = probe
20387                    .end
20388                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20389                if cmp.is_gt() {
20390                    Ordering::Greater
20391                } else {
20392                    Ordering::Less
20393                }
20394            }) {
20395                Ok(i) | Err(i) => i,
20396            };
20397            for range in &ranges[start_ix..] {
20398                if range
20399                    .start
20400                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20401                    .is_ge()
20402                {
20403                    break;
20404                }
20405
20406                let start = range.start.to_display_point(display_snapshot);
20407                let end = range.end.to_display_point(display_snapshot);
20408                results.push((start..end, color))
20409            }
20410        }
20411        results
20412    }
20413
20414    pub fn gutter_highlights_in_range(
20415        &self,
20416        search_range: Range<Anchor>,
20417        display_snapshot: &DisplaySnapshot,
20418        cx: &App,
20419    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20420        let mut results = Vec::new();
20421        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20422            let color = color_fetcher(cx);
20423            let start_ix = match ranges.binary_search_by(|probe| {
20424                let cmp = probe
20425                    .end
20426                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20427                if cmp.is_gt() {
20428                    Ordering::Greater
20429                } else {
20430                    Ordering::Less
20431                }
20432            }) {
20433                Ok(i) | Err(i) => i,
20434            };
20435            for range in &ranges[start_ix..] {
20436                if range
20437                    .start
20438                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20439                    .is_ge()
20440                {
20441                    break;
20442                }
20443
20444                let start = range.start.to_display_point(display_snapshot);
20445                let end = range.end.to_display_point(display_snapshot);
20446                results.push((start..end, color))
20447            }
20448        }
20449        results
20450    }
20451
20452    /// Get the text ranges corresponding to the redaction query
20453    pub fn redacted_ranges(
20454        &self,
20455        search_range: Range<Anchor>,
20456        display_snapshot: &DisplaySnapshot,
20457        cx: &App,
20458    ) -> Vec<Range<DisplayPoint>> {
20459        display_snapshot
20460            .buffer_snapshot
20461            .redacted_ranges(search_range, |file| {
20462                if let Some(file) = file {
20463                    file.is_private()
20464                        && EditorSettings::get(
20465                            Some(SettingsLocation {
20466                                worktree_id: file.worktree_id(cx),
20467                                path: file.path().as_ref(),
20468                            }),
20469                            cx,
20470                        )
20471                        .redact_private_values
20472                } else {
20473                    false
20474                }
20475            })
20476            .map(|range| {
20477                range.start.to_display_point(display_snapshot)
20478                    ..range.end.to_display_point(display_snapshot)
20479            })
20480            .collect()
20481    }
20482
20483    pub fn highlight_text_key<T: 'static>(
20484        &mut self,
20485        key: usize,
20486        ranges: Vec<Range<Anchor>>,
20487        style: HighlightStyle,
20488        cx: &mut Context<Self>,
20489    ) {
20490        self.display_map.update(cx, |map, _| {
20491            map.highlight_text(
20492                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20493                ranges,
20494                style,
20495            );
20496        });
20497        cx.notify();
20498    }
20499
20500    pub fn highlight_text<T: 'static>(
20501        &mut self,
20502        ranges: Vec<Range<Anchor>>,
20503        style: HighlightStyle,
20504        cx: &mut Context<Self>,
20505    ) {
20506        self.display_map.update(cx, |map, _| {
20507            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20508        });
20509        cx.notify();
20510    }
20511
20512    pub(crate) fn highlight_inlays<T: 'static>(
20513        &mut self,
20514        highlights: Vec<InlayHighlight>,
20515        style: HighlightStyle,
20516        cx: &mut Context<Self>,
20517    ) {
20518        self.display_map.update(cx, |map, _| {
20519            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20520        });
20521        cx.notify();
20522    }
20523
20524    pub fn text_highlights<'a, T: 'static>(
20525        &'a self,
20526        cx: &'a App,
20527    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20528        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20529    }
20530
20531    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20532        let cleared = self
20533            .display_map
20534            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20535        if cleared {
20536            cx.notify();
20537        }
20538    }
20539
20540    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20541        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20542            && self.focus_handle.is_focused(window)
20543    }
20544
20545    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20546        self.show_cursor_when_unfocused = is_enabled;
20547        cx.notify();
20548    }
20549
20550    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20551        cx.notify();
20552    }
20553
20554    fn on_debug_session_event(
20555        &mut self,
20556        _session: Entity<Session>,
20557        event: &SessionEvent,
20558        cx: &mut Context<Self>,
20559    ) {
20560        if let SessionEvent::InvalidateInlineValue = event {
20561            self.refresh_inline_values(cx);
20562        }
20563    }
20564
20565    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20566        let Some(project) = self.project.clone() else {
20567            return;
20568        };
20569
20570        if !self.inline_value_cache.enabled {
20571            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20572            self.splice_inlays(&inlays, Vec::new(), cx);
20573            return;
20574        }
20575
20576        let current_execution_position = self
20577            .highlighted_rows
20578            .get(&TypeId::of::<ActiveDebugLine>())
20579            .and_then(|lines| lines.last().map(|line| line.range.end));
20580
20581        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20582            let inline_values = editor
20583                .update(cx, |editor, cx| {
20584                    let Some(current_execution_position) = current_execution_position else {
20585                        return Some(Task::ready(Ok(Vec::new())));
20586                    };
20587
20588                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20589                        let snapshot = buffer.snapshot(cx);
20590
20591                        let excerpt = snapshot.excerpt_containing(
20592                            current_execution_position..current_execution_position,
20593                        )?;
20594
20595                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20596                    })?;
20597
20598                    let range =
20599                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20600
20601                    project.inline_values(buffer, range, cx)
20602                })
20603                .ok()
20604                .flatten()?
20605                .await
20606                .context("refreshing debugger inlays")
20607                .log_err()?;
20608
20609            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20610
20611            for (buffer_id, inline_value) in inline_values
20612                .into_iter()
20613                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20614            {
20615                buffer_inline_values
20616                    .entry(buffer_id)
20617                    .or_default()
20618                    .push(inline_value);
20619            }
20620
20621            editor
20622                .update(cx, |editor, cx| {
20623                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20624                    let mut new_inlays = Vec::default();
20625
20626                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20627                        let buffer_id = buffer_snapshot.remote_id();
20628                        buffer_inline_values
20629                            .get(&buffer_id)
20630                            .into_iter()
20631                            .flatten()
20632                            .for_each(|hint| {
20633                                let inlay = Inlay::debugger(
20634                                    post_inc(&mut editor.next_inlay_id),
20635                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20636                                    hint.text(),
20637                                );
20638                                if !inlay.text().chars().contains(&'\n') {
20639                                    new_inlays.push(inlay);
20640                                }
20641                            });
20642                    }
20643
20644                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20645                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20646
20647                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20648                })
20649                .ok()?;
20650            Some(())
20651        });
20652    }
20653
20654    fn on_buffer_event(
20655        &mut self,
20656        multibuffer: &Entity<MultiBuffer>,
20657        event: &multi_buffer::Event,
20658        window: &mut Window,
20659        cx: &mut Context<Self>,
20660    ) {
20661        match event {
20662            multi_buffer::Event::Edited {
20663                singleton_buffer_edited,
20664                edited_buffer,
20665            } => {
20666                self.scrollbar_marker_state.dirty = true;
20667                self.active_indent_guides_state.dirty = true;
20668                self.refresh_active_diagnostics(cx);
20669                self.refresh_code_actions(window, cx);
20670                self.refresh_selected_text_highlights(true, window, cx);
20671                self.refresh_single_line_folds(window, cx);
20672                refresh_matching_bracket_highlights(self, window, cx);
20673                if self.has_active_edit_prediction() {
20674                    self.update_visible_edit_prediction(window, cx);
20675                }
20676                if let Some(project) = self.project.as_ref()
20677                    && let Some(edited_buffer) = edited_buffer
20678                {
20679                    project.update(cx, |project, cx| {
20680                        self.registered_buffers
20681                            .entry(edited_buffer.read(cx).remote_id())
20682                            .or_insert_with(|| {
20683                                project.register_buffer_with_language_servers(edited_buffer, cx)
20684                            });
20685                    });
20686                }
20687                cx.emit(EditorEvent::BufferEdited);
20688                cx.emit(SearchEvent::MatchesInvalidated);
20689
20690                if let Some(buffer) = edited_buffer {
20691                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20692                }
20693
20694                if *singleton_buffer_edited {
20695                    if let Some(buffer) = edited_buffer
20696                        && buffer.read(cx).file().is_none()
20697                    {
20698                        cx.emit(EditorEvent::TitleChanged);
20699                    }
20700                    if let Some(project) = &self.project {
20701                        #[allow(clippy::mutable_key_type)]
20702                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20703                            multibuffer
20704                                .all_buffers()
20705                                .into_iter()
20706                                .filter_map(|buffer| {
20707                                    buffer.update(cx, |buffer, cx| {
20708                                        let language = buffer.language()?;
20709                                        let should_discard = project.update(cx, |project, cx| {
20710                                            project.is_local()
20711                                                && !project.has_language_servers_for(buffer, cx)
20712                                        });
20713                                        should_discard.not().then_some(language.clone())
20714                                    })
20715                                })
20716                                .collect::<HashSet<_>>()
20717                        });
20718                        if !languages_affected.is_empty() {
20719                            self.refresh_inlay_hints(
20720                                InlayHintRefreshReason::BufferEdited(languages_affected),
20721                                cx,
20722                            );
20723                        }
20724                    }
20725                }
20726
20727                let Some(project) = &self.project else { return };
20728                let (telemetry, is_via_ssh) = {
20729                    let project = project.read(cx);
20730                    let telemetry = project.client().telemetry().clone();
20731                    let is_via_ssh = project.is_via_remote_server();
20732                    (telemetry, is_via_ssh)
20733                };
20734                refresh_linked_ranges(self, window, cx);
20735                telemetry.log_edit_event("editor", is_via_ssh);
20736            }
20737            multi_buffer::Event::ExcerptsAdded {
20738                buffer,
20739                predecessor,
20740                excerpts,
20741            } => {
20742                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20743                let buffer_id = buffer.read(cx).remote_id();
20744                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20745                    && let Some(project) = &self.project
20746                {
20747                    update_uncommitted_diff_for_buffer(
20748                        cx.entity(),
20749                        project,
20750                        [buffer.clone()],
20751                        self.buffer.clone(),
20752                        cx,
20753                    )
20754                    .detach();
20755                }
20756                if self.active_diagnostics != ActiveDiagnostic::All {
20757                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20758                }
20759                cx.emit(EditorEvent::ExcerptsAdded {
20760                    buffer: buffer.clone(),
20761                    predecessor: *predecessor,
20762                    excerpts: excerpts.clone(),
20763                });
20764                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20765            }
20766            multi_buffer::Event::ExcerptsRemoved {
20767                ids,
20768                removed_buffer_ids,
20769            } => {
20770                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20771                let buffer = self.buffer.read(cx);
20772                self.registered_buffers
20773                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20774                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20775                cx.emit(EditorEvent::ExcerptsRemoved {
20776                    ids: ids.clone(),
20777                    removed_buffer_ids: removed_buffer_ids.clone(),
20778                });
20779            }
20780            multi_buffer::Event::ExcerptsEdited {
20781                excerpt_ids,
20782                buffer_ids,
20783            } => {
20784                self.display_map.update(cx, |map, cx| {
20785                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20786                });
20787                cx.emit(EditorEvent::ExcerptsEdited {
20788                    ids: excerpt_ids.clone(),
20789                });
20790            }
20791            multi_buffer::Event::ExcerptsExpanded { ids } => {
20792                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20793                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20794            }
20795            multi_buffer::Event::Reparsed(buffer_id) => {
20796                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20797                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20798
20799                cx.emit(EditorEvent::Reparsed(*buffer_id));
20800            }
20801            multi_buffer::Event::DiffHunksToggled => {
20802                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20803            }
20804            multi_buffer::Event::LanguageChanged(buffer_id) => {
20805                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20806                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20807                cx.emit(EditorEvent::Reparsed(*buffer_id));
20808                cx.notify();
20809            }
20810            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20811            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20812            multi_buffer::Event::FileHandleChanged
20813            | multi_buffer::Event::Reloaded
20814            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20815            multi_buffer::Event::DiagnosticsUpdated => {
20816                self.update_diagnostics_state(window, cx);
20817            }
20818            _ => {}
20819        };
20820    }
20821
20822    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20823        if !self.diagnostics_enabled() {
20824            return;
20825        }
20826        self.refresh_active_diagnostics(cx);
20827        self.refresh_inline_diagnostics(true, window, cx);
20828        self.scrollbar_marker_state.dirty = true;
20829        cx.notify();
20830    }
20831
20832    pub fn start_temporary_diff_override(&mut self) {
20833        self.load_diff_task.take();
20834        self.temporary_diff_override = true;
20835    }
20836
20837    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20838        self.temporary_diff_override = false;
20839        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20840        self.buffer.update(cx, |buffer, cx| {
20841            buffer.set_all_diff_hunks_collapsed(cx);
20842        });
20843
20844        if let Some(project) = self.project.clone() {
20845            self.load_diff_task = Some(
20846                update_uncommitted_diff_for_buffer(
20847                    cx.entity(),
20848                    &project,
20849                    self.buffer.read(cx).all_buffers(),
20850                    self.buffer.clone(),
20851                    cx,
20852                )
20853                .shared(),
20854            );
20855        }
20856    }
20857
20858    fn on_display_map_changed(
20859        &mut self,
20860        _: Entity<DisplayMap>,
20861        _: &mut Window,
20862        cx: &mut Context<Self>,
20863    ) {
20864        cx.notify();
20865    }
20866
20867    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20868        if self.diagnostics_enabled() {
20869            let new_severity = EditorSettings::get_global(cx)
20870                .diagnostics_max_severity
20871                .unwrap_or(DiagnosticSeverity::Hint);
20872            self.set_max_diagnostics_severity(new_severity, cx);
20873        }
20874        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20875        self.update_edit_prediction_settings(cx);
20876        self.refresh_edit_prediction(true, false, window, cx);
20877        self.refresh_inline_values(cx);
20878        self.refresh_inlay_hints(
20879            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20880                self.selections.newest_anchor().head(),
20881                &self.buffer.read(cx).snapshot(cx),
20882                cx,
20883            )),
20884            cx,
20885        );
20886
20887        let old_cursor_shape = self.cursor_shape;
20888        let old_show_breadcrumbs = self.show_breadcrumbs;
20889
20890        {
20891            let editor_settings = EditorSettings::get_global(cx);
20892            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20893            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20894            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20895            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20896        }
20897
20898        if old_cursor_shape != self.cursor_shape {
20899            cx.emit(EditorEvent::CursorShapeChanged);
20900        }
20901
20902        if old_show_breadcrumbs != self.show_breadcrumbs {
20903            cx.emit(EditorEvent::BreadcrumbsChanged);
20904        }
20905
20906        let project_settings = ProjectSettings::get_global(cx);
20907        self.serialize_dirty_buffers =
20908            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20909
20910        if self.mode.is_full() {
20911            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20912            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20913            if self.show_inline_diagnostics != show_inline_diagnostics {
20914                self.show_inline_diagnostics = show_inline_diagnostics;
20915                self.refresh_inline_diagnostics(false, window, cx);
20916            }
20917
20918            if self.git_blame_inline_enabled != inline_blame_enabled {
20919                self.toggle_git_blame_inline_internal(false, window, cx);
20920            }
20921
20922            let minimap_settings = EditorSettings::get_global(cx).minimap;
20923            if self.minimap_visibility != MinimapVisibility::Disabled {
20924                if self.minimap_visibility.settings_visibility()
20925                    != minimap_settings.minimap_enabled()
20926                {
20927                    self.set_minimap_visibility(
20928                        MinimapVisibility::for_mode(self.mode(), cx),
20929                        window,
20930                        cx,
20931                    );
20932                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20933                    minimap_entity.update(cx, |minimap_editor, cx| {
20934                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20935                    })
20936                }
20937            }
20938        }
20939
20940        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20941            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20942        }) {
20943            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20944                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20945            }
20946            self.refresh_colors(false, None, window, cx);
20947        }
20948
20949        cx.notify();
20950    }
20951
20952    pub fn set_searchable(&mut self, searchable: bool) {
20953        self.searchable = searchable;
20954    }
20955
20956    pub fn searchable(&self) -> bool {
20957        self.searchable
20958    }
20959
20960    fn open_proposed_changes_editor(
20961        &mut self,
20962        _: &OpenProposedChangesEditor,
20963        window: &mut Window,
20964        cx: &mut Context<Self>,
20965    ) {
20966        let Some(workspace) = self.workspace() else {
20967            cx.propagate();
20968            return;
20969        };
20970
20971        let selections = self.selections.all::<usize>(cx);
20972        let multi_buffer = self.buffer.read(cx);
20973        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20974        let mut new_selections_by_buffer = HashMap::default();
20975        for selection in selections {
20976            for (buffer, range, _) in
20977                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20978            {
20979                let mut range = range.to_point(buffer);
20980                range.start.column = 0;
20981                range.end.column = buffer.line_len(range.end.row);
20982                new_selections_by_buffer
20983                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20984                    .or_insert(Vec::new())
20985                    .push(range)
20986            }
20987        }
20988
20989        let proposed_changes_buffers = new_selections_by_buffer
20990            .into_iter()
20991            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20992            .collect::<Vec<_>>();
20993        let proposed_changes_editor = cx.new(|cx| {
20994            ProposedChangesEditor::new(
20995                "Proposed changes",
20996                proposed_changes_buffers,
20997                self.project.clone(),
20998                window,
20999                cx,
21000            )
21001        });
21002
21003        window.defer(cx, move |window, cx| {
21004            workspace.update(cx, |workspace, cx| {
21005                workspace.active_pane().update(cx, |pane, cx| {
21006                    pane.add_item(
21007                        Box::new(proposed_changes_editor),
21008                        true,
21009                        true,
21010                        None,
21011                        window,
21012                        cx,
21013                    );
21014                });
21015            });
21016        });
21017    }
21018
21019    pub fn open_excerpts_in_split(
21020        &mut self,
21021        _: &OpenExcerptsSplit,
21022        window: &mut Window,
21023        cx: &mut Context<Self>,
21024    ) {
21025        self.open_excerpts_common(None, true, window, cx)
21026    }
21027
21028    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21029        self.open_excerpts_common(None, false, window, cx)
21030    }
21031
21032    fn open_excerpts_common(
21033        &mut self,
21034        jump_data: Option<JumpData>,
21035        split: bool,
21036        window: &mut Window,
21037        cx: &mut Context<Self>,
21038    ) {
21039        let Some(workspace) = self.workspace() else {
21040            cx.propagate();
21041            return;
21042        };
21043
21044        if self.buffer.read(cx).is_singleton() {
21045            cx.propagate();
21046            return;
21047        }
21048
21049        let mut new_selections_by_buffer = HashMap::default();
21050        match &jump_data {
21051            Some(JumpData::MultiBufferPoint {
21052                excerpt_id,
21053                position,
21054                anchor,
21055                line_offset_from_top,
21056            }) => {
21057                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21058                if let Some(buffer) = multi_buffer_snapshot
21059                    .buffer_id_for_excerpt(*excerpt_id)
21060                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21061                {
21062                    let buffer_snapshot = buffer.read(cx).snapshot();
21063                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21064                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21065                    } else {
21066                        buffer_snapshot.clip_point(*position, Bias::Left)
21067                    };
21068                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21069                    new_selections_by_buffer.insert(
21070                        buffer,
21071                        (
21072                            vec![jump_to_offset..jump_to_offset],
21073                            Some(*line_offset_from_top),
21074                        ),
21075                    );
21076                }
21077            }
21078            Some(JumpData::MultiBufferRow {
21079                row,
21080                line_offset_from_top,
21081            }) => {
21082                let point = MultiBufferPoint::new(row.0, 0);
21083                if let Some((buffer, buffer_point, _)) =
21084                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21085                {
21086                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21087                    new_selections_by_buffer
21088                        .entry(buffer)
21089                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21090                        .0
21091                        .push(buffer_offset..buffer_offset)
21092                }
21093            }
21094            None => {
21095                let selections = self.selections.all::<usize>(cx);
21096                let multi_buffer = self.buffer.read(cx);
21097                for selection in selections {
21098                    for (snapshot, range, _, anchor) in multi_buffer
21099                        .snapshot(cx)
21100                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21101                    {
21102                        if let Some(anchor) = anchor {
21103                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21104                            else {
21105                                continue;
21106                            };
21107                            let offset = text::ToOffset::to_offset(
21108                                &anchor.text_anchor,
21109                                &buffer_handle.read(cx).snapshot(),
21110                            );
21111                            let range = offset..offset;
21112                            new_selections_by_buffer
21113                                .entry(buffer_handle)
21114                                .or_insert((Vec::new(), None))
21115                                .0
21116                                .push(range)
21117                        } else {
21118                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21119                            else {
21120                                continue;
21121                            };
21122                            new_selections_by_buffer
21123                                .entry(buffer_handle)
21124                                .or_insert((Vec::new(), None))
21125                                .0
21126                                .push(range)
21127                        }
21128                    }
21129                }
21130            }
21131        }
21132
21133        new_selections_by_buffer
21134            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21135
21136        if new_selections_by_buffer.is_empty() {
21137            return;
21138        }
21139
21140        // We defer the pane interaction because we ourselves are a workspace item
21141        // and activating a new item causes the pane to call a method on us reentrantly,
21142        // which panics if we're on the stack.
21143        window.defer(cx, move |window, cx| {
21144            workspace.update(cx, |workspace, cx| {
21145                let pane = if split {
21146                    workspace.adjacent_pane(window, cx)
21147                } else {
21148                    workspace.active_pane().clone()
21149                };
21150
21151                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21152                    let editor = buffer
21153                        .read(cx)
21154                        .file()
21155                        .is_none()
21156                        .then(|| {
21157                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21158                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21159                            // Instead, we try to activate the existing editor in the pane first.
21160                            let (editor, pane_item_index) =
21161                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21162                                    let editor = item.downcast::<Editor>()?;
21163                                    let singleton_buffer =
21164                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21165                                    if singleton_buffer == buffer {
21166                                        Some((editor, i))
21167                                    } else {
21168                                        None
21169                                    }
21170                                })?;
21171                            pane.update(cx, |pane, cx| {
21172                                pane.activate_item(pane_item_index, true, true, window, cx)
21173                            });
21174                            Some(editor)
21175                        })
21176                        .flatten()
21177                        .unwrap_or_else(|| {
21178                            workspace.open_project_item::<Self>(
21179                                pane.clone(),
21180                                buffer,
21181                                true,
21182                                true,
21183                                window,
21184                                cx,
21185                            )
21186                        });
21187
21188                    editor.update(cx, |editor, cx| {
21189                        let autoscroll = match scroll_offset {
21190                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21191                            None => Autoscroll::newest(),
21192                        };
21193                        let nav_history = editor.nav_history.take();
21194                        editor.change_selections(
21195                            SelectionEffects::scroll(autoscroll),
21196                            window,
21197                            cx,
21198                            |s| {
21199                                s.select_ranges(ranges);
21200                            },
21201                        );
21202                        editor.nav_history = nav_history;
21203                    });
21204                }
21205            })
21206        });
21207    }
21208
21209    // For now, don't allow opening excerpts in buffers that aren't backed by
21210    // regular project files.
21211    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21212        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21213    }
21214
21215    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21216        let snapshot = self.buffer.read(cx).read(cx);
21217        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21218        Some(
21219            ranges
21220                .iter()
21221                .map(move |range| {
21222                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21223                })
21224                .collect(),
21225        )
21226    }
21227
21228    fn selection_replacement_ranges(
21229        &self,
21230        range: Range<OffsetUtf16>,
21231        cx: &mut App,
21232    ) -> Vec<Range<OffsetUtf16>> {
21233        let selections = self.selections.all::<OffsetUtf16>(cx);
21234        let newest_selection = selections
21235            .iter()
21236            .max_by_key(|selection| selection.id)
21237            .unwrap();
21238        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21239        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21240        let snapshot = self.buffer.read(cx).read(cx);
21241        selections
21242            .into_iter()
21243            .map(|mut selection| {
21244                selection.start.0 =
21245                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21246                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21247                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21248                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21249            })
21250            .collect()
21251    }
21252
21253    fn report_editor_event(
21254        &self,
21255        reported_event: ReportEditorEvent,
21256        file_extension: Option<String>,
21257        cx: &App,
21258    ) {
21259        if cfg!(any(test, feature = "test-support")) {
21260            return;
21261        }
21262
21263        let Some(project) = &self.project else { return };
21264
21265        // If None, we are in a file without an extension
21266        let file = self
21267            .buffer
21268            .read(cx)
21269            .as_singleton()
21270            .and_then(|b| b.read(cx).file());
21271        let file_extension = file_extension.or(file
21272            .as_ref()
21273            .and_then(|file| Path::new(file.file_name(cx)).extension())
21274            .and_then(|e| e.to_str())
21275            .map(|a| a.to_string()));
21276
21277        let vim_mode = vim_enabled(cx);
21278
21279        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21280        let copilot_enabled = edit_predictions_provider
21281            == language::language_settings::EditPredictionProvider::Copilot;
21282        let copilot_enabled_for_language = self
21283            .buffer
21284            .read(cx)
21285            .language_settings(cx)
21286            .show_edit_predictions;
21287
21288        let project = project.read(cx);
21289        let event_type = reported_event.event_type();
21290
21291        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21292            telemetry::event!(
21293                event_type,
21294                type = if auto_saved {"autosave"} else {"manual"},
21295                file_extension,
21296                vim_mode,
21297                copilot_enabled,
21298                copilot_enabled_for_language,
21299                edit_predictions_provider,
21300                is_via_ssh = project.is_via_remote_server(),
21301            );
21302        } else {
21303            telemetry::event!(
21304                event_type,
21305                file_extension,
21306                vim_mode,
21307                copilot_enabled,
21308                copilot_enabled_for_language,
21309                edit_predictions_provider,
21310                is_via_ssh = project.is_via_remote_server(),
21311            );
21312        };
21313    }
21314
21315    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21316    /// with each line being an array of {text, highlight} objects.
21317    fn copy_highlight_json(
21318        &mut self,
21319        _: &CopyHighlightJson,
21320        window: &mut Window,
21321        cx: &mut Context<Self>,
21322    ) {
21323        #[derive(Serialize)]
21324        struct Chunk<'a> {
21325            text: String,
21326            highlight: Option<&'a str>,
21327        }
21328
21329        let snapshot = self.buffer.read(cx).snapshot(cx);
21330        let range = self
21331            .selected_text_range(false, window, cx)
21332            .and_then(|selection| {
21333                if selection.range.is_empty() {
21334                    None
21335                } else {
21336                    Some(selection.range)
21337                }
21338            })
21339            .unwrap_or_else(|| 0..snapshot.len());
21340
21341        let chunks = snapshot.chunks(range, true);
21342        let mut lines = Vec::new();
21343        let mut line: VecDeque<Chunk> = VecDeque::new();
21344
21345        let Some(style) = self.style.as_ref() else {
21346            return;
21347        };
21348
21349        for chunk in chunks {
21350            let highlight = chunk
21351                .syntax_highlight_id
21352                .and_then(|id| id.name(&style.syntax));
21353            let mut chunk_lines = chunk.text.split('\n').peekable();
21354            while let Some(text) = chunk_lines.next() {
21355                let mut merged_with_last_token = false;
21356                if let Some(last_token) = line.back_mut()
21357                    && last_token.highlight == highlight
21358                {
21359                    last_token.text.push_str(text);
21360                    merged_with_last_token = true;
21361                }
21362
21363                if !merged_with_last_token {
21364                    line.push_back(Chunk {
21365                        text: text.into(),
21366                        highlight,
21367                    });
21368                }
21369
21370                if chunk_lines.peek().is_some() {
21371                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21372                        line.pop_front();
21373                    }
21374                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21375                        line.pop_back();
21376                    }
21377
21378                    lines.push(mem::take(&mut line));
21379                }
21380            }
21381        }
21382
21383        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21384            return;
21385        };
21386        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21387    }
21388
21389    pub fn open_context_menu(
21390        &mut self,
21391        _: &OpenContextMenu,
21392        window: &mut Window,
21393        cx: &mut Context<Self>,
21394    ) {
21395        self.request_autoscroll(Autoscroll::newest(), cx);
21396        let position = self.selections.newest_display(cx).start;
21397        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21398    }
21399
21400    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21401        &self.inlay_hint_cache
21402    }
21403
21404    pub fn replay_insert_event(
21405        &mut self,
21406        text: &str,
21407        relative_utf16_range: Option<Range<isize>>,
21408        window: &mut Window,
21409        cx: &mut Context<Self>,
21410    ) {
21411        if !self.input_enabled {
21412            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21413            return;
21414        }
21415        if let Some(relative_utf16_range) = relative_utf16_range {
21416            let selections = self.selections.all::<OffsetUtf16>(cx);
21417            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21418                let new_ranges = selections.into_iter().map(|range| {
21419                    let start = OffsetUtf16(
21420                        range
21421                            .head()
21422                            .0
21423                            .saturating_add_signed(relative_utf16_range.start),
21424                    );
21425                    let end = OffsetUtf16(
21426                        range
21427                            .head()
21428                            .0
21429                            .saturating_add_signed(relative_utf16_range.end),
21430                    );
21431                    start..end
21432                });
21433                s.select_ranges(new_ranges);
21434            });
21435        }
21436
21437        self.handle_input(text, window, cx);
21438    }
21439
21440    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21441        let Some(provider) = self.semantics_provider.as_ref() else {
21442            return false;
21443        };
21444
21445        let mut supports = false;
21446        self.buffer().update(cx, |this, cx| {
21447            this.for_each_buffer(|buffer| {
21448                supports |= provider.supports_inlay_hints(buffer, cx);
21449            });
21450        });
21451
21452        supports
21453    }
21454
21455    pub fn is_focused(&self, window: &Window) -> bool {
21456        self.focus_handle.is_focused(window)
21457    }
21458
21459    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21460        cx.emit(EditorEvent::Focused);
21461
21462        if let Some(descendant) = self
21463            .last_focused_descendant
21464            .take()
21465            .and_then(|descendant| descendant.upgrade())
21466        {
21467            window.focus(&descendant);
21468        } else {
21469            if let Some(blame) = self.blame.as_ref() {
21470                blame.update(cx, GitBlame::focus)
21471            }
21472
21473            self.blink_manager.update(cx, BlinkManager::enable);
21474            self.show_cursor_names(window, cx);
21475            self.buffer.update(cx, |buffer, cx| {
21476                buffer.finalize_last_transaction(cx);
21477                if self.leader_id.is_none() {
21478                    buffer.set_active_selections(
21479                        &self.selections.disjoint_anchors_arc(),
21480                        self.selections.line_mode(),
21481                        self.cursor_shape,
21482                        cx,
21483                    );
21484                }
21485            });
21486        }
21487    }
21488
21489    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21490        cx.emit(EditorEvent::FocusedIn)
21491    }
21492
21493    fn handle_focus_out(
21494        &mut self,
21495        event: FocusOutEvent,
21496        _window: &mut Window,
21497        cx: &mut Context<Self>,
21498    ) {
21499        if event.blurred != self.focus_handle {
21500            self.last_focused_descendant = Some(event.blurred);
21501        }
21502        self.selection_drag_state = SelectionDragState::None;
21503        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21504    }
21505
21506    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21507        self.blink_manager.update(cx, BlinkManager::disable);
21508        self.buffer
21509            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21510
21511        if let Some(blame) = self.blame.as_ref() {
21512            blame.update(cx, GitBlame::blur)
21513        }
21514        if !self.hover_state.focused(window, cx) {
21515            hide_hover(self, cx);
21516        }
21517        if !self
21518            .context_menu
21519            .borrow()
21520            .as_ref()
21521            .is_some_and(|context_menu| context_menu.focused(window, cx))
21522        {
21523            self.hide_context_menu(window, cx);
21524        }
21525        self.take_active_edit_prediction(cx);
21526        cx.emit(EditorEvent::Blurred);
21527        cx.notify();
21528    }
21529
21530    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21531        let mut pending: String = window
21532            .pending_input_keystrokes()
21533            .into_iter()
21534            .flatten()
21535            .filter_map(|keystroke| {
21536                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21537                    keystroke.key_char.clone()
21538                } else {
21539                    None
21540                }
21541            })
21542            .collect();
21543
21544        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21545            pending = "".to_string();
21546        }
21547
21548        let existing_pending = self
21549            .text_highlights::<PendingInput>(cx)
21550            .map(|(_, ranges)| ranges.to_vec());
21551        if existing_pending.is_none() && pending.is_empty() {
21552            return;
21553        }
21554        let transaction =
21555            self.transact(window, cx, |this, window, cx| {
21556                let selections = this.selections.all::<usize>(cx);
21557                let edits = selections
21558                    .iter()
21559                    .map(|selection| (selection.end..selection.end, pending.clone()));
21560                this.edit(edits, cx);
21561                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21562                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21563                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21564                    }));
21565                });
21566                if let Some(existing_ranges) = existing_pending {
21567                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21568                    this.edit(edits, cx);
21569                }
21570            });
21571
21572        let snapshot = self.snapshot(window, cx);
21573        let ranges = self
21574            .selections
21575            .all::<usize>(cx)
21576            .into_iter()
21577            .map(|selection| {
21578                snapshot.buffer_snapshot.anchor_after(selection.end)
21579                    ..snapshot
21580                        .buffer_snapshot
21581                        .anchor_before(selection.end + pending.len())
21582            })
21583            .collect();
21584
21585        if pending.is_empty() {
21586            self.clear_highlights::<PendingInput>(cx);
21587        } else {
21588            self.highlight_text::<PendingInput>(
21589                ranges,
21590                HighlightStyle {
21591                    underline: Some(UnderlineStyle {
21592                        thickness: px(1.),
21593                        color: None,
21594                        wavy: false,
21595                    }),
21596                    ..Default::default()
21597                },
21598                cx,
21599            );
21600        }
21601
21602        self.ime_transaction = self.ime_transaction.or(transaction);
21603        if let Some(transaction) = self.ime_transaction {
21604            self.buffer.update(cx, |buffer, cx| {
21605                buffer.group_until_transaction(transaction, cx);
21606            });
21607        }
21608
21609        if self.text_highlights::<PendingInput>(cx).is_none() {
21610            self.ime_transaction.take();
21611        }
21612    }
21613
21614    pub fn register_action_renderer(
21615        &mut self,
21616        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21617    ) -> Subscription {
21618        let id = self.next_editor_action_id.post_inc();
21619        self.editor_actions
21620            .borrow_mut()
21621            .insert(id, Box::new(listener));
21622
21623        let editor_actions = self.editor_actions.clone();
21624        Subscription::new(move || {
21625            editor_actions.borrow_mut().remove(&id);
21626        })
21627    }
21628
21629    pub fn register_action<A: Action>(
21630        &mut self,
21631        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21632    ) -> Subscription {
21633        let id = self.next_editor_action_id.post_inc();
21634        let listener = Arc::new(listener);
21635        self.editor_actions.borrow_mut().insert(
21636            id,
21637            Box::new(move |_, window, _| {
21638                let listener = listener.clone();
21639                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21640                    let action = action.downcast_ref().unwrap();
21641                    if phase == DispatchPhase::Bubble {
21642                        listener(action, window, cx)
21643                    }
21644                })
21645            }),
21646        );
21647
21648        let editor_actions = self.editor_actions.clone();
21649        Subscription::new(move || {
21650            editor_actions.borrow_mut().remove(&id);
21651        })
21652    }
21653
21654    pub fn file_header_size(&self) -> u32 {
21655        FILE_HEADER_HEIGHT
21656    }
21657
21658    pub fn restore(
21659        &mut self,
21660        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21661        window: &mut Window,
21662        cx: &mut Context<Self>,
21663    ) {
21664        let workspace = self.workspace();
21665        let project = self.project();
21666        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21667            let mut tasks = Vec::new();
21668            for (buffer_id, changes) in revert_changes {
21669                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21670                    buffer.update(cx, |buffer, cx| {
21671                        buffer.edit(
21672                            changes
21673                                .into_iter()
21674                                .map(|(range, text)| (range, text.to_string())),
21675                            None,
21676                            cx,
21677                        );
21678                    });
21679
21680                    if let Some(project) =
21681                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21682                    {
21683                        project.update(cx, |project, cx| {
21684                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21685                        })
21686                    }
21687                }
21688            }
21689            tasks
21690        });
21691        cx.spawn_in(window, async move |_, cx| {
21692            for (buffer, task) in save_tasks {
21693                let result = task.await;
21694                if result.is_err() {
21695                    let Some(path) = buffer
21696                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21697                        .ok()
21698                    else {
21699                        continue;
21700                    };
21701                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21702                        let Some(task) = cx
21703                            .update_window_entity(workspace, |workspace, window, cx| {
21704                                workspace
21705                                    .open_path_preview(path, None, false, false, false, window, cx)
21706                            })
21707                            .ok()
21708                        else {
21709                            continue;
21710                        };
21711                        task.await.log_err();
21712                    }
21713                }
21714            }
21715        })
21716        .detach();
21717        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21718            selections.refresh()
21719        });
21720    }
21721
21722    pub fn to_pixel_point(
21723        &self,
21724        source: multi_buffer::Anchor,
21725        editor_snapshot: &EditorSnapshot,
21726        window: &mut Window,
21727    ) -> Option<gpui::Point<Pixels>> {
21728        let source_point = source.to_display_point(editor_snapshot);
21729        self.display_to_pixel_point(source_point, editor_snapshot, window)
21730    }
21731
21732    pub fn display_to_pixel_point(
21733        &self,
21734        source: DisplayPoint,
21735        editor_snapshot: &EditorSnapshot,
21736        window: &mut Window,
21737    ) -> Option<gpui::Point<Pixels>> {
21738        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21739        let text_layout_details = self.text_layout_details(window);
21740        let scroll_top = text_layout_details
21741            .scroll_anchor
21742            .scroll_position(editor_snapshot)
21743            .y;
21744
21745        if source.row().as_f32() < scroll_top.floor() {
21746            return None;
21747        }
21748        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21749        let source_y = line_height * (source.row().as_f32() - scroll_top);
21750        Some(gpui::Point::new(source_x, source_y))
21751    }
21752
21753    pub fn has_visible_completions_menu(&self) -> bool {
21754        !self.edit_prediction_preview_is_active()
21755            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21756                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21757            })
21758    }
21759
21760    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21761        if self.mode.is_minimap() {
21762            return;
21763        }
21764        self.addons
21765            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21766    }
21767
21768    pub fn unregister_addon<T: Addon>(&mut self) {
21769        self.addons.remove(&std::any::TypeId::of::<T>());
21770    }
21771
21772    pub fn addon<T: Addon>(&self) -> Option<&T> {
21773        let type_id = std::any::TypeId::of::<T>();
21774        self.addons
21775            .get(&type_id)
21776            .and_then(|item| item.to_any().downcast_ref::<T>())
21777    }
21778
21779    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21780        let type_id = std::any::TypeId::of::<T>();
21781        self.addons
21782            .get_mut(&type_id)
21783            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21784    }
21785
21786    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21787        let text_layout_details = self.text_layout_details(window);
21788        let style = &text_layout_details.editor_style;
21789        let font_id = window.text_system().resolve_font(&style.text.font());
21790        let font_size = style.text.font_size.to_pixels(window.rem_size());
21791        let line_height = style.text.line_height_in_pixels(window.rem_size());
21792        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21793        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21794
21795        CharacterDimensions {
21796            em_width,
21797            em_advance,
21798            line_height,
21799        }
21800    }
21801
21802    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21803        self.load_diff_task.clone()
21804    }
21805
21806    fn read_metadata_from_db(
21807        &mut self,
21808        item_id: u64,
21809        workspace_id: WorkspaceId,
21810        window: &mut Window,
21811        cx: &mut Context<Editor>,
21812    ) {
21813        if self.is_singleton(cx)
21814            && !self.mode.is_minimap()
21815            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21816        {
21817            let buffer_snapshot = OnceCell::new();
21818
21819            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21820                && !folds.is_empty()
21821            {
21822                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21823                self.fold_ranges(
21824                    folds
21825                        .into_iter()
21826                        .map(|(start, end)| {
21827                            snapshot.clip_offset(start, Bias::Left)
21828                                ..snapshot.clip_offset(end, Bias::Right)
21829                        })
21830                        .collect(),
21831                    false,
21832                    window,
21833                    cx,
21834                );
21835            }
21836
21837            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21838                && !selections.is_empty()
21839            {
21840                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21841                // skip adding the initial selection to selection history
21842                self.selection_history.mode = SelectionHistoryMode::Skipping;
21843                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21844                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21845                        snapshot.clip_offset(start, Bias::Left)
21846                            ..snapshot.clip_offset(end, Bias::Right)
21847                    }));
21848                });
21849                self.selection_history.mode = SelectionHistoryMode::Normal;
21850            };
21851        }
21852
21853        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21854    }
21855
21856    fn update_lsp_data(
21857        &mut self,
21858        ignore_cache: bool,
21859        for_buffer: Option<BufferId>,
21860        window: &mut Window,
21861        cx: &mut Context<'_, Self>,
21862    ) {
21863        self.pull_diagnostics(for_buffer, window, cx);
21864        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21865    }
21866}
21867
21868fn edit_for_markdown_paste<'a>(
21869    buffer: &MultiBufferSnapshot,
21870    range: Range<usize>,
21871    to_insert: &'a str,
21872    url: Option<url::Url>,
21873) -> (Range<usize>, Cow<'a, str>) {
21874    if url.is_none() {
21875        return (range, Cow::Borrowed(to_insert));
21876    };
21877
21878    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21879
21880    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21881        Cow::Borrowed(to_insert)
21882    } else {
21883        Cow::Owned(format!("[{old_text}]({to_insert})"))
21884    };
21885    (range, new_text)
21886}
21887
21888fn vim_enabled(cx: &App) -> bool {
21889    vim_mode_setting::VimModeSetting::try_get(cx)
21890        .map(|vim_mode| vim_mode.0)
21891        .unwrap_or(false)
21892}
21893
21894fn process_completion_for_edit(
21895    completion: &Completion,
21896    intent: CompletionIntent,
21897    buffer: &Entity<Buffer>,
21898    cursor_position: &text::Anchor,
21899    cx: &mut Context<Editor>,
21900) -> CompletionEdit {
21901    let buffer = buffer.read(cx);
21902    let buffer_snapshot = buffer.snapshot();
21903    let (snippet, new_text) = if completion.is_snippet() {
21904        // Workaround for typescript language server issues so that methods don't expand within
21905        // strings and functions with type expressions. The previous point is used because the query
21906        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21907        let mut snippet_source = completion.new_text.clone();
21908        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21909        previous_point.column = previous_point.column.saturating_sub(1);
21910        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21911            && scope.prefers_label_for_snippet_in_completion()
21912            && let Some(label) = completion.label()
21913            && matches!(
21914                completion.kind(),
21915                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21916            )
21917        {
21918            snippet_source = label;
21919        }
21920        match Snippet::parse(&snippet_source).log_err() {
21921            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21922            None => (None, completion.new_text.clone()),
21923        }
21924    } else {
21925        (None, completion.new_text.clone())
21926    };
21927
21928    let mut range_to_replace = {
21929        let replace_range = &completion.replace_range;
21930        if let CompletionSource::Lsp {
21931            insert_range: Some(insert_range),
21932            ..
21933        } = &completion.source
21934        {
21935            debug_assert_eq!(
21936                insert_range.start, replace_range.start,
21937                "insert_range and replace_range should start at the same position"
21938            );
21939            debug_assert!(
21940                insert_range
21941                    .start
21942                    .cmp(cursor_position, &buffer_snapshot)
21943                    .is_le(),
21944                "insert_range should start before or at cursor position"
21945            );
21946            debug_assert!(
21947                replace_range
21948                    .start
21949                    .cmp(cursor_position, &buffer_snapshot)
21950                    .is_le(),
21951                "replace_range should start before or at cursor position"
21952            );
21953
21954            let should_replace = match intent {
21955                CompletionIntent::CompleteWithInsert => false,
21956                CompletionIntent::CompleteWithReplace => true,
21957                CompletionIntent::Complete | CompletionIntent::Compose => {
21958                    let insert_mode =
21959                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21960                            .completions
21961                            .lsp_insert_mode;
21962                    match insert_mode {
21963                        LspInsertMode::Insert => false,
21964                        LspInsertMode::Replace => true,
21965                        LspInsertMode::ReplaceSubsequence => {
21966                            let mut text_to_replace = buffer.chars_for_range(
21967                                buffer.anchor_before(replace_range.start)
21968                                    ..buffer.anchor_after(replace_range.end),
21969                            );
21970                            let mut current_needle = text_to_replace.next();
21971                            for haystack_ch in completion.label.text.chars() {
21972                                if let Some(needle_ch) = current_needle
21973                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21974                                {
21975                                    current_needle = text_to_replace.next();
21976                                }
21977                            }
21978                            current_needle.is_none()
21979                        }
21980                        LspInsertMode::ReplaceSuffix => {
21981                            if replace_range
21982                                .end
21983                                .cmp(cursor_position, &buffer_snapshot)
21984                                .is_gt()
21985                            {
21986                                let range_after_cursor = *cursor_position..replace_range.end;
21987                                let text_after_cursor = buffer
21988                                    .text_for_range(
21989                                        buffer.anchor_before(range_after_cursor.start)
21990                                            ..buffer.anchor_after(range_after_cursor.end),
21991                                    )
21992                                    .collect::<String>()
21993                                    .to_ascii_lowercase();
21994                                completion
21995                                    .label
21996                                    .text
21997                                    .to_ascii_lowercase()
21998                                    .ends_with(&text_after_cursor)
21999                            } else {
22000                                true
22001                            }
22002                        }
22003                    }
22004                }
22005            };
22006
22007            if should_replace {
22008                replace_range.clone()
22009            } else {
22010                insert_range.clone()
22011            }
22012        } else {
22013            replace_range.clone()
22014        }
22015    };
22016
22017    if range_to_replace
22018        .end
22019        .cmp(cursor_position, &buffer_snapshot)
22020        .is_lt()
22021    {
22022        range_to_replace.end = *cursor_position;
22023    }
22024
22025    CompletionEdit {
22026        new_text,
22027        replace_range: range_to_replace.to_offset(buffer),
22028        snippet,
22029    }
22030}
22031
22032struct CompletionEdit {
22033    new_text: String,
22034    replace_range: Range<usize>,
22035    snippet: Option<Snippet>,
22036}
22037
22038fn insert_extra_newline_brackets(
22039    buffer: &MultiBufferSnapshot,
22040    range: Range<usize>,
22041    language: &language::LanguageScope,
22042) -> bool {
22043    let leading_whitespace_len = buffer
22044        .reversed_chars_at(range.start)
22045        .take_while(|c| c.is_whitespace() && *c != '\n')
22046        .map(|c| c.len_utf8())
22047        .sum::<usize>();
22048    let trailing_whitespace_len = buffer
22049        .chars_at(range.end)
22050        .take_while(|c| c.is_whitespace() && *c != '\n')
22051        .map(|c| c.len_utf8())
22052        .sum::<usize>();
22053    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22054
22055    language.brackets().any(|(pair, enabled)| {
22056        let pair_start = pair.start.trim_end();
22057        let pair_end = pair.end.trim_start();
22058
22059        enabled
22060            && pair.newline
22061            && buffer.contains_str_at(range.end, pair_end)
22062            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22063    })
22064}
22065
22066fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22067    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22068        [(buffer, range, _)] => (*buffer, range.clone()),
22069        _ => return false,
22070    };
22071    let pair = {
22072        let mut result: Option<BracketMatch> = None;
22073
22074        for pair in buffer
22075            .all_bracket_ranges(range.clone())
22076            .filter(move |pair| {
22077                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22078            })
22079        {
22080            let len = pair.close_range.end - pair.open_range.start;
22081
22082            if let Some(existing) = &result {
22083                let existing_len = existing.close_range.end - existing.open_range.start;
22084                if len > existing_len {
22085                    continue;
22086                }
22087            }
22088
22089            result = Some(pair);
22090        }
22091
22092        result
22093    };
22094    let Some(pair) = pair else {
22095        return false;
22096    };
22097    pair.newline_only
22098        && buffer
22099            .chars_for_range(pair.open_range.end..range.start)
22100            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22101            .all(|c| c.is_whitespace() && c != '\n')
22102}
22103
22104fn update_uncommitted_diff_for_buffer(
22105    editor: Entity<Editor>,
22106    project: &Entity<Project>,
22107    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22108    buffer: Entity<MultiBuffer>,
22109    cx: &mut App,
22110) -> Task<()> {
22111    let mut tasks = Vec::new();
22112    project.update(cx, |project, cx| {
22113        for buffer in buffers {
22114            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22115                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22116            }
22117        }
22118    });
22119    cx.spawn(async move |cx| {
22120        let diffs = future::join_all(tasks).await;
22121        if editor
22122            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22123            .unwrap_or(false)
22124        {
22125            return;
22126        }
22127
22128        buffer
22129            .update(cx, |buffer, cx| {
22130                for diff in diffs.into_iter().flatten() {
22131                    buffer.add_diff(diff, cx);
22132                }
22133            })
22134            .ok();
22135    })
22136}
22137
22138fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22139    let tab_size = tab_size.get() as usize;
22140    let mut width = offset;
22141
22142    for ch in text.chars() {
22143        width += if ch == '\t' {
22144            tab_size - (width % tab_size)
22145        } else {
22146            1
22147        };
22148    }
22149
22150    width - offset
22151}
22152
22153#[cfg(test)]
22154mod tests {
22155    use super::*;
22156
22157    #[test]
22158    fn test_string_size_with_expanded_tabs() {
22159        let nz = |val| NonZeroU32::new(val).unwrap();
22160        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22161        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22162        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22163        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22164        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22165        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22166        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22167        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22168    }
22169}
22170
22171/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22172struct WordBreakingTokenizer<'a> {
22173    input: &'a str,
22174}
22175
22176impl<'a> WordBreakingTokenizer<'a> {
22177    fn new(input: &'a str) -> Self {
22178        Self { input }
22179    }
22180}
22181
22182fn is_char_ideographic(ch: char) -> bool {
22183    use unicode_script::Script::*;
22184    use unicode_script::UnicodeScript;
22185    matches!(ch.script(), Han | Tangut | Yi)
22186}
22187
22188fn is_grapheme_ideographic(text: &str) -> bool {
22189    text.chars().any(is_char_ideographic)
22190}
22191
22192fn is_grapheme_whitespace(text: &str) -> bool {
22193    text.chars().any(|x| x.is_whitespace())
22194}
22195
22196fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22197    text.chars()
22198        .next()
22199        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22200}
22201
22202#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22203enum WordBreakToken<'a> {
22204    Word { token: &'a str, grapheme_len: usize },
22205    InlineWhitespace { token: &'a str, grapheme_len: usize },
22206    Newline,
22207}
22208
22209impl<'a> Iterator for WordBreakingTokenizer<'a> {
22210    /// Yields a span, the count of graphemes in the token, and whether it was
22211    /// whitespace. Note that it also breaks at word boundaries.
22212    type Item = WordBreakToken<'a>;
22213
22214    fn next(&mut self) -> Option<Self::Item> {
22215        use unicode_segmentation::UnicodeSegmentation;
22216        if self.input.is_empty() {
22217            return None;
22218        }
22219
22220        let mut iter = self.input.graphemes(true).peekable();
22221        let mut offset = 0;
22222        let mut grapheme_len = 0;
22223        if let Some(first_grapheme) = iter.next() {
22224            let is_newline = first_grapheme == "\n";
22225            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22226            offset += first_grapheme.len();
22227            grapheme_len += 1;
22228            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22229                if let Some(grapheme) = iter.peek().copied()
22230                    && should_stay_with_preceding_ideograph(grapheme)
22231                {
22232                    offset += grapheme.len();
22233                    grapheme_len += 1;
22234                }
22235            } else {
22236                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22237                let mut next_word_bound = words.peek().copied();
22238                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22239                    next_word_bound = words.next();
22240                }
22241                while let Some(grapheme) = iter.peek().copied() {
22242                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22243                        break;
22244                    };
22245                    if is_grapheme_whitespace(grapheme) != is_whitespace
22246                        || (grapheme == "\n") != is_newline
22247                    {
22248                        break;
22249                    };
22250                    offset += grapheme.len();
22251                    grapheme_len += 1;
22252                    iter.next();
22253                }
22254            }
22255            let token = &self.input[..offset];
22256            self.input = &self.input[offset..];
22257            if token == "\n" {
22258                Some(WordBreakToken::Newline)
22259            } else if is_whitespace {
22260                Some(WordBreakToken::InlineWhitespace {
22261                    token,
22262                    grapheme_len,
22263                })
22264            } else {
22265                Some(WordBreakToken::Word {
22266                    token,
22267                    grapheme_len,
22268                })
22269            }
22270        } else {
22271            None
22272        }
22273    }
22274}
22275
22276#[test]
22277fn test_word_breaking_tokenizer() {
22278    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22279        ("", &[]),
22280        ("  ", &[whitespace("  ", 2)]),
22281        ("Ʒ", &[word("Ʒ", 1)]),
22282        ("Ǽ", &[word("Ǽ", 1)]),
22283        ("", &[word("", 1)]),
22284        ("⋑⋑", &[word("⋑⋑", 2)]),
22285        (
22286            "原理,进而",
22287            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22288        ),
22289        (
22290            "hello world",
22291            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22292        ),
22293        (
22294            "hello, world",
22295            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22296        ),
22297        (
22298            "  hello world",
22299            &[
22300                whitespace("  ", 2),
22301                word("hello", 5),
22302                whitespace(" ", 1),
22303                word("world", 5),
22304            ],
22305        ),
22306        (
22307            "这是什么 \n 钢笔",
22308            &[
22309                word("", 1),
22310                word("", 1),
22311                word("", 1),
22312                word("", 1),
22313                whitespace(" ", 1),
22314                newline(),
22315                whitespace(" ", 1),
22316                word("", 1),
22317                word("", 1),
22318            ],
22319        ),
22320        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22321    ];
22322
22323    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22324        WordBreakToken::Word {
22325            token,
22326            grapheme_len,
22327        }
22328    }
22329
22330    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22331        WordBreakToken::InlineWhitespace {
22332            token,
22333            grapheme_len,
22334        }
22335    }
22336
22337    fn newline() -> WordBreakToken<'static> {
22338        WordBreakToken::Newline
22339    }
22340
22341    for (input, result) in tests {
22342        assert_eq!(
22343            WordBreakingTokenizer::new(input)
22344                .collect::<Vec<_>>()
22345                .as_slice(),
22346            *result,
22347        );
22348    }
22349}
22350
22351fn wrap_with_prefix(
22352    first_line_prefix: String,
22353    subsequent_lines_prefix: String,
22354    unwrapped_text: String,
22355    wrap_column: usize,
22356    tab_size: NonZeroU32,
22357    preserve_existing_whitespace: bool,
22358) -> String {
22359    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22360    let subsequent_lines_prefix_len =
22361        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22362    let mut wrapped_text = String::new();
22363    let mut current_line = first_line_prefix;
22364    let mut is_first_line = true;
22365
22366    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22367    let mut current_line_len = first_line_prefix_len;
22368    let mut in_whitespace = false;
22369    for token in tokenizer {
22370        let have_preceding_whitespace = in_whitespace;
22371        match token {
22372            WordBreakToken::Word {
22373                token,
22374                grapheme_len,
22375            } => {
22376                in_whitespace = false;
22377                let current_prefix_len = if is_first_line {
22378                    first_line_prefix_len
22379                } else {
22380                    subsequent_lines_prefix_len
22381                };
22382                if current_line_len + grapheme_len > wrap_column
22383                    && current_line_len != current_prefix_len
22384                {
22385                    wrapped_text.push_str(current_line.trim_end());
22386                    wrapped_text.push('\n');
22387                    is_first_line = false;
22388                    current_line = subsequent_lines_prefix.clone();
22389                    current_line_len = subsequent_lines_prefix_len;
22390                }
22391                current_line.push_str(token);
22392                current_line_len += grapheme_len;
22393            }
22394            WordBreakToken::InlineWhitespace {
22395                mut token,
22396                mut grapheme_len,
22397            } => {
22398                in_whitespace = true;
22399                if have_preceding_whitespace && !preserve_existing_whitespace {
22400                    continue;
22401                }
22402                if !preserve_existing_whitespace {
22403                    token = " ";
22404                    grapheme_len = 1;
22405                }
22406                let current_prefix_len = if is_first_line {
22407                    first_line_prefix_len
22408                } else {
22409                    subsequent_lines_prefix_len
22410                };
22411                if current_line_len + grapheme_len > wrap_column {
22412                    wrapped_text.push_str(current_line.trim_end());
22413                    wrapped_text.push('\n');
22414                    is_first_line = false;
22415                    current_line = subsequent_lines_prefix.clone();
22416                    current_line_len = subsequent_lines_prefix_len;
22417                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22418                    current_line.push_str(token);
22419                    current_line_len += grapheme_len;
22420                }
22421            }
22422            WordBreakToken::Newline => {
22423                in_whitespace = true;
22424                let current_prefix_len = if is_first_line {
22425                    first_line_prefix_len
22426                } else {
22427                    subsequent_lines_prefix_len
22428                };
22429                if preserve_existing_whitespace {
22430                    wrapped_text.push_str(current_line.trim_end());
22431                    wrapped_text.push('\n');
22432                    is_first_line = false;
22433                    current_line = subsequent_lines_prefix.clone();
22434                    current_line_len = subsequent_lines_prefix_len;
22435                } else if have_preceding_whitespace {
22436                    continue;
22437                } else if current_line_len + 1 > wrap_column
22438                    && current_line_len != current_prefix_len
22439                {
22440                    wrapped_text.push_str(current_line.trim_end());
22441                    wrapped_text.push('\n');
22442                    is_first_line = false;
22443                    current_line = subsequent_lines_prefix.clone();
22444                    current_line_len = subsequent_lines_prefix_len;
22445                } else if current_line_len != current_prefix_len {
22446                    current_line.push(' ');
22447                    current_line_len += 1;
22448                }
22449            }
22450        }
22451    }
22452
22453    if !current_line.is_empty() {
22454        wrapped_text.push_str(&current_line);
22455    }
22456    wrapped_text
22457}
22458
22459#[test]
22460fn test_wrap_with_prefix() {
22461    assert_eq!(
22462        wrap_with_prefix(
22463            "# ".to_string(),
22464            "# ".to_string(),
22465            "abcdefg".to_string(),
22466            4,
22467            NonZeroU32::new(4).unwrap(),
22468            false,
22469        ),
22470        "# abcdefg"
22471    );
22472    assert_eq!(
22473        wrap_with_prefix(
22474            "".to_string(),
22475            "".to_string(),
22476            "\thello world".to_string(),
22477            8,
22478            NonZeroU32::new(4).unwrap(),
22479            false,
22480        ),
22481        "hello\nworld"
22482    );
22483    assert_eq!(
22484        wrap_with_prefix(
22485            "// ".to_string(),
22486            "// ".to_string(),
22487            "xx \nyy zz aa bb cc".to_string(),
22488            12,
22489            NonZeroU32::new(4).unwrap(),
22490            false,
22491        ),
22492        "// xx yy zz\n// aa bb cc"
22493    );
22494    assert_eq!(
22495        wrap_with_prefix(
22496            String::new(),
22497            String::new(),
22498            "这是什么 \n 钢笔".to_string(),
22499            3,
22500            NonZeroU32::new(4).unwrap(),
22501            false,
22502        ),
22503        "这是什\n么 钢\n"
22504    );
22505}
22506
22507pub trait CollaborationHub {
22508    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22509    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22510    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22511}
22512
22513impl CollaborationHub for Entity<Project> {
22514    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22515        self.read(cx).collaborators()
22516    }
22517
22518    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22519        self.read(cx).user_store().read(cx).participant_indices()
22520    }
22521
22522    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22523        let this = self.read(cx);
22524        let user_ids = this.collaborators().values().map(|c| c.user_id);
22525        this.user_store().read(cx).participant_names(user_ids, cx)
22526    }
22527}
22528
22529pub trait SemanticsProvider {
22530    fn hover(
22531        &self,
22532        buffer: &Entity<Buffer>,
22533        position: text::Anchor,
22534        cx: &mut App,
22535    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22536
22537    fn inline_values(
22538        &self,
22539        buffer_handle: Entity<Buffer>,
22540        range: Range<text::Anchor>,
22541        cx: &mut App,
22542    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22543
22544    fn inlay_hints(
22545        &self,
22546        buffer_handle: Entity<Buffer>,
22547        range: Range<text::Anchor>,
22548        cx: &mut App,
22549    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22550
22551    fn resolve_inlay_hint(
22552        &self,
22553        hint: InlayHint,
22554        buffer_handle: Entity<Buffer>,
22555        server_id: LanguageServerId,
22556        cx: &mut App,
22557    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22558
22559    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22560
22561    fn document_highlights(
22562        &self,
22563        buffer: &Entity<Buffer>,
22564        position: text::Anchor,
22565        cx: &mut App,
22566    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22567
22568    fn definitions(
22569        &self,
22570        buffer: &Entity<Buffer>,
22571        position: text::Anchor,
22572        kind: GotoDefinitionKind,
22573        cx: &mut App,
22574    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22575
22576    fn range_for_rename(
22577        &self,
22578        buffer: &Entity<Buffer>,
22579        position: text::Anchor,
22580        cx: &mut App,
22581    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22582
22583    fn perform_rename(
22584        &self,
22585        buffer: &Entity<Buffer>,
22586        position: text::Anchor,
22587        new_name: String,
22588        cx: &mut App,
22589    ) -> Option<Task<Result<ProjectTransaction>>>;
22590}
22591
22592pub trait CompletionProvider {
22593    fn completions(
22594        &self,
22595        excerpt_id: ExcerptId,
22596        buffer: &Entity<Buffer>,
22597        buffer_position: text::Anchor,
22598        trigger: CompletionContext,
22599        window: &mut Window,
22600        cx: &mut Context<Editor>,
22601    ) -> Task<Result<Vec<CompletionResponse>>>;
22602
22603    fn resolve_completions(
22604        &self,
22605        _buffer: Entity<Buffer>,
22606        _completion_indices: Vec<usize>,
22607        _completions: Rc<RefCell<Box<[Completion]>>>,
22608        _cx: &mut Context<Editor>,
22609    ) -> Task<Result<bool>> {
22610        Task::ready(Ok(false))
22611    }
22612
22613    fn apply_additional_edits_for_completion(
22614        &self,
22615        _buffer: Entity<Buffer>,
22616        _completions: Rc<RefCell<Box<[Completion]>>>,
22617        _completion_index: usize,
22618        _push_to_history: bool,
22619        _cx: &mut Context<Editor>,
22620    ) -> Task<Result<Option<language::Transaction>>> {
22621        Task::ready(Ok(None))
22622    }
22623
22624    fn is_completion_trigger(
22625        &self,
22626        buffer: &Entity<Buffer>,
22627        position: language::Anchor,
22628        text: &str,
22629        trigger_in_words: bool,
22630        menu_is_open: bool,
22631        cx: &mut Context<Editor>,
22632    ) -> bool;
22633
22634    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22635
22636    fn sort_completions(&self) -> bool {
22637        true
22638    }
22639
22640    fn filter_completions(&self) -> bool {
22641        true
22642    }
22643}
22644
22645pub trait CodeActionProvider {
22646    fn id(&self) -> Arc<str>;
22647
22648    fn code_actions(
22649        &self,
22650        buffer: &Entity<Buffer>,
22651        range: Range<text::Anchor>,
22652        window: &mut Window,
22653        cx: &mut App,
22654    ) -> Task<Result<Vec<CodeAction>>>;
22655
22656    fn apply_code_action(
22657        &self,
22658        buffer_handle: Entity<Buffer>,
22659        action: CodeAction,
22660        excerpt_id: ExcerptId,
22661        push_to_history: bool,
22662        window: &mut Window,
22663        cx: &mut App,
22664    ) -> Task<Result<ProjectTransaction>>;
22665}
22666
22667impl CodeActionProvider for Entity<Project> {
22668    fn id(&self) -> Arc<str> {
22669        "project".into()
22670    }
22671
22672    fn code_actions(
22673        &self,
22674        buffer: &Entity<Buffer>,
22675        range: Range<text::Anchor>,
22676        _window: &mut Window,
22677        cx: &mut App,
22678    ) -> Task<Result<Vec<CodeAction>>> {
22679        self.update(cx, |project, cx| {
22680            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22681            let code_actions = project.code_actions(buffer, range, None, cx);
22682            cx.background_spawn(async move {
22683                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22684                Ok(code_lens_actions
22685                    .context("code lens fetch")?
22686                    .into_iter()
22687                    .flatten()
22688                    .chain(
22689                        code_actions
22690                            .context("code action fetch")?
22691                            .into_iter()
22692                            .flatten(),
22693                    )
22694                    .collect())
22695            })
22696        })
22697    }
22698
22699    fn apply_code_action(
22700        &self,
22701        buffer_handle: Entity<Buffer>,
22702        action: CodeAction,
22703        _excerpt_id: ExcerptId,
22704        push_to_history: bool,
22705        _window: &mut Window,
22706        cx: &mut App,
22707    ) -> Task<Result<ProjectTransaction>> {
22708        self.update(cx, |project, cx| {
22709            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22710        })
22711    }
22712}
22713
22714fn snippet_completions(
22715    project: &Project,
22716    buffer: &Entity<Buffer>,
22717    buffer_position: text::Anchor,
22718    cx: &mut App,
22719) -> Task<Result<CompletionResponse>> {
22720    let languages = buffer.read(cx).languages_at(buffer_position);
22721    let snippet_store = project.snippets().read(cx);
22722
22723    let scopes: Vec<_> = languages
22724        .iter()
22725        .filter_map(|language| {
22726            let language_name = language.lsp_id();
22727            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22728
22729            if snippets.is_empty() {
22730                None
22731            } else {
22732                Some((language.default_scope(), snippets))
22733            }
22734        })
22735        .collect();
22736
22737    if scopes.is_empty() {
22738        return Task::ready(Ok(CompletionResponse {
22739            completions: vec![],
22740            display_options: CompletionDisplayOptions::default(),
22741            is_incomplete: false,
22742        }));
22743    }
22744
22745    let snapshot = buffer.read(cx).text_snapshot();
22746    let chars: String = snapshot
22747        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22748        .collect();
22749    let executor = cx.background_executor().clone();
22750
22751    cx.background_spawn(async move {
22752        let mut is_incomplete = false;
22753        let mut completions: Vec<Completion> = Vec::new();
22754        for (scope, snippets) in scopes.into_iter() {
22755            let classifier =
22756                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22757            let mut last_word = chars
22758                .chars()
22759                .take_while(|c| classifier.is_word(*c))
22760                .collect::<String>();
22761            last_word = last_word.chars().rev().collect();
22762
22763            if last_word.is_empty() {
22764                return Ok(CompletionResponse {
22765                    completions: vec![],
22766                    display_options: CompletionDisplayOptions::default(),
22767                    is_incomplete: true,
22768                });
22769            }
22770
22771            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22772            let to_lsp = |point: &text::Anchor| {
22773                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22774                point_to_lsp(end)
22775            };
22776            let lsp_end = to_lsp(&buffer_position);
22777
22778            let candidates = snippets
22779                .iter()
22780                .enumerate()
22781                .flat_map(|(ix, snippet)| {
22782                    snippet
22783                        .prefix
22784                        .iter()
22785                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22786                })
22787                .collect::<Vec<StringMatchCandidate>>();
22788
22789            const MAX_RESULTS: usize = 100;
22790            let mut matches = fuzzy::match_strings(
22791                &candidates,
22792                &last_word,
22793                last_word.chars().any(|c| c.is_uppercase()),
22794                true,
22795                MAX_RESULTS,
22796                &Default::default(),
22797                executor.clone(),
22798            )
22799            .await;
22800
22801            if matches.len() >= MAX_RESULTS {
22802                is_incomplete = true;
22803            }
22804
22805            // Remove all candidates where the query's start does not match the start of any word in the candidate
22806            if let Some(query_start) = last_word.chars().next() {
22807                matches.retain(|string_match| {
22808                    split_words(&string_match.string).any(|word| {
22809                        // Check that the first codepoint of the word as lowercase matches the first
22810                        // codepoint of the query as lowercase
22811                        word.chars()
22812                            .flat_map(|codepoint| codepoint.to_lowercase())
22813                            .zip(query_start.to_lowercase())
22814                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22815                    })
22816                });
22817            }
22818
22819            let matched_strings = matches
22820                .into_iter()
22821                .map(|m| m.string)
22822                .collect::<HashSet<_>>();
22823
22824            completions.extend(snippets.iter().filter_map(|snippet| {
22825                let matching_prefix = snippet
22826                    .prefix
22827                    .iter()
22828                    .find(|prefix| matched_strings.contains(*prefix))?;
22829                let start = as_offset - last_word.len();
22830                let start = snapshot.anchor_before(start);
22831                let range = start..buffer_position;
22832                let lsp_start = to_lsp(&start);
22833                let lsp_range = lsp::Range {
22834                    start: lsp_start,
22835                    end: lsp_end,
22836                };
22837                Some(Completion {
22838                    replace_range: range,
22839                    new_text: snippet.body.clone(),
22840                    source: CompletionSource::Lsp {
22841                        insert_range: None,
22842                        server_id: LanguageServerId(usize::MAX),
22843                        resolved: true,
22844                        lsp_completion: Box::new(lsp::CompletionItem {
22845                            label: snippet.prefix.first().unwrap().clone(),
22846                            kind: Some(CompletionItemKind::SNIPPET),
22847                            label_details: snippet.description.as_ref().map(|description| {
22848                                lsp::CompletionItemLabelDetails {
22849                                    detail: Some(description.clone()),
22850                                    description: None,
22851                                }
22852                            }),
22853                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22854                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22855                                lsp::InsertReplaceEdit {
22856                                    new_text: snippet.body.clone(),
22857                                    insert: lsp_range,
22858                                    replace: lsp_range,
22859                                },
22860                            )),
22861                            filter_text: Some(snippet.body.clone()),
22862                            sort_text: Some(char::MAX.to_string()),
22863                            ..lsp::CompletionItem::default()
22864                        }),
22865                        lsp_defaults: None,
22866                    },
22867                    label: CodeLabel {
22868                        text: matching_prefix.clone(),
22869                        runs: Vec::new(),
22870                        filter_range: 0..matching_prefix.len(),
22871                    },
22872                    icon_path: None,
22873                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22874                        single_line: snippet.name.clone().into(),
22875                        plain_text: snippet
22876                            .description
22877                            .clone()
22878                            .map(|description| description.into()),
22879                    }),
22880                    insert_text_mode: None,
22881                    confirm: None,
22882                })
22883            }))
22884        }
22885
22886        Ok(CompletionResponse {
22887            completions,
22888            display_options: CompletionDisplayOptions::default(),
22889            is_incomplete,
22890        })
22891    })
22892}
22893
22894impl CompletionProvider for Entity<Project> {
22895    fn completions(
22896        &self,
22897        _excerpt_id: ExcerptId,
22898        buffer: &Entity<Buffer>,
22899        buffer_position: text::Anchor,
22900        options: CompletionContext,
22901        _window: &mut Window,
22902        cx: &mut Context<Editor>,
22903    ) -> Task<Result<Vec<CompletionResponse>>> {
22904        self.update(cx, |project, cx| {
22905            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22906            let project_completions = project.completions(buffer, buffer_position, options, cx);
22907            cx.background_spawn(async move {
22908                let mut responses = project_completions.await?;
22909                let snippets = snippets.await?;
22910                if !snippets.completions.is_empty() {
22911                    responses.push(snippets);
22912                }
22913                Ok(responses)
22914            })
22915        })
22916    }
22917
22918    fn resolve_completions(
22919        &self,
22920        buffer: Entity<Buffer>,
22921        completion_indices: Vec<usize>,
22922        completions: Rc<RefCell<Box<[Completion]>>>,
22923        cx: &mut Context<Editor>,
22924    ) -> Task<Result<bool>> {
22925        self.update(cx, |project, cx| {
22926            project.lsp_store().update(cx, |lsp_store, cx| {
22927                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22928            })
22929        })
22930    }
22931
22932    fn apply_additional_edits_for_completion(
22933        &self,
22934        buffer: Entity<Buffer>,
22935        completions: Rc<RefCell<Box<[Completion]>>>,
22936        completion_index: usize,
22937        push_to_history: bool,
22938        cx: &mut Context<Editor>,
22939    ) -> Task<Result<Option<language::Transaction>>> {
22940        self.update(cx, |project, cx| {
22941            project.lsp_store().update(cx, |lsp_store, cx| {
22942                lsp_store.apply_additional_edits_for_completion(
22943                    buffer,
22944                    completions,
22945                    completion_index,
22946                    push_to_history,
22947                    cx,
22948                )
22949            })
22950        })
22951    }
22952
22953    fn is_completion_trigger(
22954        &self,
22955        buffer: &Entity<Buffer>,
22956        position: language::Anchor,
22957        text: &str,
22958        trigger_in_words: bool,
22959        menu_is_open: bool,
22960        cx: &mut Context<Editor>,
22961    ) -> bool {
22962        let mut chars = text.chars();
22963        let char = if let Some(char) = chars.next() {
22964            char
22965        } else {
22966            return false;
22967        };
22968        if chars.next().is_some() {
22969            return false;
22970        }
22971
22972        let buffer = buffer.read(cx);
22973        let snapshot = buffer.snapshot();
22974        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22975            return false;
22976        }
22977        let classifier = snapshot
22978            .char_classifier_at(position)
22979            .scope_context(Some(CharScopeContext::Completion));
22980        if trigger_in_words && classifier.is_word(char) {
22981            return true;
22982        }
22983
22984        buffer.completion_triggers().contains(text)
22985    }
22986}
22987
22988impl SemanticsProvider for Entity<Project> {
22989    fn hover(
22990        &self,
22991        buffer: &Entity<Buffer>,
22992        position: text::Anchor,
22993        cx: &mut App,
22994    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22995        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22996    }
22997
22998    fn document_highlights(
22999        &self,
23000        buffer: &Entity<Buffer>,
23001        position: text::Anchor,
23002        cx: &mut App,
23003    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23004        Some(self.update(cx, |project, cx| {
23005            project.document_highlights(buffer, position, cx)
23006        }))
23007    }
23008
23009    fn definitions(
23010        &self,
23011        buffer: &Entity<Buffer>,
23012        position: text::Anchor,
23013        kind: GotoDefinitionKind,
23014        cx: &mut App,
23015    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23016        Some(self.update(cx, |project, cx| match kind {
23017            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23018            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23019            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23020            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23021        }))
23022    }
23023
23024    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23025        self.update(cx, |project, cx| {
23026            if project
23027                .active_debug_session(cx)
23028                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23029            {
23030                return true;
23031            }
23032
23033            buffer.update(cx, |buffer, cx| {
23034                project.any_language_server_supports_inlay_hints(buffer, cx)
23035            })
23036        })
23037    }
23038
23039    fn inline_values(
23040        &self,
23041        buffer_handle: Entity<Buffer>,
23042        range: Range<text::Anchor>,
23043        cx: &mut App,
23044    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23045        self.update(cx, |project, cx| {
23046            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23047
23048            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23049        })
23050    }
23051
23052    fn inlay_hints(
23053        &self,
23054        buffer_handle: Entity<Buffer>,
23055        range: Range<text::Anchor>,
23056        cx: &mut App,
23057    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23058        Some(self.update(cx, |project, cx| {
23059            project.inlay_hints(buffer_handle, range, cx)
23060        }))
23061    }
23062
23063    fn resolve_inlay_hint(
23064        &self,
23065        hint: InlayHint,
23066        buffer_handle: Entity<Buffer>,
23067        server_id: LanguageServerId,
23068        cx: &mut App,
23069    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23070        Some(self.update(cx, |project, cx| {
23071            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23072        }))
23073    }
23074
23075    fn range_for_rename(
23076        &self,
23077        buffer: &Entity<Buffer>,
23078        position: text::Anchor,
23079        cx: &mut App,
23080    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23081        Some(self.update(cx, |project, cx| {
23082            let buffer = buffer.clone();
23083            let task = project.prepare_rename(buffer.clone(), position, cx);
23084            cx.spawn(async move |_, cx| {
23085                Ok(match task.await? {
23086                    PrepareRenameResponse::Success(range) => Some(range),
23087                    PrepareRenameResponse::InvalidPosition => None,
23088                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23089                        // Fallback on using TreeSitter info to determine identifier range
23090                        buffer.read_with(cx, |buffer, _| {
23091                            let snapshot = buffer.snapshot();
23092                            let (range, kind) = snapshot.surrounding_word(position, None);
23093                            if kind != Some(CharKind::Word) {
23094                                return None;
23095                            }
23096                            Some(
23097                                snapshot.anchor_before(range.start)
23098                                    ..snapshot.anchor_after(range.end),
23099                            )
23100                        })?
23101                    }
23102                })
23103            })
23104        }))
23105    }
23106
23107    fn perform_rename(
23108        &self,
23109        buffer: &Entity<Buffer>,
23110        position: text::Anchor,
23111        new_name: String,
23112        cx: &mut App,
23113    ) -> Option<Task<Result<ProjectTransaction>>> {
23114        Some(self.update(cx, |project, cx| {
23115            project.perform_rename(buffer.clone(), position, new_name, cx)
23116        }))
23117    }
23118}
23119
23120fn inlay_hint_settings(
23121    location: Anchor,
23122    snapshot: &MultiBufferSnapshot,
23123    cx: &mut Context<Editor>,
23124) -> InlayHintSettings {
23125    let file = snapshot.file_at(location);
23126    let language = snapshot.language_at(location).map(|l| l.name());
23127    language_settings(language, file, cx).inlay_hints
23128}
23129
23130fn consume_contiguous_rows(
23131    contiguous_row_selections: &mut Vec<Selection<Point>>,
23132    selection: &Selection<Point>,
23133    display_map: &DisplaySnapshot,
23134    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23135) -> (MultiBufferRow, MultiBufferRow) {
23136    contiguous_row_selections.push(selection.clone());
23137    let start_row = starting_row(selection, display_map);
23138    let mut end_row = ending_row(selection, display_map);
23139
23140    while let Some(next_selection) = selections.peek() {
23141        if next_selection.start.row <= end_row.0 {
23142            end_row = ending_row(next_selection, display_map);
23143            contiguous_row_selections.push(selections.next().unwrap().clone());
23144        } else {
23145            break;
23146        }
23147    }
23148    (start_row, end_row)
23149}
23150
23151fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23152    if selection.start.column > 0 {
23153        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23154    } else {
23155        MultiBufferRow(selection.start.row)
23156    }
23157}
23158
23159fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23160    if next_selection.end.column > 0 || next_selection.is_empty() {
23161        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23162    } else {
23163        MultiBufferRow(next_selection.end.row)
23164    }
23165}
23166
23167impl EditorSnapshot {
23168    pub fn remote_selections_in_range<'a>(
23169        &'a self,
23170        range: &'a Range<Anchor>,
23171        collaboration_hub: &dyn CollaborationHub,
23172        cx: &'a App,
23173    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23174        let participant_names = collaboration_hub.user_names(cx);
23175        let participant_indices = collaboration_hub.user_participant_indices(cx);
23176        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23177        let collaborators_by_replica_id = collaborators_by_peer_id
23178            .values()
23179            .map(|collaborator| (collaborator.replica_id, collaborator))
23180            .collect::<HashMap<_, _>>();
23181        self.buffer_snapshot
23182            .selections_in_range(range, false)
23183            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23184                if replica_id == AGENT_REPLICA_ID {
23185                    Some(RemoteSelection {
23186                        replica_id,
23187                        selection,
23188                        cursor_shape,
23189                        line_mode,
23190                        collaborator_id: CollaboratorId::Agent,
23191                        user_name: Some("Agent".into()),
23192                        color: cx.theme().players().agent(),
23193                    })
23194                } else {
23195                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23196                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23197                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23198                    Some(RemoteSelection {
23199                        replica_id,
23200                        selection,
23201                        cursor_shape,
23202                        line_mode,
23203                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23204                        user_name,
23205                        color: if let Some(index) = participant_index {
23206                            cx.theme().players().color_for_participant(index.0)
23207                        } else {
23208                            cx.theme().players().absent()
23209                        },
23210                    })
23211                }
23212            })
23213    }
23214
23215    pub fn hunks_for_ranges(
23216        &self,
23217        ranges: impl IntoIterator<Item = Range<Point>>,
23218    ) -> Vec<MultiBufferDiffHunk> {
23219        let mut hunks = Vec::new();
23220        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23221            HashMap::default();
23222        for query_range in ranges {
23223            let query_rows =
23224                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23225            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23226                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23227            ) {
23228                // Include deleted hunks that are adjacent to the query range, because
23229                // otherwise they would be missed.
23230                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23231                if hunk.status().is_deleted() {
23232                    intersects_range |= hunk.row_range.start == query_rows.end;
23233                    intersects_range |= hunk.row_range.end == query_rows.start;
23234                }
23235                if intersects_range {
23236                    if !processed_buffer_rows
23237                        .entry(hunk.buffer_id)
23238                        .or_default()
23239                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23240                    {
23241                        continue;
23242                    }
23243                    hunks.push(hunk);
23244                }
23245            }
23246        }
23247
23248        hunks
23249    }
23250
23251    fn display_diff_hunks_for_rows<'a>(
23252        &'a self,
23253        display_rows: Range<DisplayRow>,
23254        folded_buffers: &'a HashSet<BufferId>,
23255    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23256        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23257        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23258
23259        self.buffer_snapshot
23260            .diff_hunks_in_range(buffer_start..buffer_end)
23261            .filter_map(|hunk| {
23262                if folded_buffers.contains(&hunk.buffer_id) {
23263                    return None;
23264                }
23265
23266                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23267                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23268
23269                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23270                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23271
23272                let display_hunk = if hunk_display_start.column() != 0 {
23273                    DisplayDiffHunk::Folded {
23274                        display_row: hunk_display_start.row(),
23275                    }
23276                } else {
23277                    let mut end_row = hunk_display_end.row();
23278                    if hunk_display_end.column() > 0 {
23279                        end_row.0 += 1;
23280                    }
23281                    let is_created_file = hunk.is_created_file();
23282                    DisplayDiffHunk::Unfolded {
23283                        status: hunk.status(),
23284                        diff_base_byte_range: hunk.diff_base_byte_range,
23285                        display_row_range: hunk_display_start.row()..end_row,
23286                        multi_buffer_range: Anchor::range_in_buffer(
23287                            hunk.excerpt_id,
23288                            hunk.buffer_id,
23289                            hunk.buffer_range,
23290                        ),
23291                        is_created_file,
23292                    }
23293                };
23294
23295                Some(display_hunk)
23296            })
23297    }
23298
23299    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23300        self.display_snapshot.buffer_snapshot.language_at(position)
23301    }
23302
23303    pub fn is_focused(&self) -> bool {
23304        self.is_focused
23305    }
23306
23307    pub fn placeholder_text(&self) -> Option<String> {
23308        self.placeholder_display_snapshot
23309            .as_ref()
23310            .map(|display_map| display_map.text())
23311    }
23312
23313    pub fn scroll_position(&self) -> gpui::Point<f32> {
23314        self.scroll_anchor.scroll_position(&self.display_snapshot)
23315    }
23316
23317    fn gutter_dimensions(
23318        &self,
23319        font_id: FontId,
23320        font_size: Pixels,
23321        max_line_number_width: Pixels,
23322        cx: &App,
23323    ) -> Option<GutterDimensions> {
23324        if !self.show_gutter {
23325            return None;
23326        }
23327
23328        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23329        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23330
23331        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23332            matches!(
23333                ProjectSettings::get_global(cx).git.git_gutter,
23334                GitGutterSetting::TrackedFiles
23335            )
23336        });
23337        let gutter_settings = EditorSettings::get_global(cx).gutter;
23338        let show_line_numbers = self
23339            .show_line_numbers
23340            .unwrap_or(gutter_settings.line_numbers);
23341        let line_gutter_width = if show_line_numbers {
23342            // Avoid flicker-like gutter resizes when the line number gains another digit by
23343            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23344            let min_width_for_number_on_gutter =
23345                ch_advance * gutter_settings.min_line_number_digits as f32;
23346            max_line_number_width.max(min_width_for_number_on_gutter)
23347        } else {
23348            0.0.into()
23349        };
23350
23351        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23352        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23353
23354        let git_blame_entries_width =
23355            self.git_blame_gutter_max_author_length
23356                .map(|max_author_length| {
23357                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23358                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23359
23360                    /// The number of characters to dedicate to gaps and margins.
23361                    const SPACING_WIDTH: usize = 4;
23362
23363                    let max_char_count = max_author_length.min(renderer.max_author_length())
23364                        + ::git::SHORT_SHA_LENGTH
23365                        + MAX_RELATIVE_TIMESTAMP.len()
23366                        + SPACING_WIDTH;
23367
23368                    ch_advance * max_char_count
23369                });
23370
23371        let is_singleton = self.buffer_snapshot.is_singleton();
23372
23373        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23374        left_padding += if !is_singleton {
23375            ch_width * 4.0
23376        } else if show_runnables || show_breakpoints {
23377            ch_width * 3.0
23378        } else if show_git_gutter && show_line_numbers {
23379            ch_width * 2.0
23380        } else if show_git_gutter || show_line_numbers {
23381            ch_width
23382        } else {
23383            px(0.)
23384        };
23385
23386        let shows_folds = is_singleton && gutter_settings.folds;
23387
23388        let right_padding = if shows_folds && show_line_numbers {
23389            ch_width * 4.0
23390        } else if shows_folds || (!is_singleton && show_line_numbers) {
23391            ch_width * 3.0
23392        } else if show_line_numbers {
23393            ch_width
23394        } else {
23395            px(0.)
23396        };
23397
23398        Some(GutterDimensions {
23399            left_padding,
23400            right_padding,
23401            width: line_gutter_width + left_padding + right_padding,
23402            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23403            git_blame_entries_width,
23404        })
23405    }
23406
23407    pub fn render_crease_toggle(
23408        &self,
23409        buffer_row: MultiBufferRow,
23410        row_contains_cursor: bool,
23411        editor: Entity<Editor>,
23412        window: &mut Window,
23413        cx: &mut App,
23414    ) -> Option<AnyElement> {
23415        let folded = self.is_line_folded(buffer_row);
23416        let mut is_foldable = false;
23417
23418        if let Some(crease) = self
23419            .crease_snapshot
23420            .query_row(buffer_row, &self.buffer_snapshot)
23421        {
23422            is_foldable = true;
23423            match crease {
23424                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23425                    if let Some(render_toggle) = render_toggle {
23426                        let toggle_callback =
23427                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23428                                if folded {
23429                                    editor.update(cx, |editor, cx| {
23430                                        editor.fold_at(buffer_row, window, cx)
23431                                    });
23432                                } else {
23433                                    editor.update(cx, |editor, cx| {
23434                                        editor.unfold_at(buffer_row, window, cx)
23435                                    });
23436                                }
23437                            });
23438                        return Some((render_toggle)(
23439                            buffer_row,
23440                            folded,
23441                            toggle_callback,
23442                            window,
23443                            cx,
23444                        ));
23445                    }
23446                }
23447            }
23448        }
23449
23450        is_foldable |= self.starts_indent(buffer_row);
23451
23452        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23453            Some(
23454                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23455                    .toggle_state(folded)
23456                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23457                        if folded {
23458                            this.unfold_at(buffer_row, window, cx);
23459                        } else {
23460                            this.fold_at(buffer_row, window, cx);
23461                        }
23462                    }))
23463                    .into_any_element(),
23464            )
23465        } else {
23466            None
23467        }
23468    }
23469
23470    pub fn render_crease_trailer(
23471        &self,
23472        buffer_row: MultiBufferRow,
23473        window: &mut Window,
23474        cx: &mut App,
23475    ) -> Option<AnyElement> {
23476        let folded = self.is_line_folded(buffer_row);
23477        if let Crease::Inline { render_trailer, .. } = self
23478            .crease_snapshot
23479            .query_row(buffer_row, &self.buffer_snapshot)?
23480        {
23481            let render_trailer = render_trailer.as_ref()?;
23482            Some(render_trailer(buffer_row, folded, window, cx))
23483        } else {
23484            None
23485        }
23486    }
23487}
23488
23489impl Deref for EditorSnapshot {
23490    type Target = DisplaySnapshot;
23491
23492    fn deref(&self) -> &Self::Target {
23493        &self.display_snapshot
23494    }
23495}
23496
23497#[derive(Clone, Debug, PartialEq, Eq)]
23498pub enum EditorEvent {
23499    InputIgnored {
23500        text: Arc<str>,
23501    },
23502    InputHandled {
23503        utf16_range_to_replace: Option<Range<isize>>,
23504        text: Arc<str>,
23505    },
23506    ExcerptsAdded {
23507        buffer: Entity<Buffer>,
23508        predecessor: ExcerptId,
23509        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23510    },
23511    ExcerptsRemoved {
23512        ids: Vec<ExcerptId>,
23513        removed_buffer_ids: Vec<BufferId>,
23514    },
23515    BufferFoldToggled {
23516        ids: Vec<ExcerptId>,
23517        folded: bool,
23518    },
23519    ExcerptsEdited {
23520        ids: Vec<ExcerptId>,
23521    },
23522    ExcerptsExpanded {
23523        ids: Vec<ExcerptId>,
23524    },
23525    BufferEdited,
23526    Edited {
23527        transaction_id: clock::Lamport,
23528    },
23529    Reparsed(BufferId),
23530    Focused,
23531    FocusedIn,
23532    Blurred,
23533    DirtyChanged,
23534    Saved,
23535    TitleChanged,
23536    SelectionsChanged {
23537        local: bool,
23538    },
23539    ScrollPositionChanged {
23540        local: bool,
23541        autoscroll: bool,
23542    },
23543    TransactionUndone {
23544        transaction_id: clock::Lamport,
23545    },
23546    TransactionBegun {
23547        transaction_id: clock::Lamport,
23548    },
23549    CursorShapeChanged,
23550    BreadcrumbsChanged,
23551    PushedToNavHistory {
23552        anchor: Anchor,
23553        is_deactivate: bool,
23554    },
23555}
23556
23557impl EventEmitter<EditorEvent> for Editor {}
23558
23559impl Focusable for Editor {
23560    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23561        self.focus_handle.clone()
23562    }
23563}
23564
23565impl Render for Editor {
23566    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23567        let settings = ThemeSettings::get_global(cx);
23568
23569        let mut text_style = match self.mode {
23570            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23571                color: cx.theme().colors().editor_foreground,
23572                font_family: settings.ui_font.family.clone(),
23573                font_features: settings.ui_font.features.clone(),
23574                font_fallbacks: settings.ui_font.fallbacks.clone(),
23575                font_size: rems(0.875).into(),
23576                font_weight: settings.ui_font.weight,
23577                line_height: relative(settings.buffer_line_height.value()),
23578                ..Default::default()
23579            },
23580            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23581                color: cx.theme().colors().editor_foreground,
23582                font_family: settings.buffer_font.family.clone(),
23583                font_features: settings.buffer_font.features.clone(),
23584                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23585                font_size: settings.buffer_font_size(cx).into(),
23586                font_weight: settings.buffer_font.weight,
23587                line_height: relative(settings.buffer_line_height.value()),
23588                ..Default::default()
23589            },
23590        };
23591        if let Some(text_style_refinement) = &self.text_style_refinement {
23592            text_style.refine(text_style_refinement)
23593        }
23594
23595        let background = match self.mode {
23596            EditorMode::SingleLine => cx.theme().system().transparent,
23597            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23598            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23599            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23600        };
23601
23602        EditorElement::new(
23603            &cx.entity(),
23604            EditorStyle {
23605                background,
23606                border: cx.theme().colors().border,
23607                local_player: cx.theme().players().local(),
23608                text: text_style,
23609                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23610                syntax: cx.theme().syntax().clone(),
23611                status: cx.theme().status().clone(),
23612                inlay_hints_style: make_inlay_hints_style(cx),
23613                edit_prediction_styles: make_suggestion_styles(cx),
23614                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23615                show_underlines: self.diagnostics_enabled(),
23616            },
23617        )
23618    }
23619}
23620
23621impl EntityInputHandler for Editor {
23622    fn text_for_range(
23623        &mut self,
23624        range_utf16: Range<usize>,
23625        adjusted_range: &mut Option<Range<usize>>,
23626        _: &mut Window,
23627        cx: &mut Context<Self>,
23628    ) -> Option<String> {
23629        let snapshot = self.buffer.read(cx).read(cx);
23630        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23631        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23632        if (start.0..end.0) != range_utf16 {
23633            adjusted_range.replace(start.0..end.0);
23634        }
23635        Some(snapshot.text_for_range(start..end).collect())
23636    }
23637
23638    fn selected_text_range(
23639        &mut self,
23640        ignore_disabled_input: bool,
23641        _: &mut Window,
23642        cx: &mut Context<Self>,
23643    ) -> Option<UTF16Selection> {
23644        // Prevent the IME menu from appearing when holding down an alphabetic key
23645        // while input is disabled.
23646        if !ignore_disabled_input && !self.input_enabled {
23647            return None;
23648        }
23649
23650        let selection = self.selections.newest::<OffsetUtf16>(cx);
23651        let range = selection.range();
23652
23653        Some(UTF16Selection {
23654            range: range.start.0..range.end.0,
23655            reversed: selection.reversed,
23656        })
23657    }
23658
23659    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23660        let snapshot = self.buffer.read(cx).read(cx);
23661        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23662        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23663    }
23664
23665    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23666        self.clear_highlights::<InputComposition>(cx);
23667        self.ime_transaction.take();
23668    }
23669
23670    fn replace_text_in_range(
23671        &mut self,
23672        range_utf16: Option<Range<usize>>,
23673        text: &str,
23674        window: &mut Window,
23675        cx: &mut Context<Self>,
23676    ) {
23677        if !self.input_enabled {
23678            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23679            return;
23680        }
23681
23682        self.transact(window, cx, |this, window, cx| {
23683            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23684                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23685                Some(this.selection_replacement_ranges(range_utf16, cx))
23686            } else {
23687                this.marked_text_ranges(cx)
23688            };
23689
23690            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23691                let newest_selection_id = this.selections.newest_anchor().id;
23692                this.selections
23693                    .all::<OffsetUtf16>(cx)
23694                    .iter()
23695                    .zip(ranges_to_replace.iter())
23696                    .find_map(|(selection, range)| {
23697                        if selection.id == newest_selection_id {
23698                            Some(
23699                                (range.start.0 as isize - selection.head().0 as isize)
23700                                    ..(range.end.0 as isize - selection.head().0 as isize),
23701                            )
23702                        } else {
23703                            None
23704                        }
23705                    })
23706            });
23707
23708            cx.emit(EditorEvent::InputHandled {
23709                utf16_range_to_replace: range_to_replace,
23710                text: text.into(),
23711            });
23712
23713            if let Some(new_selected_ranges) = new_selected_ranges {
23714                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23715                    selections.select_ranges(new_selected_ranges)
23716                });
23717                this.backspace(&Default::default(), window, cx);
23718            }
23719
23720            this.handle_input(text, window, cx);
23721        });
23722
23723        if let Some(transaction) = self.ime_transaction {
23724            self.buffer.update(cx, |buffer, cx| {
23725                buffer.group_until_transaction(transaction, cx);
23726            });
23727        }
23728
23729        self.unmark_text(window, cx);
23730    }
23731
23732    fn replace_and_mark_text_in_range(
23733        &mut self,
23734        range_utf16: Option<Range<usize>>,
23735        text: &str,
23736        new_selected_range_utf16: Option<Range<usize>>,
23737        window: &mut Window,
23738        cx: &mut Context<Self>,
23739    ) {
23740        if !self.input_enabled {
23741            return;
23742        }
23743
23744        let transaction = self.transact(window, cx, |this, window, cx| {
23745            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23746                let snapshot = this.buffer.read(cx).read(cx);
23747                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23748                    for marked_range in &mut marked_ranges {
23749                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23750                        marked_range.start.0 += relative_range_utf16.start;
23751                        marked_range.start =
23752                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23753                        marked_range.end =
23754                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23755                    }
23756                }
23757                Some(marked_ranges)
23758            } else if let Some(range_utf16) = range_utf16 {
23759                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23760                Some(this.selection_replacement_ranges(range_utf16, cx))
23761            } else {
23762                None
23763            };
23764
23765            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23766                let newest_selection_id = this.selections.newest_anchor().id;
23767                this.selections
23768                    .all::<OffsetUtf16>(cx)
23769                    .iter()
23770                    .zip(ranges_to_replace.iter())
23771                    .find_map(|(selection, range)| {
23772                        if selection.id == newest_selection_id {
23773                            Some(
23774                                (range.start.0 as isize - selection.head().0 as isize)
23775                                    ..(range.end.0 as isize - selection.head().0 as isize),
23776                            )
23777                        } else {
23778                            None
23779                        }
23780                    })
23781            });
23782
23783            cx.emit(EditorEvent::InputHandled {
23784                utf16_range_to_replace: range_to_replace,
23785                text: text.into(),
23786            });
23787
23788            if let Some(ranges) = ranges_to_replace {
23789                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23790                    s.select_ranges(ranges)
23791                });
23792            }
23793
23794            let marked_ranges = {
23795                let snapshot = this.buffer.read(cx).read(cx);
23796                this.selections
23797                    .disjoint_anchors_arc()
23798                    .iter()
23799                    .map(|selection| {
23800                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23801                    })
23802                    .collect::<Vec<_>>()
23803            };
23804
23805            if text.is_empty() {
23806                this.unmark_text(window, cx);
23807            } else {
23808                this.highlight_text::<InputComposition>(
23809                    marked_ranges.clone(),
23810                    HighlightStyle {
23811                        underline: Some(UnderlineStyle {
23812                            thickness: px(1.),
23813                            color: None,
23814                            wavy: false,
23815                        }),
23816                        ..Default::default()
23817                    },
23818                    cx,
23819                );
23820            }
23821
23822            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23823            let use_autoclose = this.use_autoclose;
23824            let use_auto_surround = this.use_auto_surround;
23825            this.set_use_autoclose(false);
23826            this.set_use_auto_surround(false);
23827            this.handle_input(text, window, cx);
23828            this.set_use_autoclose(use_autoclose);
23829            this.set_use_auto_surround(use_auto_surround);
23830
23831            if let Some(new_selected_range) = new_selected_range_utf16 {
23832                let snapshot = this.buffer.read(cx).read(cx);
23833                let new_selected_ranges = marked_ranges
23834                    .into_iter()
23835                    .map(|marked_range| {
23836                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23837                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23838                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23839                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23840                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23841                    })
23842                    .collect::<Vec<_>>();
23843
23844                drop(snapshot);
23845                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23846                    selections.select_ranges(new_selected_ranges)
23847                });
23848            }
23849        });
23850
23851        self.ime_transaction = self.ime_transaction.or(transaction);
23852        if let Some(transaction) = self.ime_transaction {
23853            self.buffer.update(cx, |buffer, cx| {
23854                buffer.group_until_transaction(transaction, cx);
23855            });
23856        }
23857
23858        if self.text_highlights::<InputComposition>(cx).is_none() {
23859            self.ime_transaction.take();
23860        }
23861    }
23862
23863    fn bounds_for_range(
23864        &mut self,
23865        range_utf16: Range<usize>,
23866        element_bounds: gpui::Bounds<Pixels>,
23867        window: &mut Window,
23868        cx: &mut Context<Self>,
23869    ) -> Option<gpui::Bounds<Pixels>> {
23870        let text_layout_details = self.text_layout_details(window);
23871        let CharacterDimensions {
23872            em_width,
23873            em_advance,
23874            line_height,
23875        } = self.character_dimensions(window);
23876
23877        let snapshot = self.snapshot(window, cx);
23878        let scroll_position = snapshot.scroll_position();
23879        let scroll_left = scroll_position.x * em_advance;
23880
23881        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23882        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23883            + self.gutter_dimensions.full_width();
23884        let y = line_height * (start.row().as_f32() - scroll_position.y);
23885
23886        Some(Bounds {
23887            origin: element_bounds.origin + point(x, y),
23888            size: size(em_width, line_height),
23889        })
23890    }
23891
23892    fn character_index_for_point(
23893        &mut self,
23894        point: gpui::Point<Pixels>,
23895        _window: &mut Window,
23896        _cx: &mut Context<Self>,
23897    ) -> Option<usize> {
23898        let position_map = self.last_position_map.as_ref()?;
23899        if !position_map.text_hitbox.contains(&point) {
23900            return None;
23901        }
23902        let display_point = position_map.point_for_position(point).previous_valid;
23903        let anchor = position_map
23904            .snapshot
23905            .display_point_to_anchor(display_point, Bias::Left);
23906        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23907        Some(utf16_offset.0)
23908    }
23909}
23910
23911trait SelectionExt {
23912    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23913    fn spanned_rows(
23914        &self,
23915        include_end_if_at_line_start: bool,
23916        map: &DisplaySnapshot,
23917    ) -> Range<MultiBufferRow>;
23918}
23919
23920impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23921    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23922        let start = self
23923            .start
23924            .to_point(&map.buffer_snapshot)
23925            .to_display_point(map);
23926        let end = self
23927            .end
23928            .to_point(&map.buffer_snapshot)
23929            .to_display_point(map);
23930        if self.reversed {
23931            end..start
23932        } else {
23933            start..end
23934        }
23935    }
23936
23937    fn spanned_rows(
23938        &self,
23939        include_end_if_at_line_start: bool,
23940        map: &DisplaySnapshot,
23941    ) -> Range<MultiBufferRow> {
23942        let start = self.start.to_point(&map.buffer_snapshot);
23943        let mut end = self.end.to_point(&map.buffer_snapshot);
23944        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23945            end.row -= 1;
23946        }
23947
23948        let buffer_start = map.prev_line_boundary(start).0;
23949        let buffer_end = map.next_line_boundary(end).0;
23950        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23951    }
23952}
23953
23954impl<T: InvalidationRegion> InvalidationStack<T> {
23955    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23956    where
23957        S: Clone + ToOffset,
23958    {
23959        while let Some(region) = self.last() {
23960            let all_selections_inside_invalidation_ranges =
23961                if selections.len() == region.ranges().len() {
23962                    selections
23963                        .iter()
23964                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23965                        .all(|(selection, invalidation_range)| {
23966                            let head = selection.head().to_offset(buffer);
23967                            invalidation_range.start <= head && invalidation_range.end >= head
23968                        })
23969                } else {
23970                    false
23971                };
23972
23973            if all_selections_inside_invalidation_ranges {
23974                break;
23975            } else {
23976                self.pop();
23977            }
23978        }
23979    }
23980}
23981
23982impl<T> Default for InvalidationStack<T> {
23983    fn default() -> Self {
23984        Self(Default::default())
23985    }
23986}
23987
23988impl<T> Deref for InvalidationStack<T> {
23989    type Target = Vec<T>;
23990
23991    fn deref(&self) -> &Self::Target {
23992        &self.0
23993    }
23994}
23995
23996impl<T> DerefMut for InvalidationStack<T> {
23997    fn deref_mut(&mut self) -> &mut Self::Target {
23998        &mut self.0
23999    }
24000}
24001
24002impl InvalidationRegion for SnippetState {
24003    fn ranges(&self) -> &[Range<Anchor>] {
24004        &self.ranges[self.active_index]
24005    }
24006}
24007
24008fn edit_prediction_edit_text(
24009    current_snapshot: &BufferSnapshot,
24010    edits: &[(Range<Anchor>, String)],
24011    edit_preview: &EditPreview,
24012    include_deletions: bool,
24013    cx: &App,
24014) -> HighlightedText {
24015    let edits = edits
24016        .iter()
24017        .map(|(anchor, text)| {
24018            (
24019                anchor.start.text_anchor..anchor.end.text_anchor,
24020                text.clone(),
24021            )
24022        })
24023        .collect::<Vec<_>>();
24024
24025    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24026}
24027
24028fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24029    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24030    // Just show the raw edit text with basic styling
24031    let mut text = String::new();
24032    let mut highlights = Vec::new();
24033
24034    let insertion_highlight_style = HighlightStyle {
24035        color: Some(cx.theme().colors().text),
24036        ..Default::default()
24037    };
24038
24039    for (_, edit_text) in edits {
24040        let start_offset = text.len();
24041        text.push_str(edit_text);
24042        let end_offset = text.len();
24043
24044        if start_offset < end_offset {
24045            highlights.push((start_offset..end_offset, insertion_highlight_style));
24046        }
24047    }
24048
24049    HighlightedText {
24050        text: text.into(),
24051        highlights,
24052    }
24053}
24054
24055pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24056    match severity {
24057        lsp::DiagnosticSeverity::ERROR => colors.error,
24058        lsp::DiagnosticSeverity::WARNING => colors.warning,
24059        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24060        lsp::DiagnosticSeverity::HINT => colors.info,
24061        _ => colors.ignored,
24062    }
24063}
24064
24065pub fn styled_runs_for_code_label<'a>(
24066    label: &'a CodeLabel,
24067    syntax_theme: &'a theme::SyntaxTheme,
24068) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24069    let fade_out = HighlightStyle {
24070        fade_out: Some(0.35),
24071        ..Default::default()
24072    };
24073
24074    let mut prev_end = label.filter_range.end;
24075    label
24076        .runs
24077        .iter()
24078        .enumerate()
24079        .flat_map(move |(ix, (range, highlight_id))| {
24080            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24081                style
24082            } else {
24083                return Default::default();
24084            };
24085            let muted_style = style.highlight(fade_out);
24086
24087            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24088            if range.start >= label.filter_range.end {
24089                if range.start > prev_end {
24090                    runs.push((prev_end..range.start, fade_out));
24091                }
24092                runs.push((range.clone(), muted_style));
24093            } else if range.end <= label.filter_range.end {
24094                runs.push((range.clone(), style));
24095            } else {
24096                runs.push((range.start..label.filter_range.end, style));
24097                runs.push((label.filter_range.end..range.end, muted_style));
24098            }
24099            prev_end = cmp::max(prev_end, range.end);
24100
24101            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24102                runs.push((prev_end..label.text.len(), fade_out));
24103            }
24104
24105            runs
24106        })
24107}
24108
24109pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24110    let mut prev_index = 0;
24111    let mut prev_codepoint: Option<char> = None;
24112    text.char_indices()
24113        .chain([(text.len(), '\0')])
24114        .filter_map(move |(index, codepoint)| {
24115            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24116            let is_boundary = index == text.len()
24117                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24118                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24119            if is_boundary {
24120                let chunk = &text[prev_index..index];
24121                prev_index = index;
24122                Some(chunk)
24123            } else {
24124                None
24125            }
24126        })
24127}
24128
24129pub trait RangeToAnchorExt: Sized {
24130    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24131
24132    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24133        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
24134        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24135    }
24136}
24137
24138impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24139    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24140        let start_offset = self.start.to_offset(snapshot);
24141        let end_offset = self.end.to_offset(snapshot);
24142        if start_offset == end_offset {
24143            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24144        } else {
24145            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24146        }
24147    }
24148}
24149
24150pub trait RowExt {
24151    fn as_f32(&self) -> f32;
24152
24153    fn next_row(&self) -> Self;
24154
24155    fn previous_row(&self) -> Self;
24156
24157    fn minus(&self, other: Self) -> u32;
24158}
24159
24160impl RowExt for DisplayRow {
24161    fn as_f32(&self) -> f32 {
24162        self.0 as f32
24163    }
24164
24165    fn next_row(&self) -> Self {
24166        Self(self.0 + 1)
24167    }
24168
24169    fn previous_row(&self) -> Self {
24170        Self(self.0.saturating_sub(1))
24171    }
24172
24173    fn minus(&self, other: Self) -> u32 {
24174        self.0 - other.0
24175    }
24176}
24177
24178impl RowExt for MultiBufferRow {
24179    fn as_f32(&self) -> f32 {
24180        self.0 as f32
24181    }
24182
24183    fn next_row(&self) -> Self {
24184        Self(self.0 + 1)
24185    }
24186
24187    fn previous_row(&self) -> Self {
24188        Self(self.0.saturating_sub(1))
24189    }
24190
24191    fn minus(&self, other: Self) -> u32 {
24192        self.0 - other.0
24193    }
24194}
24195
24196trait RowRangeExt {
24197    type Row;
24198
24199    fn len(&self) -> usize;
24200
24201    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24202}
24203
24204impl RowRangeExt for Range<MultiBufferRow> {
24205    type Row = MultiBufferRow;
24206
24207    fn len(&self) -> usize {
24208        (self.end.0 - self.start.0) as usize
24209    }
24210
24211    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24212        (self.start.0..self.end.0).map(MultiBufferRow)
24213    }
24214}
24215
24216impl RowRangeExt for Range<DisplayRow> {
24217    type Row = DisplayRow;
24218
24219    fn len(&self) -> usize {
24220        (self.end.0 - self.start.0) as usize
24221    }
24222
24223    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24224        (self.start.0..self.end.0).map(DisplayRow)
24225    }
24226}
24227
24228/// If select range has more than one line, we
24229/// just point the cursor to range.start.
24230fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24231    if range.start.row == range.end.row {
24232        range
24233    } else {
24234        range.start..range.start
24235    }
24236}
24237pub struct KillRing(ClipboardItem);
24238impl Global for KillRing {}
24239
24240const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24241
24242enum BreakpointPromptEditAction {
24243    Log,
24244    Condition,
24245    HitCondition,
24246}
24247
24248struct BreakpointPromptEditor {
24249    pub(crate) prompt: Entity<Editor>,
24250    editor: WeakEntity<Editor>,
24251    breakpoint_anchor: Anchor,
24252    breakpoint: Breakpoint,
24253    edit_action: BreakpointPromptEditAction,
24254    block_ids: HashSet<CustomBlockId>,
24255    editor_margins: Arc<Mutex<EditorMargins>>,
24256    _subscriptions: Vec<Subscription>,
24257}
24258
24259impl BreakpointPromptEditor {
24260    const MAX_LINES: u8 = 4;
24261
24262    fn new(
24263        editor: WeakEntity<Editor>,
24264        breakpoint_anchor: Anchor,
24265        breakpoint: Breakpoint,
24266        edit_action: BreakpointPromptEditAction,
24267        window: &mut Window,
24268        cx: &mut Context<Self>,
24269    ) -> Self {
24270        let base_text = match edit_action {
24271            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24272            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24273            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24274        }
24275        .map(|msg| msg.to_string())
24276        .unwrap_or_default();
24277
24278        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24279        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24280
24281        let prompt = cx.new(|cx| {
24282            let mut prompt = Editor::new(
24283                EditorMode::AutoHeight {
24284                    min_lines: 1,
24285                    max_lines: Some(Self::MAX_LINES as usize),
24286                },
24287                buffer,
24288                None,
24289                window,
24290                cx,
24291            );
24292            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24293            prompt.set_show_cursor_when_unfocused(false, cx);
24294            prompt.set_placeholder_text(
24295                match edit_action {
24296                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24297                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24298                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24299                },
24300                window,
24301                cx,
24302            );
24303
24304            prompt
24305        });
24306
24307        Self {
24308            prompt,
24309            editor,
24310            breakpoint_anchor,
24311            breakpoint,
24312            edit_action,
24313            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24314            block_ids: Default::default(),
24315            _subscriptions: vec![],
24316        }
24317    }
24318
24319    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24320        self.block_ids.extend(block_ids)
24321    }
24322
24323    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24324        if let Some(editor) = self.editor.upgrade() {
24325            let message = self
24326                .prompt
24327                .read(cx)
24328                .buffer
24329                .read(cx)
24330                .as_singleton()
24331                .expect("A multi buffer in breakpoint prompt isn't possible")
24332                .read(cx)
24333                .as_rope()
24334                .to_string();
24335
24336            editor.update(cx, |editor, cx| {
24337                editor.edit_breakpoint_at_anchor(
24338                    self.breakpoint_anchor,
24339                    self.breakpoint.clone(),
24340                    match self.edit_action {
24341                        BreakpointPromptEditAction::Log => {
24342                            BreakpointEditAction::EditLogMessage(message.into())
24343                        }
24344                        BreakpointPromptEditAction::Condition => {
24345                            BreakpointEditAction::EditCondition(message.into())
24346                        }
24347                        BreakpointPromptEditAction::HitCondition => {
24348                            BreakpointEditAction::EditHitCondition(message.into())
24349                        }
24350                    },
24351                    cx,
24352                );
24353
24354                editor.remove_blocks(self.block_ids.clone(), None, cx);
24355                cx.focus_self(window);
24356            });
24357        }
24358    }
24359
24360    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24361        self.editor
24362            .update(cx, |editor, cx| {
24363                editor.remove_blocks(self.block_ids.clone(), None, cx);
24364                window.focus(&editor.focus_handle);
24365            })
24366            .log_err();
24367    }
24368
24369    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24370        let settings = ThemeSettings::get_global(cx);
24371        let text_style = TextStyle {
24372            color: if self.prompt.read(cx).read_only(cx) {
24373                cx.theme().colors().text_disabled
24374            } else {
24375                cx.theme().colors().text
24376            },
24377            font_family: settings.buffer_font.family.clone(),
24378            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24379            font_size: settings.buffer_font_size(cx).into(),
24380            font_weight: settings.buffer_font.weight,
24381            line_height: relative(settings.buffer_line_height.value()),
24382            ..Default::default()
24383        };
24384        EditorElement::new(
24385            &self.prompt,
24386            EditorStyle {
24387                background: cx.theme().colors().editor_background,
24388                local_player: cx.theme().players().local(),
24389                text: text_style,
24390                ..Default::default()
24391            },
24392        )
24393    }
24394}
24395
24396impl Render for BreakpointPromptEditor {
24397    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24398        let editor_margins = *self.editor_margins.lock();
24399        let gutter_dimensions = editor_margins.gutter;
24400        h_flex()
24401            .key_context("Editor")
24402            .bg(cx.theme().colors().editor_background)
24403            .border_y_1()
24404            .border_color(cx.theme().status().info_border)
24405            .size_full()
24406            .py(window.line_height() / 2.5)
24407            .on_action(cx.listener(Self::confirm))
24408            .on_action(cx.listener(Self::cancel))
24409            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24410            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24411    }
24412}
24413
24414impl Focusable for BreakpointPromptEditor {
24415    fn focus_handle(&self, cx: &App) -> FocusHandle {
24416        self.prompt.focus_handle(cx)
24417    }
24418}
24419
24420fn all_edits_insertions_or_deletions(
24421    edits: &Vec<(Range<Anchor>, String)>,
24422    snapshot: &MultiBufferSnapshot,
24423) -> bool {
24424    let mut all_insertions = true;
24425    let mut all_deletions = true;
24426
24427    for (range, new_text) in edits.iter() {
24428        let range_is_empty = range.to_offset(snapshot).is_empty();
24429        let text_is_empty = new_text.is_empty();
24430
24431        if range_is_empty != text_is_empty {
24432            if range_is_empty {
24433                all_deletions = false;
24434            } else {
24435                all_insertions = false;
24436            }
24437        } else {
24438            return false;
24439        }
24440
24441        if !all_insertions && !all_deletions {
24442            return false;
24443        }
24444    }
24445    all_insertions || all_deletions
24446}
24447
24448struct MissingEditPredictionKeybindingTooltip;
24449
24450impl Render for MissingEditPredictionKeybindingTooltip {
24451    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24452        ui::tooltip_container(cx, |container, cx| {
24453            container
24454                .flex_shrink_0()
24455                .max_w_80()
24456                .min_h(rems_from_px(124.))
24457                .justify_between()
24458                .child(
24459                    v_flex()
24460                        .flex_1()
24461                        .text_ui_sm(cx)
24462                        .child(Label::new("Conflict with Accept Keybinding"))
24463                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24464                )
24465                .child(
24466                    h_flex()
24467                        .pb_1()
24468                        .gap_1()
24469                        .items_end()
24470                        .w_full()
24471                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24472                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24473                        }))
24474                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24475                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24476                        })),
24477                )
24478        })
24479    }
24480}
24481
24482#[derive(Debug, Clone, Copy, PartialEq)]
24483pub struct LineHighlight {
24484    pub background: Background,
24485    pub border: Option<gpui::Hsla>,
24486    pub include_gutter: bool,
24487    pub type_id: Option<TypeId>,
24488}
24489
24490struct LineManipulationResult {
24491    pub new_text: String,
24492    pub line_count_before: usize,
24493    pub line_count_after: usize,
24494}
24495
24496fn render_diff_hunk_controls(
24497    row: u32,
24498    status: &DiffHunkStatus,
24499    hunk_range: Range<Anchor>,
24500    is_created_file: bool,
24501    line_height: Pixels,
24502    editor: &Entity<Editor>,
24503    _window: &mut Window,
24504    cx: &mut App,
24505) -> AnyElement {
24506    h_flex()
24507        .h(line_height)
24508        .mr_1()
24509        .gap_1()
24510        .px_0p5()
24511        .pb_1()
24512        .border_x_1()
24513        .border_b_1()
24514        .border_color(cx.theme().colors().border_variant)
24515        .rounded_b_lg()
24516        .bg(cx.theme().colors().editor_background)
24517        .gap_1()
24518        .block_mouse_except_scroll()
24519        .shadow_md()
24520        .child(if status.has_secondary_hunk() {
24521            Button::new(("stage", row as u64), "Stage")
24522                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24523                .tooltip({
24524                    let focus_handle = editor.focus_handle(cx);
24525                    move |window, cx| {
24526                        Tooltip::for_action_in(
24527                            "Stage Hunk",
24528                            &::git::ToggleStaged,
24529                            &focus_handle,
24530                            window,
24531                            cx,
24532                        )
24533                    }
24534                })
24535                .on_click({
24536                    let editor = editor.clone();
24537                    move |_event, _window, cx| {
24538                        editor.update(cx, |editor, cx| {
24539                            editor.stage_or_unstage_diff_hunks(
24540                                true,
24541                                vec![hunk_range.start..hunk_range.start],
24542                                cx,
24543                            );
24544                        });
24545                    }
24546                })
24547        } else {
24548            Button::new(("unstage", row as u64), "Unstage")
24549                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24550                .tooltip({
24551                    let focus_handle = editor.focus_handle(cx);
24552                    move |window, cx| {
24553                        Tooltip::for_action_in(
24554                            "Unstage Hunk",
24555                            &::git::ToggleStaged,
24556                            &focus_handle,
24557                            window,
24558                            cx,
24559                        )
24560                    }
24561                })
24562                .on_click({
24563                    let editor = editor.clone();
24564                    move |_event, _window, cx| {
24565                        editor.update(cx, |editor, cx| {
24566                            editor.stage_or_unstage_diff_hunks(
24567                                false,
24568                                vec![hunk_range.start..hunk_range.start],
24569                                cx,
24570                            );
24571                        });
24572                    }
24573                })
24574        })
24575        .child(
24576            Button::new(("restore", row as u64), "Restore")
24577                .tooltip({
24578                    let focus_handle = editor.focus_handle(cx);
24579                    move |window, cx| {
24580                        Tooltip::for_action_in(
24581                            "Restore Hunk",
24582                            &::git::Restore,
24583                            &focus_handle,
24584                            window,
24585                            cx,
24586                        )
24587                    }
24588                })
24589                .on_click({
24590                    let editor = editor.clone();
24591                    move |_event, window, cx| {
24592                        editor.update(cx, |editor, cx| {
24593                            let snapshot = editor.snapshot(window, cx);
24594                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24595                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24596                        });
24597                    }
24598                })
24599                .disabled(is_created_file),
24600        )
24601        .when(
24602            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24603            |el| {
24604                el.child(
24605                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24606                        .shape(IconButtonShape::Square)
24607                        .icon_size(IconSize::Small)
24608                        // .disabled(!has_multiple_hunks)
24609                        .tooltip({
24610                            let focus_handle = editor.focus_handle(cx);
24611                            move |window, cx| {
24612                                Tooltip::for_action_in(
24613                                    "Next Hunk",
24614                                    &GoToHunk,
24615                                    &focus_handle,
24616                                    window,
24617                                    cx,
24618                                )
24619                            }
24620                        })
24621                        .on_click({
24622                            let editor = editor.clone();
24623                            move |_event, window, cx| {
24624                                editor.update(cx, |editor, cx| {
24625                                    let snapshot = editor.snapshot(window, cx);
24626                                    let position =
24627                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24628                                    editor.go_to_hunk_before_or_after_position(
24629                                        &snapshot,
24630                                        position,
24631                                        Direction::Next,
24632                                        window,
24633                                        cx,
24634                                    );
24635                                    editor.expand_selected_diff_hunks(cx);
24636                                });
24637                            }
24638                        }),
24639                )
24640                .child(
24641                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24642                        .shape(IconButtonShape::Square)
24643                        .icon_size(IconSize::Small)
24644                        // .disabled(!has_multiple_hunks)
24645                        .tooltip({
24646                            let focus_handle = editor.focus_handle(cx);
24647                            move |window, cx| {
24648                                Tooltip::for_action_in(
24649                                    "Previous Hunk",
24650                                    &GoToPreviousHunk,
24651                                    &focus_handle,
24652                                    window,
24653                                    cx,
24654                                )
24655                            }
24656                        })
24657                        .on_click({
24658                            let editor = editor.clone();
24659                            move |_event, window, cx| {
24660                                editor.update(cx, |editor, cx| {
24661                                    let snapshot = editor.snapshot(window, cx);
24662                                    let point =
24663                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24664                                    editor.go_to_hunk_before_or_after_position(
24665                                        &snapshot,
24666                                        point,
24667                                        Direction::Prev,
24668                                        window,
24669                                        cx,
24670                                    );
24671                                    editor.expand_selected_diff_hunks(cx);
24672                                });
24673                            }
24674                        }),
24675                )
24676            },
24677        )
24678        .into_any_element()
24679}
24680
24681pub fn multibuffer_context_lines(cx: &App) -> u32 {
24682    EditorSettings::try_get(cx)
24683        .map(|settings| settings.excerpt_context_lines)
24684        .unwrap_or(2)
24685        .min(32)
24686}