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, ShowScrollbar,
   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};
   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, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    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    MultiOrSingleBufferOffsetRange, 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::{
  164        DiagnosticSeverity, GitGutterSetting, GoToDiagnosticSeverityFilter, ProjectSettings,
  165    },
  166};
  167use rand::{seq::SliceRandom, thread_rng};
  168use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  169use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  170use selections_collection::{
  171    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  172};
  173use serde::{Deserialize, Serialize};
  174use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  175use smallvec::{SmallVec, smallvec};
  176use snippet::Snippet;
  177use std::{
  178    any::TypeId,
  179    borrow::Cow,
  180    cell::OnceCell,
  181    cell::RefCell,
  182    cmp::{self, Ordering, Reverse},
  183    iter::Peekable,
  184    mem,
  185    num::NonZeroU32,
  186    ops::Not,
  187    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  188    path::{Path, PathBuf},
  189    rc::Rc,
  190    sync::Arc,
  191    time::{Duration, Instant},
  192};
  193use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  202};
  203use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  204use workspace::{
  205    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  206    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  207    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  208    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::{
  214    code_context_menus::CompletionsMenuSource,
  215    editor_settings::MultiCursorModifier,
  216    hover_links::{find_url, find_url_from_range},
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  223const MAX_LINE_LEN: usize = 1024;
  224const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  225const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  226pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  227#[doc(hidden)]
  228pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  229pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  230
  231pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  234
  235pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  236pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252enum ReportEditorEvent {
  253    Saved { auto_saved: bool },
  254    EditorOpened,
  255    Closed,
  256}
  257
  258impl ReportEditorEvent {
  259    pub fn event_type(&self) -> &'static str {
  260        match self {
  261            Self::Saved { .. } => "Editor Saved",
  262            Self::EditorOpened => "Editor Opened",
  263            Self::Closed => "Editor Closed",
  264        }
  265    }
  266}
  267
  268struct InlineValueCache {
  269    enabled: bool,
  270    inlays: Vec<InlayId>,
  271    refresh_task: Task<Option<()>>,
  272}
  273
  274impl InlineValueCache {
  275    fn new(enabled: bool) -> Self {
  276        Self {
  277            enabled,
  278            inlays: Vec::new(),
  279            refresh_task: Task::ready(None),
  280        }
  281    }
  282}
  283
  284#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  285pub enum InlayId {
  286    EditPrediction(usize),
  287    DebuggerValue(usize),
  288    // LSP
  289    Hint(usize),
  290    Color(usize),
  291}
  292
  293impl InlayId {
  294    fn id(&self) -> usize {
  295        match self {
  296            Self::EditPrediction(id) => *id,
  297            Self::DebuggerValue(id) => *id,
  298            Self::Hint(id) => *id,
  299            Self::Color(id) => *id,
  300        }
  301    }
  302}
  303
  304pub enum ActiveDebugLine {}
  305pub enum DebugStackFrameLine {}
  306enum DocumentHighlightRead {}
  307enum DocumentHighlightWrite {}
  308enum InputComposition {}
  309pub enum PendingInput {}
  310enum SelectedTextHighlight {}
  311
  312pub enum ConflictsOuter {}
  313pub enum ConflictsOurs {}
  314pub enum ConflictsTheirs {}
  315pub enum ConflictsOursMarker {}
  316pub enum ConflictsTheirsMarker {}
  317
  318#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  319pub enum Navigated {
  320    Yes,
  321    No,
  322}
  323
  324impl Navigated {
  325    pub fn from_bool(yes: bool) -> Navigated {
  326        if yes { Navigated::Yes } else { Navigated::No }
  327    }
  328}
  329
  330#[derive(Debug, Clone, PartialEq, Eq)]
  331enum DisplayDiffHunk {
  332    Folded {
  333        display_row: DisplayRow,
  334    },
  335    Unfolded {
  336        is_created_file: bool,
  337        diff_base_byte_range: Range<usize>,
  338        display_row_range: Range<DisplayRow>,
  339        multi_buffer_range: Range<Anchor>,
  340        status: DiffHunkStatus,
  341    },
  342}
  343
  344pub enum HideMouseCursorOrigin {
  345    TypingAction,
  346    MovementAction,
  347}
  348
  349pub fn init_settings(cx: &mut App) {
  350    EditorSettings::register(cx);
  351}
  352
  353pub fn init(cx: &mut App) {
  354    init_settings(cx);
  355
  356    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  357
  358    workspace::register_project_item::<Editor>(cx);
  359    workspace::FollowableViewRegistry::register::<Editor>(cx);
  360    workspace::register_serializable_item::<Editor>(cx);
  361
  362    cx.observe_new(
  363        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  364            workspace.register_action(Editor::new_file);
  365            workspace.register_action(Editor::new_file_vertical);
  366            workspace.register_action(Editor::new_file_horizontal);
  367            workspace.register_action(Editor::cancel_language_server_work);
  368            workspace.register_action(Editor::toggle_focus);
  369        },
  370    )
  371    .detach();
  372
  373    cx.on_action(move |_: &workspace::NewFile, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    Editor::new_file(workspace, &Default::default(), window, cx)
  382                },
  383            )
  384            .detach();
  385        }
  386    });
  387    cx.on_action(move |_: &workspace::NewWindow, cx| {
  388        let app_state = workspace::AppState::global(cx);
  389        if let Some(app_state) = app_state.upgrade() {
  390            workspace::open_new(
  391                Default::default(),
  392                app_state,
  393                cx,
  394                |workspace, window, cx| {
  395                    cx.activate(true);
  396                    Editor::new_file(workspace, &Default::default(), window, cx)
  397                },
  398            )
  399            .detach();
  400        }
  401    });
  402}
  403
  404pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  405    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  406}
  407
  408pub trait DiagnosticRenderer {
  409    fn render_group(
  410        &self,
  411        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  412        buffer_id: BufferId,
  413        snapshot: EditorSnapshot,
  414        editor: WeakEntity<Editor>,
  415        cx: &mut App,
  416    ) -> Vec<BlockProperties<Anchor>>;
  417
  418    fn render_hover(
  419        &self,
  420        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  421        range: Range<Point>,
  422        buffer_id: BufferId,
  423        cx: &mut App,
  424    ) -> Option<Entity<markdown::Markdown>>;
  425
  426    fn open_link(
  427        &self,
  428        editor: &mut Editor,
  429        link: SharedString,
  430        window: &mut Window,
  431        cx: &mut Context<Editor>,
  432    );
  433}
  434
  435pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  436
  437impl GlobalDiagnosticRenderer {
  438    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  439        cx.try_global::<Self>().map(|g| g.0.clone())
  440    }
  441}
  442
  443impl gpui::Global for GlobalDiagnosticRenderer {}
  444pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  445    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  446}
  447
  448pub struct SearchWithinRange;
  449
  450trait InvalidationRegion {
  451    fn ranges(&self) -> &[Range<Anchor>];
  452}
  453
  454#[derive(Clone, Debug, PartialEq)]
  455pub enum SelectPhase {
  456    Begin {
  457        position: DisplayPoint,
  458        add: bool,
  459        click_count: usize,
  460    },
  461    BeginColumnar {
  462        position: DisplayPoint,
  463        reset: bool,
  464        mode: ColumnarMode,
  465        goal_column: u32,
  466    },
  467    Extend {
  468        position: DisplayPoint,
  469        click_count: usize,
  470    },
  471    Update {
  472        position: DisplayPoint,
  473        goal_column: u32,
  474        scroll_delta: gpui::Point<f32>,
  475    },
  476    End,
  477}
  478
  479#[derive(Clone, Debug, PartialEq)]
  480pub enum ColumnarMode {
  481    FromMouse,
  482    FromSelection,
  483}
  484
  485#[derive(Clone, Debug)]
  486pub enum SelectMode {
  487    Character,
  488    Word(Range<Anchor>),
  489    Line(Range<Anchor>),
  490    All,
  491}
  492
  493#[derive(Clone, PartialEq, Eq, Debug)]
  494pub enum EditorMode {
  495    SingleLine,
  496    AutoHeight {
  497        min_lines: usize,
  498        max_lines: Option<usize>,
  499    },
  500    Full {
  501        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  502        scale_ui_elements_with_buffer_font_size: bool,
  503        /// When set to `true`, the editor will render a background for the active line.
  504        show_active_line_background: bool,
  505        /// When set to `true`, the editor's height will be determined by its content.
  506        sized_by_content: bool,
  507    },
  508    Minimap {
  509        parent: WeakEntity<Editor>,
  510    },
  511}
  512
  513impl EditorMode {
  514    pub fn full() -> Self {
  515        Self::Full {
  516            scale_ui_elements_with_buffer_font_size: true,
  517            show_active_line_background: true,
  518            sized_by_content: false,
  519        }
  520    }
  521
  522    #[inline]
  523    pub fn is_full(&self) -> bool {
  524        matches!(self, Self::Full { .. })
  525    }
  526
  527    #[inline]
  528    pub fn is_single_line(&self) -> bool {
  529        matches!(self, Self::SingleLine { .. })
  530    }
  531
  532    #[inline]
  533    fn is_minimap(&self) -> bool {
  534        matches!(self, Self::Minimap { .. })
  535    }
  536}
  537
  538#[derive(Copy, Clone, Debug)]
  539pub enum SoftWrap {
  540    /// Prefer not to wrap at all.
  541    ///
  542    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  543    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  544    GitDiff,
  545    /// Prefer a single line generally, unless an overly long line is encountered.
  546    None,
  547    /// Soft wrap lines that exceed the editor width.
  548    EditorWidth,
  549    /// Soft wrap lines at the preferred line length.
  550    Column(u32),
  551    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  552    Bounded(u32),
  553}
  554
  555#[derive(Clone)]
  556pub struct EditorStyle {
  557    pub background: Hsla,
  558    pub border: Hsla,
  559    pub local_player: PlayerColor,
  560    pub text: TextStyle,
  561    pub scrollbar_width: Pixels,
  562    pub syntax: Arc<SyntaxTheme>,
  563    pub status: StatusColors,
  564    pub inlay_hints_style: HighlightStyle,
  565    pub edit_prediction_styles: EditPredictionStyles,
  566    pub unnecessary_code_fade: f32,
  567    pub show_underlines: bool,
  568}
  569
  570impl Default for EditorStyle {
  571    fn default() -> Self {
  572        Self {
  573            background: Hsla::default(),
  574            border: Hsla::default(),
  575            local_player: PlayerColor::default(),
  576            text: TextStyle::default(),
  577            scrollbar_width: Pixels::default(),
  578            syntax: Default::default(),
  579            // HACK: Status colors don't have a real default.
  580            // We should look into removing the status colors from the editor
  581            // style and retrieve them directly from the theme.
  582            status: StatusColors::dark(),
  583            inlay_hints_style: HighlightStyle::default(),
  584            edit_prediction_styles: EditPredictionStyles {
  585                insertion: HighlightStyle::default(),
  586                whitespace: HighlightStyle::default(),
  587            },
  588            unnecessary_code_fade: Default::default(),
  589            show_underlines: true,
  590        }
  591    }
  592}
  593
  594pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  595    let show_background = language_settings::language_settings(None, None, cx)
  596        .inlay_hints
  597        .show_background;
  598
  599    HighlightStyle {
  600        color: Some(cx.theme().status().hint),
  601        background_color: show_background.then(|| cx.theme().status().hint_background),
  602        ..HighlightStyle::default()
  603    }
  604}
  605
  606pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  607    EditPredictionStyles {
  608        insertion: HighlightStyle {
  609            color: Some(cx.theme().status().predictive),
  610            ..HighlightStyle::default()
  611        },
  612        whitespace: HighlightStyle {
  613            background_color: Some(cx.theme().status().created_background),
  614            ..HighlightStyle::default()
  615        },
  616    }
  617}
  618
  619type CompletionId = usize;
  620
  621pub(crate) enum EditDisplayMode {
  622    TabAccept,
  623    DiffPopover,
  624    Inline,
  625}
  626
  627enum EditPrediction {
  628    Edit {
  629        edits: Vec<(Range<Anchor>, String)>,
  630        edit_preview: Option<EditPreview>,
  631        display_mode: EditDisplayMode,
  632        snapshot: BufferSnapshot,
  633    },
  634    Move {
  635        target: Anchor,
  636        snapshot: BufferSnapshot,
  637    },
  638}
  639
  640struct EditPredictionState {
  641    inlay_ids: Vec<InlayId>,
  642    completion: EditPrediction,
  643    completion_id: Option<SharedString>,
  644    invalidation_range: Range<Anchor>,
  645}
  646
  647enum EditPredictionSettings {
  648    Disabled,
  649    Enabled {
  650        show_in_menu: bool,
  651        preview_requires_modifier: bool,
  652    },
  653}
  654
  655enum EditPredictionHighlight {}
  656
  657#[derive(Debug, Clone)]
  658struct InlineDiagnostic {
  659    message: SharedString,
  660    group_id: usize,
  661    is_primary: bool,
  662    start: Point,
  663    severity: lsp::DiagnosticSeverity,
  664}
  665
  666pub enum MenuEditPredictionsPolicy {
  667    Never,
  668    ByProvider,
  669}
  670
  671pub enum EditPredictionPreview {
  672    /// Modifier is not pressed
  673    Inactive { released_too_fast: bool },
  674    /// Modifier pressed
  675    Active {
  676        since: Instant,
  677        previous_scroll_position: Option<ScrollAnchor>,
  678    },
  679}
  680
  681impl EditPredictionPreview {
  682    pub fn released_too_fast(&self) -> bool {
  683        match self {
  684            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  685            EditPredictionPreview::Active { .. } => false,
  686        }
  687    }
  688
  689    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  690        if let EditPredictionPreview::Active {
  691            previous_scroll_position,
  692            ..
  693        } = self
  694        {
  695            *previous_scroll_position = scroll_position;
  696        }
  697    }
  698}
  699
  700pub struct ContextMenuOptions {
  701    pub min_entries_visible: usize,
  702    pub max_entries_visible: usize,
  703    pub placement: Option<ContextMenuPlacement>,
  704}
  705
  706#[derive(Debug, Clone, PartialEq, Eq)]
  707pub enum ContextMenuPlacement {
  708    Above,
  709    Below,
  710}
  711
  712#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  713struct EditorActionId(usize);
  714
  715impl EditorActionId {
  716    pub fn post_inc(&mut self) -> Self {
  717        let answer = self.0;
  718
  719        *self = Self(answer + 1);
  720
  721        Self(answer)
  722    }
  723}
  724
  725// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  726// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  727
  728type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  729type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  730
  731#[derive(Default)]
  732struct ScrollbarMarkerState {
  733    scrollbar_size: Size<Pixels>,
  734    dirty: bool,
  735    markers: Arc<[PaintQuad]>,
  736    pending_refresh: Option<Task<Result<()>>>,
  737}
  738
  739impl ScrollbarMarkerState {
  740    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  741        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  742    }
  743}
  744
  745#[derive(Clone, Copy, PartialEq, Eq)]
  746pub enum MinimapVisibility {
  747    Disabled,
  748    Enabled {
  749        /// The configuration currently present in the users settings.
  750        setting_configuration: bool,
  751        /// Whether to override the currently set visibility from the users setting.
  752        toggle_override: bool,
  753    },
  754}
  755
  756impl MinimapVisibility {
  757    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  758        if mode.is_full() {
  759            Self::Enabled {
  760                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  761                toggle_override: false,
  762            }
  763        } else {
  764            Self::Disabled
  765        }
  766    }
  767
  768    fn hidden(&self) -> Self {
  769        match *self {
  770            Self::Enabled {
  771                setting_configuration,
  772                ..
  773            } => Self::Enabled {
  774                setting_configuration,
  775                toggle_override: setting_configuration,
  776            },
  777            Self::Disabled => Self::Disabled,
  778        }
  779    }
  780
  781    fn disabled(&self) -> bool {
  782        matches!(*self, Self::Disabled)
  783    }
  784
  785    fn settings_visibility(&self) -> bool {
  786        match *self {
  787            Self::Enabled {
  788                setting_configuration,
  789                ..
  790            } => setting_configuration,
  791            _ => false,
  792        }
  793    }
  794
  795    fn visible(&self) -> bool {
  796        match *self {
  797            Self::Enabled {
  798                setting_configuration,
  799                toggle_override,
  800            } => setting_configuration ^ toggle_override,
  801            _ => false,
  802        }
  803    }
  804
  805    fn toggle_visibility(&self) -> Self {
  806        match *self {
  807            Self::Enabled {
  808                toggle_override,
  809                setting_configuration,
  810            } => Self::Enabled {
  811                setting_configuration,
  812                toggle_override: !toggle_override,
  813            },
  814            Self::Disabled => Self::Disabled,
  815        }
  816    }
  817}
  818
  819#[derive(Clone, Debug)]
  820struct RunnableTasks {
  821    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  822    offset: multi_buffer::Anchor,
  823    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  824    column: u32,
  825    // Values of all named captures, including those starting with '_'
  826    extra_variables: HashMap<String, String>,
  827    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  828    context_range: Range<BufferOffset>,
  829}
  830
  831impl RunnableTasks {
  832    fn resolve<'a>(
  833        &'a self,
  834        cx: &'a task::TaskContext,
  835    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  836        self.templates.iter().filter_map(|(kind, template)| {
  837            template
  838                .resolve_task(&kind.to_id_base(), cx)
  839                .map(|task| (kind.clone(), task))
  840        })
  841    }
  842}
  843
  844#[derive(Clone)]
  845pub struct ResolvedTasks {
  846    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  847    position: Anchor,
  848}
  849
  850#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  851struct BufferOffset(usize);
  852
  853// Addons allow storing per-editor state in other crates (e.g. Vim)
  854pub trait Addon: 'static {
  855    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  856
  857    fn render_buffer_header_controls(
  858        &self,
  859        _: &ExcerptInfo,
  860        _: &Window,
  861        _: &App,
  862    ) -> Option<AnyElement> {
  863        None
  864    }
  865
  866    fn to_any(&self) -> &dyn std::any::Any;
  867
  868    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  869        None
  870    }
  871}
  872
  873struct ChangeLocation {
  874    current: Option<Vec<Anchor>>,
  875    original: Vec<Anchor>,
  876}
  877impl ChangeLocation {
  878    fn locations(&self) -> &[Anchor] {
  879        self.current.as_ref().unwrap_or(&self.original)
  880    }
  881}
  882
  883/// A set of caret positions, registered when the editor was edited.
  884pub struct ChangeList {
  885    changes: Vec<ChangeLocation>,
  886    /// Currently "selected" change.
  887    position: Option<usize>,
  888}
  889
  890impl ChangeList {
  891    pub fn new() -> Self {
  892        Self {
  893            changes: Vec::new(),
  894            position: None,
  895        }
  896    }
  897
  898    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  899    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  900    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  901        if self.changes.is_empty() {
  902            return None;
  903        }
  904
  905        let prev = self.position.unwrap_or(self.changes.len());
  906        let next = if direction == Direction::Prev {
  907            prev.saturating_sub(count)
  908        } else {
  909            (prev + count).min(self.changes.len() - 1)
  910        };
  911        self.position = Some(next);
  912        self.changes.get(next).map(|change| change.locations())
  913    }
  914
  915    /// Adds a new change to the list, resetting the change list position.
  916    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  917        self.position.take();
  918        if let Some(last) = self.changes.last_mut()
  919            && group
  920        {
  921            last.current = Some(new_positions)
  922        } else {
  923            self.changes.push(ChangeLocation {
  924                original: new_positions,
  925                current: None,
  926            });
  927        }
  928    }
  929
  930    pub fn last(&self) -> Option<&[Anchor]> {
  931        self.changes.last().map(|change| change.locations())
  932    }
  933
  934    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  935        self.changes.last().map(|change| change.original.as_slice())
  936    }
  937
  938    pub fn invert_last_group(&mut self) {
  939        if let Some(last) = self.changes.last_mut()
  940            && let Some(current) = last.current.as_mut()
  941        {
  942            mem::swap(&mut last.original, current);
  943        }
  944    }
  945}
  946
  947#[derive(Clone)]
  948struct InlineBlamePopoverState {
  949    scroll_handle: ScrollHandle,
  950    commit_message: Option<ParsedCommitMessage>,
  951    markdown: Entity<Markdown>,
  952}
  953
  954struct InlineBlamePopover {
  955    position: gpui::Point<Pixels>,
  956    hide_task: Option<Task<()>>,
  957    popover_bounds: Option<Bounds<Pixels>>,
  958    popover_state: InlineBlamePopoverState,
  959    keyboard_grace: bool,
  960}
  961
  962enum SelectionDragState {
  963    /// State when no drag related activity is detected.
  964    None,
  965    /// State when the mouse is down on a selection that is about to be dragged.
  966    ReadyToDrag {
  967        selection: Selection<Anchor>,
  968        click_position: gpui::Point<Pixels>,
  969        mouse_down_time: Instant,
  970    },
  971    /// State when the mouse is dragging the selection in the editor.
  972    Dragging {
  973        selection: Selection<Anchor>,
  974        drop_cursor: Selection<Anchor>,
  975        hide_drop_cursor: bool,
  976    },
  977}
  978
  979enum ColumnarSelectionState {
  980    FromMouse {
  981        selection_tail: Anchor,
  982        display_point: Option<DisplayPoint>,
  983    },
  984    FromSelection {
  985        selection_tail: Anchor,
  986    },
  987}
  988
  989/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  990/// a breakpoint on them.
  991#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  992struct PhantomBreakpointIndicator {
  993    display_row: DisplayRow,
  994    /// There's a small debounce between hovering over the line and showing the indicator.
  995    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  996    is_active: bool,
  997    collides_with_existing_breakpoint: bool,
  998}
  999
 1000/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1001///
 1002/// See the [module level documentation](self) for more information.
 1003pub struct Editor {
 1004    focus_handle: FocusHandle,
 1005    last_focused_descendant: Option<WeakFocusHandle>,
 1006    /// The text buffer being edited
 1007    buffer: Entity<MultiBuffer>,
 1008    /// Map of how text in the buffer should be displayed.
 1009    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1010    pub display_map: Entity<DisplayMap>,
 1011    pub selections: SelectionsCollection,
 1012    pub scroll_manager: ScrollManager,
 1013    /// When inline assist editors are linked, they all render cursors because
 1014    /// typing enters text into each of them, even the ones that aren't focused.
 1015    pub(crate) show_cursor_when_unfocused: bool,
 1016    columnar_selection_state: Option<ColumnarSelectionState>,
 1017    add_selections_state: Option<AddSelectionsState>,
 1018    select_next_state: Option<SelectNextState>,
 1019    select_prev_state: Option<SelectNextState>,
 1020    selection_history: SelectionHistory,
 1021    defer_selection_effects: bool,
 1022    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1023    autoclose_regions: Vec<AutocloseRegion>,
 1024    snippet_stack: InvalidationStack<SnippetState>,
 1025    select_syntax_node_history: SelectSyntaxNodeHistory,
 1026    ime_transaction: Option<TransactionId>,
 1027    pub diagnostics_max_severity: DiagnosticSeverity,
 1028    active_diagnostics: ActiveDiagnostic,
 1029    show_inline_diagnostics: bool,
 1030    inline_diagnostics_update: Task<()>,
 1031    inline_diagnostics_enabled: bool,
 1032    diagnostics_enabled: bool,
 1033    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1034    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1035    hard_wrap: Option<usize>,
 1036    project: Option<Entity<Project>>,
 1037    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1038    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1039    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1040    blink_manager: Entity<BlinkManager>,
 1041    show_cursor_names: bool,
 1042    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1043    pub show_local_selections: bool,
 1044    mode: EditorMode,
 1045    show_breadcrumbs: bool,
 1046    show_gutter: bool,
 1047    show_scrollbars: ScrollbarAxes,
 1048    minimap_visibility: MinimapVisibility,
 1049    offset_content: bool,
 1050    disable_expand_excerpt_buttons: bool,
 1051    show_line_numbers: Option<bool>,
 1052    use_relative_line_numbers: Option<bool>,
 1053    show_git_diff_gutter: Option<bool>,
 1054    show_code_actions: Option<bool>,
 1055    show_runnables: Option<bool>,
 1056    show_breakpoints: Option<bool>,
 1057    show_wrap_guides: Option<bool>,
 1058    show_indent_guides: Option<bool>,
 1059    placeholder_text: Option<Arc<str>>,
 1060    highlight_order: usize,
 1061    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1062    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1063    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1064    scrollbar_marker_state: ScrollbarMarkerState,
 1065    active_indent_guides_state: ActiveIndentGuidesState,
 1066    nav_history: Option<ItemNavHistory>,
 1067    context_menu: RefCell<Option<CodeContextMenu>>,
 1068    context_menu_options: Option<ContextMenuOptions>,
 1069    mouse_context_menu: Option<MouseContextMenu>,
 1070    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1071    inline_blame_popover: Option<InlineBlamePopover>,
 1072    inline_blame_popover_show_task: Option<Task<()>>,
 1073    signature_help_state: SignatureHelpState,
 1074    auto_signature_help: Option<bool>,
 1075    find_all_references_task_sources: Vec<Anchor>,
 1076    next_completion_id: CompletionId,
 1077    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1078    code_actions_task: Option<Task<Result<()>>>,
 1079    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1080    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1081    document_highlights_task: Option<Task<()>>,
 1082    linked_editing_range_task: Option<Task<Option<()>>>,
 1083    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1084    pending_rename: Option<RenameState>,
 1085    searchable: bool,
 1086    cursor_shape: CursorShape,
 1087    current_line_highlight: Option<CurrentLineHighlight>,
 1088    collapse_matches: bool,
 1089    autoindent_mode: Option<AutoindentMode>,
 1090    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1091    input_enabled: bool,
 1092    use_modal_editing: bool,
 1093    read_only: bool,
 1094    leader_id: Option<CollaboratorId>,
 1095    remote_id: Option<ViewId>,
 1096    pub hover_state: HoverState,
 1097    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1098    gutter_hovered: bool,
 1099    hovered_link_state: Option<HoveredLinkState>,
 1100    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1101    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1102    active_edit_prediction: Option<EditPredictionState>,
 1103    /// Used to prevent flickering as the user types while the menu is open
 1104    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1105    edit_prediction_settings: EditPredictionSettings,
 1106    edit_predictions_hidden_for_vim_mode: bool,
 1107    show_edit_predictions_override: Option<bool>,
 1108    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1109    edit_prediction_preview: EditPredictionPreview,
 1110    edit_prediction_indent_conflict: bool,
 1111    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1112    inlay_hint_cache: InlayHintCache,
 1113    next_inlay_id: usize,
 1114    _subscriptions: Vec<Subscription>,
 1115    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1116    gutter_dimensions: GutterDimensions,
 1117    style: Option<EditorStyle>,
 1118    text_style_refinement: Option<TextStyleRefinement>,
 1119    next_editor_action_id: EditorActionId,
 1120    editor_actions: Rc<
 1121        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1122    >,
 1123    use_autoclose: bool,
 1124    use_auto_surround: bool,
 1125    auto_replace_emoji_shortcode: bool,
 1126    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1127    show_git_blame_gutter: bool,
 1128    show_git_blame_inline: bool,
 1129    show_git_blame_inline_delay_task: Option<Task<()>>,
 1130    git_blame_inline_enabled: bool,
 1131    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1132    serialize_dirty_buffers: bool,
 1133    show_selection_menu: Option<bool>,
 1134    blame: Option<Entity<GitBlame>>,
 1135    blame_subscription: Option<Subscription>,
 1136    custom_context_menu: Option<
 1137        Box<
 1138            dyn 'static
 1139                + Fn(
 1140                    &mut Self,
 1141                    DisplayPoint,
 1142                    &mut Window,
 1143                    &mut Context<Self>,
 1144                ) -> Option<Entity<ui::ContextMenu>>,
 1145        >,
 1146    >,
 1147    last_bounds: Option<Bounds<Pixels>>,
 1148    last_position_map: Option<Rc<PositionMap>>,
 1149    expect_bounds_change: Option<Bounds<Pixels>>,
 1150    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1151    tasks_update_task: Option<Task<()>>,
 1152    breakpoint_store: Option<Entity<BreakpointStore>>,
 1153    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1154    hovered_diff_hunk_row: Option<DisplayRow>,
 1155    pull_diagnostics_task: Task<()>,
 1156    in_project_search: bool,
 1157    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1158    breadcrumb_header: Option<String>,
 1159    focused_block: Option<FocusedBlock>,
 1160    next_scroll_position: NextScrollCursorCenterTopBottom,
 1161    addons: HashMap<TypeId, Box<dyn Addon>>,
 1162    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1163    load_diff_task: Option<Shared<Task<()>>>,
 1164    /// Whether we are temporarily displaying a diff other than git's
 1165    temporary_diff_override: bool,
 1166    selection_mark_mode: bool,
 1167    toggle_fold_multiple_buffers: Task<()>,
 1168    _scroll_cursor_center_top_bottom_task: Task<()>,
 1169    serialize_selections: Task<()>,
 1170    serialize_folds: Task<()>,
 1171    mouse_cursor_hidden: bool,
 1172    minimap: Option<Entity<Self>>,
 1173    hide_mouse_mode: HideMouseMode,
 1174    pub change_list: ChangeList,
 1175    inline_value_cache: InlineValueCache,
 1176    selection_drag_state: SelectionDragState,
 1177    next_color_inlay_id: usize,
 1178    colors: Option<LspColorData>,
 1179    folding_newlines: Task<()>,
 1180}
 1181
 1182#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1183enum NextScrollCursorCenterTopBottom {
 1184    #[default]
 1185    Center,
 1186    Top,
 1187    Bottom,
 1188}
 1189
 1190impl NextScrollCursorCenterTopBottom {
 1191    fn next(&self) -> Self {
 1192        match self {
 1193            Self::Center => Self::Top,
 1194            Self::Top => Self::Bottom,
 1195            Self::Bottom => Self::Center,
 1196        }
 1197    }
 1198}
 1199
 1200#[derive(Clone)]
 1201pub struct EditorSnapshot {
 1202    pub mode: EditorMode,
 1203    show_gutter: bool,
 1204    show_line_numbers: Option<bool>,
 1205    show_git_diff_gutter: Option<bool>,
 1206    show_code_actions: Option<bool>,
 1207    show_runnables: Option<bool>,
 1208    show_breakpoints: Option<bool>,
 1209    git_blame_gutter_max_author_length: Option<usize>,
 1210    pub display_snapshot: DisplaySnapshot,
 1211    pub placeholder_text: Option<Arc<str>>,
 1212    is_focused: bool,
 1213    scroll_anchor: ScrollAnchor,
 1214    ongoing_scroll: OngoingScroll,
 1215    current_line_highlight: CurrentLineHighlight,
 1216    gutter_hovered: bool,
 1217}
 1218
 1219#[derive(Default, Debug, Clone, Copy)]
 1220pub struct GutterDimensions {
 1221    pub left_padding: Pixels,
 1222    pub right_padding: Pixels,
 1223    pub width: Pixels,
 1224    pub margin: Pixels,
 1225    pub git_blame_entries_width: Option<Pixels>,
 1226}
 1227
 1228impl GutterDimensions {
 1229    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1230        Self {
 1231            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1232            ..Default::default()
 1233        }
 1234    }
 1235
 1236    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1237        -cx.text_system().descent(font_id, font_size)
 1238    }
 1239    /// The full width of the space taken up by the gutter.
 1240    pub fn full_width(&self) -> Pixels {
 1241        self.margin + self.width
 1242    }
 1243
 1244    /// The width of the space reserved for the fold indicators,
 1245    /// use alongside 'justify_end' and `gutter_width` to
 1246    /// right align content with the line numbers
 1247    pub fn fold_area_width(&self) -> Pixels {
 1248        self.margin + self.right_padding
 1249    }
 1250}
 1251
 1252struct CharacterDimensions {
 1253    em_width: Pixels,
 1254    em_advance: Pixels,
 1255    line_height: Pixels,
 1256}
 1257
 1258#[derive(Debug)]
 1259pub struct RemoteSelection {
 1260    pub replica_id: ReplicaId,
 1261    pub selection: Selection<Anchor>,
 1262    pub cursor_shape: CursorShape,
 1263    pub collaborator_id: CollaboratorId,
 1264    pub line_mode: bool,
 1265    pub user_name: Option<SharedString>,
 1266    pub color: PlayerColor,
 1267}
 1268
 1269#[derive(Clone, Debug)]
 1270struct SelectionHistoryEntry {
 1271    selections: Arc<[Selection<Anchor>]>,
 1272    select_next_state: Option<SelectNextState>,
 1273    select_prev_state: Option<SelectNextState>,
 1274    add_selections_state: Option<AddSelectionsState>,
 1275}
 1276
 1277#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1278enum SelectionHistoryMode {
 1279    Normal,
 1280    Undoing,
 1281    Redoing,
 1282    Skipping,
 1283}
 1284
 1285#[derive(Clone, PartialEq, Eq, Hash)]
 1286struct HoveredCursor {
 1287    replica_id: u16,
 1288    selection_id: usize,
 1289}
 1290
 1291impl Default for SelectionHistoryMode {
 1292    fn default() -> Self {
 1293        Self::Normal
 1294    }
 1295}
 1296
 1297#[derive(Debug)]
 1298/// SelectionEffects controls the side-effects of updating the selection.
 1299///
 1300/// The default behaviour does "what you mostly want":
 1301/// - it pushes to the nav history if the cursor moved by >10 lines
 1302/// - it re-triggers completion requests
 1303/// - it scrolls to fit
 1304///
 1305/// You might want to modify these behaviours. For example when doing a "jump"
 1306/// like go to definition, we always want to add to nav history; but when scrolling
 1307/// in vim mode we never do.
 1308///
 1309/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1310/// move.
 1311#[derive(Clone)]
 1312pub struct SelectionEffects {
 1313    nav_history: Option<bool>,
 1314    completions: bool,
 1315    scroll: Option<Autoscroll>,
 1316}
 1317
 1318impl Default for SelectionEffects {
 1319    fn default() -> Self {
 1320        Self {
 1321            nav_history: None,
 1322            completions: true,
 1323            scroll: Some(Autoscroll::fit()),
 1324        }
 1325    }
 1326}
 1327impl SelectionEffects {
 1328    pub fn scroll(scroll: Autoscroll) -> Self {
 1329        Self {
 1330            scroll: Some(scroll),
 1331            ..Default::default()
 1332        }
 1333    }
 1334
 1335    pub fn no_scroll() -> Self {
 1336        Self {
 1337            scroll: None,
 1338            ..Default::default()
 1339        }
 1340    }
 1341
 1342    pub fn completions(self, completions: bool) -> Self {
 1343        Self {
 1344            completions,
 1345            ..self
 1346        }
 1347    }
 1348
 1349    pub fn nav_history(self, nav_history: bool) -> Self {
 1350        Self {
 1351            nav_history: Some(nav_history),
 1352            ..self
 1353        }
 1354    }
 1355}
 1356
 1357struct DeferredSelectionEffectsState {
 1358    changed: bool,
 1359    effects: SelectionEffects,
 1360    old_cursor_position: Anchor,
 1361    history_entry: SelectionHistoryEntry,
 1362}
 1363
 1364#[derive(Default)]
 1365struct SelectionHistory {
 1366    #[allow(clippy::type_complexity)]
 1367    selections_by_transaction:
 1368        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1369    mode: SelectionHistoryMode,
 1370    undo_stack: VecDeque<SelectionHistoryEntry>,
 1371    redo_stack: VecDeque<SelectionHistoryEntry>,
 1372}
 1373
 1374impl SelectionHistory {
 1375    #[track_caller]
 1376    fn insert_transaction(
 1377        &mut self,
 1378        transaction_id: TransactionId,
 1379        selections: Arc<[Selection<Anchor>]>,
 1380    ) {
 1381        if selections.is_empty() {
 1382            log::error!(
 1383                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1384                std::panic::Location::caller()
 1385            );
 1386            return;
 1387        }
 1388        self.selections_by_transaction
 1389            .insert(transaction_id, (selections, None));
 1390    }
 1391
 1392    #[allow(clippy::type_complexity)]
 1393    fn transaction(
 1394        &self,
 1395        transaction_id: TransactionId,
 1396    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1397        self.selections_by_transaction.get(&transaction_id)
 1398    }
 1399
 1400    #[allow(clippy::type_complexity)]
 1401    fn transaction_mut(
 1402        &mut self,
 1403        transaction_id: TransactionId,
 1404    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1405        self.selections_by_transaction.get_mut(&transaction_id)
 1406    }
 1407
 1408    fn push(&mut self, entry: SelectionHistoryEntry) {
 1409        if !entry.selections.is_empty() {
 1410            match self.mode {
 1411                SelectionHistoryMode::Normal => {
 1412                    self.push_undo(entry);
 1413                    self.redo_stack.clear();
 1414                }
 1415                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1416                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1417                SelectionHistoryMode::Skipping => {}
 1418            }
 1419        }
 1420    }
 1421
 1422    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1423        if self
 1424            .undo_stack
 1425            .back()
 1426            .is_none_or(|e| e.selections != entry.selections)
 1427        {
 1428            self.undo_stack.push_back(entry);
 1429            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1430                self.undo_stack.pop_front();
 1431            }
 1432        }
 1433    }
 1434
 1435    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1436        if self
 1437            .redo_stack
 1438            .back()
 1439            .is_none_or(|e| e.selections != entry.selections)
 1440        {
 1441            self.redo_stack.push_back(entry);
 1442            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1443                self.redo_stack.pop_front();
 1444            }
 1445        }
 1446    }
 1447}
 1448
 1449#[derive(Clone, Copy)]
 1450pub struct RowHighlightOptions {
 1451    pub autoscroll: bool,
 1452    pub include_gutter: bool,
 1453}
 1454
 1455impl Default for RowHighlightOptions {
 1456    fn default() -> Self {
 1457        Self {
 1458            autoscroll: Default::default(),
 1459            include_gutter: true,
 1460        }
 1461    }
 1462}
 1463
 1464struct RowHighlight {
 1465    index: usize,
 1466    range: Range<Anchor>,
 1467    color: Hsla,
 1468    options: RowHighlightOptions,
 1469    type_id: TypeId,
 1470}
 1471
 1472#[derive(Clone, Debug)]
 1473struct AddSelectionsState {
 1474    groups: Vec<AddSelectionsGroup>,
 1475}
 1476
 1477#[derive(Clone, Debug)]
 1478struct AddSelectionsGroup {
 1479    above: bool,
 1480    stack: Vec<usize>,
 1481}
 1482
 1483#[derive(Clone)]
 1484struct SelectNextState {
 1485    query: AhoCorasick,
 1486    wordwise: bool,
 1487    done: bool,
 1488}
 1489
 1490impl std::fmt::Debug for SelectNextState {
 1491    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1492        f.debug_struct(std::any::type_name::<Self>())
 1493            .field("wordwise", &self.wordwise)
 1494            .field("done", &self.done)
 1495            .finish()
 1496    }
 1497}
 1498
 1499#[derive(Debug)]
 1500struct AutocloseRegion {
 1501    selection_id: usize,
 1502    range: Range<Anchor>,
 1503    pair: BracketPair,
 1504}
 1505
 1506#[derive(Debug)]
 1507struct SnippetState {
 1508    ranges: Vec<Vec<Range<Anchor>>>,
 1509    active_index: usize,
 1510    choices: Vec<Option<Vec<String>>>,
 1511}
 1512
 1513#[doc(hidden)]
 1514pub struct RenameState {
 1515    pub range: Range<Anchor>,
 1516    pub old_name: Arc<str>,
 1517    pub editor: Entity<Editor>,
 1518    block_id: CustomBlockId,
 1519}
 1520
 1521struct InvalidationStack<T>(Vec<T>);
 1522
 1523struct RegisteredEditPredictionProvider {
 1524    provider: Arc<dyn EditPredictionProviderHandle>,
 1525    _subscription: Subscription,
 1526}
 1527
 1528#[derive(Debug, PartialEq, Eq)]
 1529pub struct ActiveDiagnosticGroup {
 1530    pub active_range: Range<Anchor>,
 1531    pub active_message: String,
 1532    pub group_id: usize,
 1533    pub blocks: HashSet<CustomBlockId>,
 1534}
 1535
 1536#[derive(Debug, PartialEq, Eq)]
 1537
 1538pub(crate) enum ActiveDiagnostic {
 1539    None,
 1540    All,
 1541    Group(ActiveDiagnosticGroup),
 1542}
 1543
 1544#[derive(Serialize, Deserialize, Clone, Debug)]
 1545pub struct ClipboardSelection {
 1546    /// The number of bytes in this selection.
 1547    pub len: usize,
 1548    /// Whether this was a full-line selection.
 1549    pub is_entire_line: bool,
 1550    /// The indentation of the first line when this content was originally copied.
 1551    pub first_line_indent: u32,
 1552}
 1553
 1554// selections, scroll behavior, was newest selection reversed
 1555type SelectSyntaxNodeHistoryState = (
 1556    Box<[Selection<usize>]>,
 1557    SelectSyntaxNodeScrollBehavior,
 1558    bool,
 1559);
 1560
 1561#[derive(Default)]
 1562struct SelectSyntaxNodeHistory {
 1563    stack: Vec<SelectSyntaxNodeHistoryState>,
 1564    // disable temporarily to allow changing selections without losing the stack
 1565    pub disable_clearing: bool,
 1566}
 1567
 1568impl SelectSyntaxNodeHistory {
 1569    pub fn try_clear(&mut self) {
 1570        if !self.disable_clearing {
 1571            self.stack.clear();
 1572        }
 1573    }
 1574
 1575    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1576        self.stack.push(selection);
 1577    }
 1578
 1579    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1580        self.stack.pop()
 1581    }
 1582}
 1583
 1584enum SelectSyntaxNodeScrollBehavior {
 1585    CursorTop,
 1586    FitSelection,
 1587    CursorBottom,
 1588}
 1589
 1590#[derive(Debug)]
 1591pub(crate) struct NavigationData {
 1592    cursor_anchor: Anchor,
 1593    cursor_position: Point,
 1594    scroll_anchor: ScrollAnchor,
 1595    scroll_top_row: u32,
 1596}
 1597
 1598#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1599pub enum GotoDefinitionKind {
 1600    Symbol,
 1601    Declaration,
 1602    Type,
 1603    Implementation,
 1604}
 1605
 1606#[derive(Debug, Clone)]
 1607enum InlayHintRefreshReason {
 1608    ModifiersChanged(bool),
 1609    Toggle(bool),
 1610    SettingsChange(InlayHintSettings),
 1611    NewLinesShown,
 1612    BufferEdited(HashSet<Arc<Language>>),
 1613    RefreshRequested,
 1614    ExcerptsRemoved(Vec<ExcerptId>),
 1615}
 1616
 1617impl InlayHintRefreshReason {
 1618    fn description(&self) -> &'static str {
 1619        match self {
 1620            Self::ModifiersChanged(_) => "modifiers changed",
 1621            Self::Toggle(_) => "toggle",
 1622            Self::SettingsChange(_) => "settings change",
 1623            Self::NewLinesShown => "new lines shown",
 1624            Self::BufferEdited(_) => "buffer edited",
 1625            Self::RefreshRequested => "refresh requested",
 1626            Self::ExcerptsRemoved(_) => "excerpts removed",
 1627        }
 1628    }
 1629}
 1630
 1631pub enum FormatTarget {
 1632    Buffers(HashSet<Entity<Buffer>>),
 1633    Ranges(Vec<Range<MultiBufferPoint>>),
 1634}
 1635
 1636pub(crate) struct FocusedBlock {
 1637    id: BlockId,
 1638    focus_handle: WeakFocusHandle,
 1639}
 1640
 1641#[derive(Clone)]
 1642enum JumpData {
 1643    MultiBufferRow {
 1644        row: MultiBufferRow,
 1645        line_offset_from_top: u32,
 1646    },
 1647    MultiBufferPoint {
 1648        excerpt_id: ExcerptId,
 1649        position: Point,
 1650        anchor: text::Anchor,
 1651        line_offset_from_top: u32,
 1652    },
 1653}
 1654
 1655pub enum MultibufferSelectionMode {
 1656    First,
 1657    All,
 1658}
 1659
 1660#[derive(Clone, Copy, Debug, Default)]
 1661pub struct RewrapOptions {
 1662    pub override_language_settings: bool,
 1663    pub preserve_existing_whitespace: bool,
 1664}
 1665
 1666impl Editor {
 1667    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1668        let buffer = cx.new(|cx| Buffer::local("", cx));
 1669        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1670        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1671    }
 1672
 1673    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1674        let buffer = cx.new(|cx| Buffer::local("", cx));
 1675        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1676        Self::new(EditorMode::full(), buffer, None, window, cx)
 1677    }
 1678
 1679    pub fn auto_height(
 1680        min_lines: usize,
 1681        max_lines: usize,
 1682        window: &mut Window,
 1683        cx: &mut Context<Self>,
 1684    ) -> Self {
 1685        let buffer = cx.new(|cx| Buffer::local("", cx));
 1686        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1687        Self::new(
 1688            EditorMode::AutoHeight {
 1689                min_lines,
 1690                max_lines: Some(max_lines),
 1691            },
 1692            buffer,
 1693            None,
 1694            window,
 1695            cx,
 1696        )
 1697    }
 1698
 1699    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1700    /// The editor grows as tall as needed to fit its content.
 1701    pub fn auto_height_unbounded(
 1702        min_lines: usize,
 1703        window: &mut Window,
 1704        cx: &mut Context<Self>,
 1705    ) -> Self {
 1706        let buffer = cx.new(|cx| Buffer::local("", cx));
 1707        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1708        Self::new(
 1709            EditorMode::AutoHeight {
 1710                min_lines,
 1711                max_lines: None,
 1712            },
 1713            buffer,
 1714            None,
 1715            window,
 1716            cx,
 1717        )
 1718    }
 1719
 1720    pub fn for_buffer(
 1721        buffer: Entity<Buffer>,
 1722        project: Option<Entity<Project>>,
 1723        window: &mut Window,
 1724        cx: &mut Context<Self>,
 1725    ) -> Self {
 1726        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1727        Self::new(EditorMode::full(), buffer, project, window, cx)
 1728    }
 1729
 1730    pub fn for_multibuffer(
 1731        buffer: Entity<MultiBuffer>,
 1732        project: Option<Entity<Project>>,
 1733        window: &mut Window,
 1734        cx: &mut Context<Self>,
 1735    ) -> Self {
 1736        Self::new(EditorMode::full(), buffer, project, window, cx)
 1737    }
 1738
 1739    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1740        let mut clone = Self::new(
 1741            self.mode.clone(),
 1742            self.buffer.clone(),
 1743            self.project.clone(),
 1744            window,
 1745            cx,
 1746        );
 1747        self.display_map.update(cx, |display_map, cx| {
 1748            let snapshot = display_map.snapshot(cx);
 1749            clone.display_map.update(cx, |display_map, cx| {
 1750                display_map.set_state(&snapshot, cx);
 1751            });
 1752        });
 1753        clone.folds_did_change(cx);
 1754        clone.selections.clone_state(&self.selections);
 1755        clone.scroll_manager.clone_state(&self.scroll_manager);
 1756        clone.searchable = self.searchable;
 1757        clone.read_only = self.read_only;
 1758        clone
 1759    }
 1760
 1761    pub fn new(
 1762        mode: EditorMode,
 1763        buffer: Entity<MultiBuffer>,
 1764        project: Option<Entity<Project>>,
 1765        window: &mut Window,
 1766        cx: &mut Context<Self>,
 1767    ) -> Self {
 1768        Editor::new_internal(mode, buffer, project, None, window, cx)
 1769    }
 1770
 1771    fn new_internal(
 1772        mode: EditorMode,
 1773        buffer: Entity<MultiBuffer>,
 1774        project: Option<Entity<Project>>,
 1775        display_map: Option<Entity<DisplayMap>>,
 1776        window: &mut Window,
 1777        cx: &mut Context<Self>,
 1778    ) -> Self {
 1779        debug_assert!(
 1780            display_map.is_none() || mode.is_minimap(),
 1781            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1782        );
 1783
 1784        let full_mode = mode.is_full();
 1785        let is_minimap = mode.is_minimap();
 1786        let diagnostics_max_severity = if full_mode {
 1787            EditorSettings::get_global(cx)
 1788                .diagnostics_max_severity
 1789                .unwrap_or(DiagnosticSeverity::Hint)
 1790        } else {
 1791            DiagnosticSeverity::Off
 1792        };
 1793        let style = window.text_style();
 1794        let font_size = style.font_size.to_pixels(window.rem_size());
 1795        let editor = cx.entity().downgrade();
 1796        let fold_placeholder = FoldPlaceholder {
 1797            constrain_width: true,
 1798            render: Arc::new(move |fold_id, fold_range, cx| {
 1799                let editor = editor.clone();
 1800                div()
 1801                    .id(fold_id)
 1802                    .bg(cx.theme().colors().ghost_element_background)
 1803                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1804                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1805                    .rounded_xs()
 1806                    .size_full()
 1807                    .cursor_pointer()
 1808                    .child("")
 1809                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1810                    .on_click(move |_, _window, cx| {
 1811                        editor
 1812                            .update(cx, |editor, cx| {
 1813                                editor.unfold_ranges(
 1814                                    &[fold_range.start..fold_range.end],
 1815                                    true,
 1816                                    false,
 1817                                    cx,
 1818                                );
 1819                                cx.stop_propagation();
 1820                            })
 1821                            .ok();
 1822                    })
 1823                    .into_any()
 1824            }),
 1825            merge_adjacent: true,
 1826            ..FoldPlaceholder::default()
 1827        };
 1828        let display_map = display_map.unwrap_or_else(|| {
 1829            cx.new(|cx| {
 1830                DisplayMap::new(
 1831                    buffer.clone(),
 1832                    style.font(),
 1833                    font_size,
 1834                    None,
 1835                    FILE_HEADER_HEIGHT,
 1836                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1837                    fold_placeholder,
 1838                    diagnostics_max_severity,
 1839                    cx,
 1840                )
 1841            })
 1842        });
 1843
 1844        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1845
 1846        let blink_manager = cx.new(|cx| {
 1847            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1848            if is_minimap {
 1849                blink_manager.disable(cx);
 1850            }
 1851            blink_manager
 1852        });
 1853
 1854        let soft_wrap_mode_override =
 1855            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1856
 1857        let mut project_subscriptions = Vec::new();
 1858        if full_mode && let Some(project) = project.as_ref() {
 1859            project_subscriptions.push(cx.subscribe_in(
 1860                project,
 1861                window,
 1862                |editor, _, event, window, cx| match event {
 1863                    project::Event::RefreshCodeLens => {
 1864                        // we always query lens with actions, without storing them, always refreshing them
 1865                    }
 1866                    project::Event::RefreshInlayHints => {
 1867                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1868                    }
 1869                    project::Event::LanguageServerAdded(..)
 1870                    | project::Event::LanguageServerRemoved(..) => {
 1871                        if editor.tasks_update_task.is_none() {
 1872                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1873                        }
 1874                    }
 1875                    project::Event::SnippetEdit(id, snippet_edits) => {
 1876                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1877                            let focus_handle = editor.focus_handle(cx);
 1878                            if focus_handle.is_focused(window) {
 1879                                let snapshot = buffer.read(cx).snapshot();
 1880                                for (range, snippet) in snippet_edits {
 1881                                    let editor_range =
 1882                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1883                                    editor
 1884                                        .insert_snippet(
 1885                                            &[editor_range],
 1886                                            snippet.clone(),
 1887                                            window,
 1888                                            cx,
 1889                                        )
 1890                                        .ok();
 1891                                }
 1892                            }
 1893                        }
 1894                    }
 1895                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1896                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1897                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1898                        }
 1899                    }
 1900
 1901                    project::Event::EntryRenamed(transaction) => {
 1902                        let Some(workspace) = editor.workspace() else {
 1903                            return;
 1904                        };
 1905                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1906                        else {
 1907                            return;
 1908                        };
 1909                        if active_editor.entity_id() == cx.entity_id() {
 1910                            let edited_buffers_already_open = {
 1911                                let other_editors: Vec<Entity<Editor>> = workspace
 1912                                    .read(cx)
 1913                                    .panes()
 1914                                    .iter()
 1915                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1916                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1917                                    .collect();
 1918
 1919                                transaction.0.keys().all(|buffer| {
 1920                                    other_editors.iter().any(|editor| {
 1921                                        let multi_buffer = editor.read(cx).buffer();
 1922                                        multi_buffer.read(cx).is_singleton()
 1923                                            && multi_buffer.read(cx).as_singleton().map_or(
 1924                                                false,
 1925                                                |singleton| {
 1926                                                    singleton.entity_id() == buffer.entity_id()
 1927                                                },
 1928                                            )
 1929                                    })
 1930                                })
 1931                            };
 1932
 1933                            if !edited_buffers_already_open {
 1934                                let workspace = workspace.downgrade();
 1935                                let transaction = transaction.clone();
 1936                                cx.defer_in(window, move |_, window, cx| {
 1937                                    cx.spawn_in(window, async move |editor, cx| {
 1938                                        Self::open_project_transaction(
 1939                                            &editor,
 1940                                            workspace,
 1941                                            transaction,
 1942                                            "Rename".to_string(),
 1943                                            cx,
 1944                                        )
 1945                                        .await
 1946                                        .ok()
 1947                                    })
 1948                                    .detach();
 1949                                });
 1950                            }
 1951                        }
 1952                    }
 1953
 1954                    _ => {}
 1955                },
 1956            ));
 1957            if let Some(task_inventory) = project
 1958                .read(cx)
 1959                .task_store()
 1960                .read(cx)
 1961                .task_inventory()
 1962                .cloned()
 1963            {
 1964                project_subscriptions.push(cx.observe_in(
 1965                    &task_inventory,
 1966                    window,
 1967                    |editor, _, window, cx| {
 1968                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1969                    },
 1970                ));
 1971            };
 1972
 1973            project_subscriptions.push(cx.subscribe_in(
 1974                &project.read(cx).breakpoint_store(),
 1975                window,
 1976                |editor, _, event, window, cx| match event {
 1977                    BreakpointStoreEvent::ClearDebugLines => {
 1978                        editor.clear_row_highlights::<ActiveDebugLine>();
 1979                        editor.refresh_inline_values(cx);
 1980                    }
 1981                    BreakpointStoreEvent::SetDebugLine => {
 1982                        if editor.go_to_active_debug_line(window, cx) {
 1983                            cx.stop_propagation();
 1984                        }
 1985
 1986                        editor.refresh_inline_values(cx);
 1987                    }
 1988                    _ => {}
 1989                },
 1990            ));
 1991            let git_store = project.read(cx).git_store().clone();
 1992            let project = project.clone();
 1993            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1994                if let GitStoreEvent::RepositoryUpdated(
 1995                    _,
 1996                    RepositoryEvent::Updated {
 1997                        new_instance: true, ..
 1998                    },
 1999                    _,
 2000                ) = event
 2001                {
 2002                    this.load_diff_task = Some(
 2003                        update_uncommitted_diff_for_buffer(
 2004                            cx.entity(),
 2005                            &project,
 2006                            this.buffer.read(cx).all_buffers(),
 2007                            this.buffer.clone(),
 2008                            cx,
 2009                        )
 2010                        .shared(),
 2011                    );
 2012                }
 2013            }));
 2014        }
 2015
 2016        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2017
 2018        let inlay_hint_settings =
 2019            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2020        let focus_handle = cx.focus_handle();
 2021        if !is_minimap {
 2022            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2023                .detach();
 2024            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2025                .detach();
 2026            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2027                .detach();
 2028            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2029                .detach();
 2030            cx.observe_pending_input(window, Self::observe_pending_input)
 2031                .detach();
 2032        }
 2033
 2034        let show_indent_guides =
 2035            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2036                Some(false)
 2037            } else {
 2038                None
 2039            };
 2040
 2041        let breakpoint_store = match (&mode, project.as_ref()) {
 2042            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2043            _ => None,
 2044        };
 2045
 2046        let mut code_action_providers = Vec::new();
 2047        let mut load_uncommitted_diff = None;
 2048        if let Some(project) = project.clone() {
 2049            load_uncommitted_diff = Some(
 2050                update_uncommitted_diff_for_buffer(
 2051                    cx.entity(),
 2052                    &project,
 2053                    buffer.read(cx).all_buffers(),
 2054                    buffer.clone(),
 2055                    cx,
 2056                )
 2057                .shared(),
 2058            );
 2059            code_action_providers.push(Rc::new(project) as Rc<_>);
 2060        }
 2061
 2062        let mut editor = Self {
 2063            focus_handle,
 2064            show_cursor_when_unfocused: false,
 2065            last_focused_descendant: None,
 2066            buffer: buffer.clone(),
 2067            display_map: display_map.clone(),
 2068            selections,
 2069            scroll_manager: ScrollManager::new(cx),
 2070            columnar_selection_state: None,
 2071            add_selections_state: None,
 2072            select_next_state: None,
 2073            select_prev_state: None,
 2074            selection_history: SelectionHistory::default(),
 2075            defer_selection_effects: false,
 2076            deferred_selection_effects_state: None,
 2077            autoclose_regions: Vec::new(),
 2078            snippet_stack: InvalidationStack::default(),
 2079            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2080            ime_transaction: None,
 2081            active_diagnostics: ActiveDiagnostic::None,
 2082            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2083            inline_diagnostics_update: Task::ready(()),
 2084            inline_diagnostics: Vec::new(),
 2085            soft_wrap_mode_override,
 2086            diagnostics_max_severity,
 2087            hard_wrap: None,
 2088            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2089            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2090            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2091            project,
 2092            blink_manager: blink_manager.clone(),
 2093            show_local_selections: true,
 2094            show_scrollbars: ScrollbarAxes {
 2095                horizontal: full_mode,
 2096                vertical: full_mode,
 2097            },
 2098            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2099            offset_content: !matches!(mode, EditorMode::SingleLine),
 2100            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2101            show_gutter: full_mode,
 2102            show_line_numbers: (!full_mode).then_some(false),
 2103            use_relative_line_numbers: None,
 2104            disable_expand_excerpt_buttons: !full_mode,
 2105            show_git_diff_gutter: None,
 2106            show_code_actions: None,
 2107            show_runnables: None,
 2108            show_breakpoints: None,
 2109            show_wrap_guides: None,
 2110            show_indent_guides,
 2111            placeholder_text: None,
 2112            highlight_order: 0,
 2113            highlighted_rows: HashMap::default(),
 2114            background_highlights: HashMap::default(),
 2115            gutter_highlights: HashMap::default(),
 2116            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2117            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2118            nav_history: None,
 2119            context_menu: RefCell::new(None),
 2120            context_menu_options: None,
 2121            mouse_context_menu: None,
 2122            completion_tasks: Vec::new(),
 2123            inline_blame_popover: None,
 2124            inline_blame_popover_show_task: None,
 2125            signature_help_state: SignatureHelpState::default(),
 2126            auto_signature_help: None,
 2127            find_all_references_task_sources: Vec::new(),
 2128            next_completion_id: 0,
 2129            next_inlay_id: 0,
 2130            code_action_providers,
 2131            available_code_actions: None,
 2132            code_actions_task: None,
 2133            quick_selection_highlight_task: None,
 2134            debounced_selection_highlight_task: None,
 2135            document_highlights_task: None,
 2136            linked_editing_range_task: None,
 2137            pending_rename: None,
 2138            searchable: !is_minimap,
 2139            cursor_shape: EditorSettings::get_global(cx)
 2140                .cursor_shape
 2141                .unwrap_or_default(),
 2142            current_line_highlight: None,
 2143            autoindent_mode: Some(AutoindentMode::EachLine),
 2144            collapse_matches: false,
 2145            workspace: None,
 2146            input_enabled: !is_minimap,
 2147            use_modal_editing: full_mode,
 2148            read_only: is_minimap,
 2149            use_autoclose: true,
 2150            use_auto_surround: true,
 2151            auto_replace_emoji_shortcode: false,
 2152            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2153            leader_id: None,
 2154            remote_id: None,
 2155            hover_state: HoverState::default(),
 2156            pending_mouse_down: None,
 2157            hovered_link_state: None,
 2158            edit_prediction_provider: None,
 2159            active_edit_prediction: None,
 2160            stale_edit_prediction_in_menu: None,
 2161            edit_prediction_preview: EditPredictionPreview::Inactive {
 2162                released_too_fast: false,
 2163            },
 2164            inline_diagnostics_enabled: full_mode,
 2165            diagnostics_enabled: full_mode,
 2166            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2167            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2168            gutter_hovered: false,
 2169            pixel_position_of_newest_cursor: None,
 2170            last_bounds: None,
 2171            last_position_map: None,
 2172            expect_bounds_change: None,
 2173            gutter_dimensions: GutterDimensions::default(),
 2174            style: None,
 2175            show_cursor_names: false,
 2176            hovered_cursors: HashMap::default(),
 2177            next_editor_action_id: EditorActionId::default(),
 2178            editor_actions: Rc::default(),
 2179            edit_predictions_hidden_for_vim_mode: false,
 2180            show_edit_predictions_override: None,
 2181            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2182            edit_prediction_settings: EditPredictionSettings::Disabled,
 2183            edit_prediction_indent_conflict: false,
 2184            edit_prediction_requires_modifier_in_indent_conflict: true,
 2185            custom_context_menu: None,
 2186            show_git_blame_gutter: false,
 2187            show_git_blame_inline: false,
 2188            show_selection_menu: None,
 2189            show_git_blame_inline_delay_task: None,
 2190            git_blame_inline_enabled: full_mode
 2191                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2192            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2193            serialize_dirty_buffers: !is_minimap
 2194                && ProjectSettings::get_global(cx)
 2195                    .session
 2196                    .restore_unsaved_buffers,
 2197            blame: None,
 2198            blame_subscription: None,
 2199            tasks: BTreeMap::default(),
 2200
 2201            breakpoint_store,
 2202            gutter_breakpoint_indicator: (None, None),
 2203            hovered_diff_hunk_row: None,
 2204            _subscriptions: (!is_minimap)
 2205                .then(|| {
 2206                    vec![
 2207                        cx.observe(&buffer, Self::on_buffer_changed),
 2208                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2209                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2210                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2211                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2212                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2213                        cx.observe_window_activation(window, |editor, window, cx| {
 2214                            let active = window.is_window_active();
 2215                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2216                                if active {
 2217                                    blink_manager.enable(cx);
 2218                                } else {
 2219                                    blink_manager.disable(cx);
 2220                                }
 2221                            });
 2222                            if active {
 2223                                editor.show_mouse_cursor(cx);
 2224                            }
 2225                        }),
 2226                    ]
 2227                })
 2228                .unwrap_or_default(),
 2229            tasks_update_task: None,
 2230            pull_diagnostics_task: Task::ready(()),
 2231            colors: None,
 2232            next_color_inlay_id: 0,
 2233            linked_edit_ranges: Default::default(),
 2234            in_project_search: false,
 2235            previous_search_ranges: None,
 2236            breadcrumb_header: None,
 2237            focused_block: None,
 2238            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2239            addons: HashMap::default(),
 2240            registered_buffers: HashMap::default(),
 2241            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2242            selection_mark_mode: false,
 2243            toggle_fold_multiple_buffers: Task::ready(()),
 2244            serialize_selections: Task::ready(()),
 2245            serialize_folds: Task::ready(()),
 2246            text_style_refinement: None,
 2247            load_diff_task: load_uncommitted_diff,
 2248            temporary_diff_override: false,
 2249            mouse_cursor_hidden: false,
 2250            minimap: None,
 2251            hide_mouse_mode: EditorSettings::get_global(cx)
 2252                .hide_mouse
 2253                .unwrap_or_default(),
 2254            change_list: ChangeList::new(),
 2255            mode,
 2256            selection_drag_state: SelectionDragState::None,
 2257            folding_newlines: Task::ready(()),
 2258        };
 2259
 2260        if is_minimap {
 2261            return editor;
 2262        }
 2263
 2264        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2265            editor
 2266                ._subscriptions
 2267                .push(cx.observe(breakpoints, |_, _, cx| {
 2268                    cx.notify();
 2269                }));
 2270        }
 2271        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2272        editor._subscriptions.extend(project_subscriptions);
 2273
 2274        editor._subscriptions.push(cx.subscribe_in(
 2275            &cx.entity(),
 2276            window,
 2277            |editor, _, e: &EditorEvent, window, cx| match e {
 2278                EditorEvent::ScrollPositionChanged { local, .. } => {
 2279                    if *local {
 2280                        let new_anchor = editor.scroll_manager.anchor();
 2281                        let snapshot = editor.snapshot(window, cx);
 2282                        editor.update_restoration_data(cx, move |data| {
 2283                            data.scroll_position = (
 2284                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2285                                new_anchor.offset,
 2286                            );
 2287                        });
 2288                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2289                        editor.inline_blame_popover.take();
 2290                    }
 2291                }
 2292                EditorEvent::Edited { .. } => {
 2293                    if !vim_enabled(cx) {
 2294                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2295                        let pop_state = editor
 2296                            .change_list
 2297                            .last()
 2298                            .map(|previous| {
 2299                                previous.len() == selections.len()
 2300                                    && previous.iter().enumerate().all(|(ix, p)| {
 2301                                        p.to_display_point(&map).row()
 2302                                            == selections[ix].head().row()
 2303                                    })
 2304                            })
 2305                            .unwrap_or(false);
 2306                        let new_positions = selections
 2307                            .into_iter()
 2308                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2309                            .collect();
 2310                        editor
 2311                            .change_list
 2312                            .push_to_change_list(pop_state, new_positions);
 2313                    }
 2314                }
 2315                _ => (),
 2316            },
 2317        ));
 2318
 2319        if let Some(dap_store) = editor
 2320            .project
 2321            .as_ref()
 2322            .map(|project| project.read(cx).dap_store())
 2323        {
 2324            let weak_editor = cx.weak_entity();
 2325
 2326            editor
 2327                ._subscriptions
 2328                .push(
 2329                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2330                        let session_entity = cx.entity();
 2331                        weak_editor
 2332                            .update(cx, |editor, cx| {
 2333                                editor._subscriptions.push(
 2334                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2335                                );
 2336                            })
 2337                            .ok();
 2338                    }),
 2339                );
 2340
 2341            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2342                editor
 2343                    ._subscriptions
 2344                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2345            }
 2346        }
 2347
 2348        // skip adding the initial selection to selection history
 2349        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2350        editor.end_selection(window, cx);
 2351        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2352
 2353        editor.scroll_manager.show_scrollbars(window, cx);
 2354        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2355
 2356        if full_mode {
 2357            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2358            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2359
 2360            if editor.git_blame_inline_enabled {
 2361                editor.start_git_blame_inline(false, window, cx);
 2362            }
 2363
 2364            editor.go_to_active_debug_line(window, cx);
 2365
 2366            if let Some(buffer) = buffer.read(cx).as_singleton()
 2367                && let Some(project) = editor.project()
 2368            {
 2369                let handle = project.update(cx, |project, cx| {
 2370                    project.register_buffer_with_language_servers(&buffer, cx)
 2371                });
 2372                editor
 2373                    .registered_buffers
 2374                    .insert(buffer.read(cx).remote_id(), handle);
 2375            }
 2376
 2377            editor.minimap =
 2378                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2379            editor.colors = Some(LspColorData::new(cx));
 2380            editor.update_lsp_data(false, None, window, cx);
 2381        }
 2382
 2383        if editor.mode.is_full() {
 2384            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2385        }
 2386
 2387        editor
 2388    }
 2389
 2390    pub fn deploy_mouse_context_menu(
 2391        &mut self,
 2392        position: gpui::Point<Pixels>,
 2393        context_menu: Entity<ContextMenu>,
 2394        window: &mut Window,
 2395        cx: &mut Context<Self>,
 2396    ) {
 2397        self.mouse_context_menu = Some(MouseContextMenu::new(
 2398            self,
 2399            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2400            context_menu,
 2401            window,
 2402            cx,
 2403        ));
 2404    }
 2405
 2406    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2407        self.mouse_context_menu
 2408            .as_ref()
 2409            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2410    }
 2411
 2412    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2413        if self
 2414            .selections
 2415            .pending
 2416            .as_ref()
 2417            .is_some_and(|pending_selection| {
 2418                let snapshot = self.buffer().read(cx).snapshot(cx);
 2419                pending_selection
 2420                    .selection
 2421                    .range()
 2422                    .includes(range, &snapshot)
 2423            })
 2424        {
 2425            return true;
 2426        }
 2427
 2428        self.selections
 2429            .disjoint_in_range::<usize>(range.clone(), cx)
 2430            .into_iter()
 2431            .any(|selection| {
 2432                // This is needed to cover a corner case, if we just check for an existing
 2433                // selection in the fold range, having a cursor at the start of the fold
 2434                // marks it as selected. Non-empty selections don't cause this.
 2435                let length = selection.end - selection.start;
 2436                length > 0
 2437            })
 2438    }
 2439
 2440    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2441        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2442    }
 2443
 2444    fn key_context_internal(
 2445        &self,
 2446        has_active_edit_prediction: bool,
 2447        window: &Window,
 2448        cx: &App,
 2449    ) -> KeyContext {
 2450        let mut key_context = KeyContext::new_with_defaults();
 2451        key_context.add("Editor");
 2452        let mode = match self.mode {
 2453            EditorMode::SingleLine => "single_line",
 2454            EditorMode::AutoHeight { .. } => "auto_height",
 2455            EditorMode::Minimap { .. } => "minimap",
 2456            EditorMode::Full { .. } => "full",
 2457        };
 2458
 2459        if EditorSettings::jupyter_enabled(cx) {
 2460            key_context.add("jupyter");
 2461        }
 2462
 2463        key_context.set("mode", mode);
 2464        if self.pending_rename.is_some() {
 2465            key_context.add("renaming");
 2466        }
 2467
 2468        match self.context_menu.borrow().as_ref() {
 2469            Some(CodeContextMenu::Completions(menu)) => {
 2470                if menu.visible() {
 2471                    key_context.add("menu");
 2472                    key_context.add("showing_completions");
 2473                }
 2474            }
 2475            Some(CodeContextMenu::CodeActions(menu)) => {
 2476                if menu.visible() {
 2477                    key_context.add("menu");
 2478                    key_context.add("showing_code_actions")
 2479                }
 2480            }
 2481            None => {}
 2482        }
 2483
 2484        if self.signature_help_state.has_multiple_signatures() {
 2485            key_context.add("showing_signature_help");
 2486        }
 2487
 2488        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2489        if !self.focus_handle(cx).contains_focused(window, cx)
 2490            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2491        {
 2492            for addon in self.addons.values() {
 2493                addon.extend_key_context(&mut key_context, cx)
 2494            }
 2495        }
 2496
 2497        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2498            if let Some(extension) = singleton_buffer
 2499                .read(cx)
 2500                .file()
 2501                .and_then(|file| file.path().extension()?.to_str())
 2502            {
 2503                key_context.set("extension", extension.to_string());
 2504            }
 2505        } else {
 2506            key_context.add("multibuffer");
 2507        }
 2508
 2509        if has_active_edit_prediction {
 2510            if self.edit_prediction_in_conflict() {
 2511                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2512            } else {
 2513                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2514                key_context.add("copilot_suggestion");
 2515            }
 2516        }
 2517
 2518        if self.selection_mark_mode {
 2519            key_context.add("selection_mode");
 2520        }
 2521
 2522        key_context
 2523    }
 2524
 2525    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2526        if self.mouse_cursor_hidden {
 2527            self.mouse_cursor_hidden = false;
 2528            cx.notify();
 2529        }
 2530    }
 2531
 2532    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2533        let hide_mouse_cursor = match origin {
 2534            HideMouseCursorOrigin::TypingAction => {
 2535                matches!(
 2536                    self.hide_mouse_mode,
 2537                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2538                )
 2539            }
 2540            HideMouseCursorOrigin::MovementAction => {
 2541                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2542            }
 2543        };
 2544        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2545            self.mouse_cursor_hidden = hide_mouse_cursor;
 2546            cx.notify();
 2547        }
 2548    }
 2549
 2550    pub fn edit_prediction_in_conflict(&self) -> bool {
 2551        if !self.show_edit_predictions_in_menu() {
 2552            return false;
 2553        }
 2554
 2555        let showing_completions = self
 2556            .context_menu
 2557            .borrow()
 2558            .as_ref()
 2559            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2560
 2561        showing_completions
 2562            || self.edit_prediction_requires_modifier()
 2563            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2564            // bindings to insert tab characters.
 2565            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2566    }
 2567
 2568    pub fn accept_edit_prediction_keybind(
 2569        &self,
 2570        accept_partial: bool,
 2571        window: &Window,
 2572        cx: &App,
 2573    ) -> AcceptEditPredictionBinding {
 2574        let key_context = self.key_context_internal(true, window, cx);
 2575        let in_conflict = self.edit_prediction_in_conflict();
 2576
 2577        let bindings = if accept_partial {
 2578            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2579        } else {
 2580            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2581        };
 2582
 2583        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2584        // just the first one.
 2585        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2586            !in_conflict
 2587                || binding
 2588                    .keystrokes()
 2589                    .first()
 2590                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2591        }))
 2592    }
 2593
 2594    pub fn new_file(
 2595        workspace: &mut Workspace,
 2596        _: &workspace::NewFile,
 2597        window: &mut Window,
 2598        cx: &mut Context<Workspace>,
 2599    ) {
 2600        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2601            "Failed to create buffer",
 2602            window,
 2603            cx,
 2604            |e, _, _| match e.error_code() {
 2605                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2606                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2607                e.error_tag("required").unwrap_or("the latest version")
 2608            )),
 2609                _ => None,
 2610            },
 2611        );
 2612    }
 2613
 2614    pub fn new_in_workspace(
 2615        workspace: &mut Workspace,
 2616        window: &mut Window,
 2617        cx: &mut Context<Workspace>,
 2618    ) -> Task<Result<Entity<Editor>>> {
 2619        let project = workspace.project().clone();
 2620        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2621
 2622        cx.spawn_in(window, async move |workspace, cx| {
 2623            let buffer = create.await?;
 2624            workspace.update_in(cx, |workspace, window, cx| {
 2625                let editor =
 2626                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2627                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2628                editor
 2629            })
 2630        })
 2631    }
 2632
 2633    fn new_file_vertical(
 2634        workspace: &mut Workspace,
 2635        _: &workspace::NewFileSplitVertical,
 2636        window: &mut Window,
 2637        cx: &mut Context<Workspace>,
 2638    ) {
 2639        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2640    }
 2641
 2642    fn new_file_horizontal(
 2643        workspace: &mut Workspace,
 2644        _: &workspace::NewFileSplitHorizontal,
 2645        window: &mut Window,
 2646        cx: &mut Context<Workspace>,
 2647    ) {
 2648        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2649    }
 2650
 2651    fn new_file_in_direction(
 2652        workspace: &mut Workspace,
 2653        direction: SplitDirection,
 2654        window: &mut Window,
 2655        cx: &mut Context<Workspace>,
 2656    ) {
 2657        let project = workspace.project().clone();
 2658        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2659
 2660        cx.spawn_in(window, async move |workspace, cx| {
 2661            let buffer = create.await?;
 2662            workspace.update_in(cx, move |workspace, window, cx| {
 2663                workspace.split_item(
 2664                    direction,
 2665                    Box::new(
 2666                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2667                    ),
 2668                    window,
 2669                    cx,
 2670                )
 2671            })?;
 2672            anyhow::Ok(())
 2673        })
 2674        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2675            match e.error_code() {
 2676                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2677                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2678                e.error_tag("required").unwrap_or("the latest version")
 2679            )),
 2680                _ => None,
 2681            }
 2682        });
 2683    }
 2684
 2685    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2686        self.leader_id
 2687    }
 2688
 2689    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2690        &self.buffer
 2691    }
 2692
 2693    pub fn project(&self) -> Option<&Entity<Project>> {
 2694        self.project.as_ref()
 2695    }
 2696
 2697    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2698        self.workspace.as_ref()?.0.upgrade()
 2699    }
 2700
 2701    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2702        self.buffer().read(cx).title(cx)
 2703    }
 2704
 2705    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2706        let git_blame_gutter_max_author_length = self
 2707            .render_git_blame_gutter(cx)
 2708            .then(|| {
 2709                if let Some(blame) = self.blame.as_ref() {
 2710                    let max_author_length =
 2711                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2712                    Some(max_author_length)
 2713                } else {
 2714                    None
 2715                }
 2716            })
 2717            .flatten();
 2718
 2719        EditorSnapshot {
 2720            mode: self.mode.clone(),
 2721            show_gutter: self.show_gutter,
 2722            show_line_numbers: self.show_line_numbers,
 2723            show_git_diff_gutter: self.show_git_diff_gutter,
 2724            show_code_actions: self.show_code_actions,
 2725            show_runnables: self.show_runnables,
 2726            show_breakpoints: self.show_breakpoints,
 2727            git_blame_gutter_max_author_length,
 2728            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2729            scroll_anchor: self.scroll_manager.anchor(),
 2730            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2731            placeholder_text: self.placeholder_text.clone(),
 2732            is_focused: self.focus_handle.is_focused(window),
 2733            current_line_highlight: self
 2734                .current_line_highlight
 2735                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2736            gutter_hovered: self.gutter_hovered,
 2737        }
 2738    }
 2739
 2740    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2741        self.buffer.read(cx).language_at(point, cx)
 2742    }
 2743
 2744    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2745        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2746    }
 2747
 2748    pub fn active_excerpt(
 2749        &self,
 2750        cx: &App,
 2751    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2752        self.buffer
 2753            .read(cx)
 2754            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2755    }
 2756
 2757    pub fn mode(&self) -> &EditorMode {
 2758        &self.mode
 2759    }
 2760
 2761    pub fn set_mode(&mut self, mode: EditorMode) {
 2762        self.mode = mode;
 2763    }
 2764
 2765    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2766        self.collaboration_hub.as_deref()
 2767    }
 2768
 2769    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2770        self.collaboration_hub = Some(hub);
 2771    }
 2772
 2773    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2774        self.in_project_search = in_project_search;
 2775    }
 2776
 2777    pub fn set_custom_context_menu(
 2778        &mut self,
 2779        f: impl 'static
 2780        + Fn(
 2781            &mut Self,
 2782            DisplayPoint,
 2783            &mut Window,
 2784            &mut Context<Self>,
 2785        ) -> Option<Entity<ui::ContextMenu>>,
 2786    ) {
 2787        self.custom_context_menu = Some(Box::new(f))
 2788    }
 2789
 2790    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2791        self.completion_provider = provider;
 2792    }
 2793
 2794    #[cfg(any(test, feature = "test-support"))]
 2795    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2796        self.completion_provider.clone()
 2797    }
 2798
 2799    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2800        self.semantics_provider.clone()
 2801    }
 2802
 2803    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2804        self.semantics_provider = provider;
 2805    }
 2806
 2807    pub fn set_edit_prediction_provider<T>(
 2808        &mut self,
 2809        provider: Option<Entity<T>>,
 2810        window: &mut Window,
 2811        cx: &mut Context<Self>,
 2812    ) where
 2813        T: EditPredictionProvider,
 2814    {
 2815        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2816            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2817                if this.focus_handle.is_focused(window) {
 2818                    this.update_visible_edit_prediction(window, cx);
 2819                }
 2820            }),
 2821            provider: Arc::new(provider),
 2822        });
 2823        self.update_edit_prediction_settings(cx);
 2824        self.refresh_edit_prediction(false, false, window, cx);
 2825    }
 2826
 2827    pub fn placeholder_text(&self) -> Option<&str> {
 2828        self.placeholder_text.as_deref()
 2829    }
 2830
 2831    pub fn set_placeholder_text(
 2832        &mut self,
 2833        placeholder_text: impl Into<Arc<str>>,
 2834        cx: &mut Context<Self>,
 2835    ) {
 2836        let placeholder_text = Some(placeholder_text.into());
 2837        if self.placeholder_text != placeholder_text {
 2838            self.placeholder_text = placeholder_text;
 2839            cx.notify();
 2840        }
 2841    }
 2842
 2843    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2844        self.cursor_shape = cursor_shape;
 2845
 2846        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2847        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2848
 2849        cx.notify();
 2850    }
 2851
 2852    pub fn set_current_line_highlight(
 2853        &mut self,
 2854        current_line_highlight: Option<CurrentLineHighlight>,
 2855    ) {
 2856        self.current_line_highlight = current_line_highlight;
 2857    }
 2858
 2859    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2860        self.collapse_matches = collapse_matches;
 2861    }
 2862
 2863    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2864        let buffers = self.buffer.read(cx).all_buffers();
 2865        let Some(project) = self.project.as_ref() else {
 2866            return;
 2867        };
 2868        project.update(cx, |project, cx| {
 2869            for buffer in buffers {
 2870                self.registered_buffers
 2871                    .entry(buffer.read(cx).remote_id())
 2872                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2873            }
 2874        })
 2875    }
 2876
 2877    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2878        if self.collapse_matches {
 2879            return range.start..range.start;
 2880        }
 2881        range.clone()
 2882    }
 2883
 2884    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2885        if self.display_map.read(cx).clip_at_line_ends != clip {
 2886            self.display_map
 2887                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2888        }
 2889    }
 2890
 2891    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2892        self.input_enabled = input_enabled;
 2893    }
 2894
 2895    pub fn set_edit_predictions_hidden_for_vim_mode(
 2896        &mut self,
 2897        hidden: bool,
 2898        window: &mut Window,
 2899        cx: &mut Context<Self>,
 2900    ) {
 2901        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2902            self.edit_predictions_hidden_for_vim_mode = hidden;
 2903            if hidden {
 2904                self.update_visible_edit_prediction(window, cx);
 2905            } else {
 2906                self.refresh_edit_prediction(true, false, window, cx);
 2907            }
 2908        }
 2909    }
 2910
 2911    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2912        self.menu_edit_predictions_policy = value;
 2913    }
 2914
 2915    pub fn set_autoindent(&mut self, autoindent: bool) {
 2916        if autoindent {
 2917            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2918        } else {
 2919            self.autoindent_mode = None;
 2920        }
 2921    }
 2922
 2923    pub fn read_only(&self, cx: &App) -> bool {
 2924        self.read_only || self.buffer.read(cx).read_only()
 2925    }
 2926
 2927    pub fn set_read_only(&mut self, read_only: bool) {
 2928        self.read_only = read_only;
 2929    }
 2930
 2931    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2932        self.use_autoclose = autoclose;
 2933    }
 2934
 2935    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2936        self.use_auto_surround = auto_surround;
 2937    }
 2938
 2939    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2940        self.auto_replace_emoji_shortcode = auto_replace;
 2941    }
 2942
 2943    pub fn toggle_edit_predictions(
 2944        &mut self,
 2945        _: &ToggleEditPrediction,
 2946        window: &mut Window,
 2947        cx: &mut Context<Self>,
 2948    ) {
 2949        if self.show_edit_predictions_override.is_some() {
 2950            self.set_show_edit_predictions(None, window, cx);
 2951        } else {
 2952            let show_edit_predictions = !self.edit_predictions_enabled();
 2953            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2954        }
 2955    }
 2956
 2957    pub fn set_show_edit_predictions(
 2958        &mut self,
 2959        show_edit_predictions: Option<bool>,
 2960        window: &mut Window,
 2961        cx: &mut Context<Self>,
 2962    ) {
 2963        self.show_edit_predictions_override = show_edit_predictions;
 2964        self.update_edit_prediction_settings(cx);
 2965
 2966        if let Some(false) = show_edit_predictions {
 2967            self.discard_edit_prediction(false, cx);
 2968        } else {
 2969            self.refresh_edit_prediction(false, true, window, cx);
 2970        }
 2971    }
 2972
 2973    fn edit_predictions_disabled_in_scope(
 2974        &self,
 2975        buffer: &Entity<Buffer>,
 2976        buffer_position: language::Anchor,
 2977        cx: &App,
 2978    ) -> bool {
 2979        let snapshot = buffer.read(cx).snapshot();
 2980        let settings = snapshot.settings_at(buffer_position, cx);
 2981
 2982        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2983            return false;
 2984        };
 2985
 2986        scope.override_name().is_some_and(|scope_name| {
 2987            settings
 2988                .edit_predictions_disabled_in
 2989                .iter()
 2990                .any(|s| s == scope_name)
 2991        })
 2992    }
 2993
 2994    pub fn set_use_modal_editing(&mut self, to: bool) {
 2995        self.use_modal_editing = to;
 2996    }
 2997
 2998    pub fn use_modal_editing(&self) -> bool {
 2999        self.use_modal_editing
 3000    }
 3001
 3002    fn selections_did_change(
 3003        &mut self,
 3004        local: bool,
 3005        old_cursor_position: &Anchor,
 3006        effects: SelectionEffects,
 3007        window: &mut Window,
 3008        cx: &mut Context<Self>,
 3009    ) {
 3010        window.invalidate_character_coordinates();
 3011
 3012        // Copy selections to primary selection buffer
 3013        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3014        if local {
 3015            let selections = self.selections.all::<usize>(cx);
 3016            let buffer_handle = self.buffer.read(cx).read(cx);
 3017
 3018            let mut text = String::new();
 3019            for (index, selection) in selections.iter().enumerate() {
 3020                let text_for_selection = buffer_handle
 3021                    .text_for_range(selection.start..selection.end)
 3022                    .collect::<String>();
 3023
 3024                text.push_str(&text_for_selection);
 3025                if index != selections.len() - 1 {
 3026                    text.push('\n');
 3027                }
 3028            }
 3029
 3030            if !text.is_empty() {
 3031                cx.write_to_primary(ClipboardItem::new_string(text));
 3032            }
 3033        }
 3034
 3035        let selection_anchors = self.selections.disjoint_anchors();
 3036
 3037        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3038            self.buffer.update(cx, |buffer, cx| {
 3039                buffer.set_active_selections(
 3040                    &selection_anchors,
 3041                    self.selections.line_mode,
 3042                    self.cursor_shape,
 3043                    cx,
 3044                )
 3045            });
 3046        }
 3047        let display_map = self
 3048            .display_map
 3049            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3050        let buffer = &display_map.buffer_snapshot;
 3051        if self.selections.count() == 1 {
 3052            self.add_selections_state = None;
 3053        }
 3054        self.select_next_state = None;
 3055        self.select_prev_state = None;
 3056        self.select_syntax_node_history.try_clear();
 3057        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3058        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3059        self.take_rename(false, window, cx);
 3060
 3061        let newest_selection = self.selections.newest_anchor();
 3062        let new_cursor_position = newest_selection.head();
 3063        let selection_start = newest_selection.start;
 3064
 3065        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3066            self.push_to_nav_history(
 3067                *old_cursor_position,
 3068                Some(new_cursor_position.to_point(buffer)),
 3069                false,
 3070                effects.nav_history == Some(true),
 3071                cx,
 3072            );
 3073        }
 3074
 3075        if local {
 3076            if let Some(buffer_id) = new_cursor_position.buffer_id
 3077                && !self.registered_buffers.contains_key(&buffer_id)
 3078                && let Some(project) = self.project.as_ref()
 3079            {
 3080                project.update(cx, |project, cx| {
 3081                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3082                        return;
 3083                    };
 3084                    self.registered_buffers.insert(
 3085                        buffer_id,
 3086                        project.register_buffer_with_language_servers(&buffer, cx),
 3087                    );
 3088                })
 3089            }
 3090
 3091            let mut context_menu = self.context_menu.borrow_mut();
 3092            let completion_menu = match context_menu.as_ref() {
 3093                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3094                Some(CodeContextMenu::CodeActions(_)) => {
 3095                    *context_menu = None;
 3096                    None
 3097                }
 3098                None => None,
 3099            };
 3100            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3101            drop(context_menu);
 3102
 3103            if effects.completions
 3104                && let Some(completion_position) = completion_position
 3105            {
 3106                let start_offset = selection_start.to_offset(buffer);
 3107                let position_matches = start_offset == completion_position.to_offset(buffer);
 3108                let continue_showing = if position_matches {
 3109                    if self.snippet_stack.is_empty() {
 3110                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3111                    } else {
 3112                        // Snippet choices can be shown even when the cursor is in whitespace.
 3113                        // Dismissing the menu with actions like backspace is handled by
 3114                        // invalidation regions.
 3115                        true
 3116                    }
 3117                } else {
 3118                    false
 3119                };
 3120
 3121                if continue_showing {
 3122                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3123                } else {
 3124                    self.hide_context_menu(window, cx);
 3125                }
 3126            }
 3127
 3128            hide_hover(self, cx);
 3129
 3130            if old_cursor_position.to_display_point(&display_map).row()
 3131                != new_cursor_position.to_display_point(&display_map).row()
 3132            {
 3133                self.available_code_actions.take();
 3134            }
 3135            self.refresh_code_actions(window, cx);
 3136            self.refresh_document_highlights(cx);
 3137            self.refresh_selected_text_highlights(false, window, cx);
 3138            refresh_matching_bracket_highlights(self, window, cx);
 3139            self.update_visible_edit_prediction(window, cx);
 3140            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3141            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3142            self.inline_blame_popover.take();
 3143            if self.git_blame_inline_enabled {
 3144                self.start_inline_blame_timer(window, cx);
 3145            }
 3146        }
 3147
 3148        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3149        cx.emit(EditorEvent::SelectionsChanged { local });
 3150
 3151        let selections = &self.selections.disjoint;
 3152        if selections.len() == 1 {
 3153            cx.emit(SearchEvent::ActiveMatchChanged)
 3154        }
 3155        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3156            let inmemory_selections = selections
 3157                .iter()
 3158                .map(|s| {
 3159                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3160                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3161                })
 3162                .collect();
 3163            self.update_restoration_data(cx, |data| {
 3164                data.selections = inmemory_selections;
 3165            });
 3166
 3167            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3168                && let Some(workspace_id) =
 3169                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3170            {
 3171                let snapshot = self.buffer().read(cx).snapshot(cx);
 3172                let selections = selections.clone();
 3173                let background_executor = cx.background_executor().clone();
 3174                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3175                self.serialize_selections = cx.background_spawn(async move {
 3176                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3177                            let db_selections = selections
 3178                                .iter()
 3179                                .map(|selection| {
 3180                                    (
 3181                                        selection.start.to_offset(&snapshot),
 3182                                        selection.end.to_offset(&snapshot),
 3183                                    )
 3184                                })
 3185                                .collect();
 3186
 3187                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3188                                .await
 3189                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3190                                .log_err();
 3191                        });
 3192            }
 3193        }
 3194
 3195        cx.notify();
 3196    }
 3197
 3198    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3199        use text::ToOffset as _;
 3200        use text::ToPoint as _;
 3201
 3202        if self.mode.is_minimap()
 3203            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3204        {
 3205            return;
 3206        }
 3207
 3208        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3209            return;
 3210        };
 3211
 3212        let snapshot = singleton.read(cx).snapshot();
 3213        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3214            let display_snapshot = display_map.snapshot(cx);
 3215
 3216            display_snapshot
 3217                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3218                .map(|fold| {
 3219                    fold.range.start.text_anchor.to_point(&snapshot)
 3220                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3221                })
 3222                .collect()
 3223        });
 3224        self.update_restoration_data(cx, |data| {
 3225            data.folds = inmemory_folds;
 3226        });
 3227
 3228        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3229            return;
 3230        };
 3231        let background_executor = cx.background_executor().clone();
 3232        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3233        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3234            display_map
 3235                .snapshot(cx)
 3236                .folds_in_range(0..snapshot.len())
 3237                .map(|fold| {
 3238                    (
 3239                        fold.range.start.text_anchor.to_offset(&snapshot),
 3240                        fold.range.end.text_anchor.to_offset(&snapshot),
 3241                    )
 3242                })
 3243                .collect()
 3244        });
 3245        self.serialize_folds = cx.background_spawn(async move {
 3246            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3247            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3248                .await
 3249                .with_context(|| {
 3250                    format!(
 3251                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3252                    )
 3253                })
 3254                .log_err();
 3255        });
 3256    }
 3257
 3258    pub fn sync_selections(
 3259        &mut self,
 3260        other: Entity<Editor>,
 3261        cx: &mut Context<Self>,
 3262    ) -> gpui::Subscription {
 3263        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3264        self.selections.change_with(cx, |selections| {
 3265            selections.select_anchors(other_selections);
 3266        });
 3267
 3268        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3269            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3270                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3271                if other_selections.is_empty() {
 3272                    return;
 3273                }
 3274                this.selections.change_with(cx, |selections| {
 3275                    selections.select_anchors(other_selections);
 3276                });
 3277            }
 3278        });
 3279
 3280        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3281            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3282                let these_selections = this.selections.disjoint.to_vec();
 3283                if these_selections.is_empty() {
 3284                    return;
 3285                }
 3286                other.update(cx, |other_editor, cx| {
 3287                    other_editor.selections.change_with(cx, |selections| {
 3288                        selections.select_anchors(these_selections);
 3289                    })
 3290                });
 3291            }
 3292        });
 3293
 3294        Subscription::join(other_subscription, this_subscription)
 3295    }
 3296
 3297    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3298    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3299    /// effects of selection change occur at the end of the transaction.
 3300    pub fn change_selections<R>(
 3301        &mut self,
 3302        effects: SelectionEffects,
 3303        window: &mut Window,
 3304        cx: &mut Context<Self>,
 3305        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3306    ) -> R {
 3307        if let Some(state) = &mut self.deferred_selection_effects_state {
 3308            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3309            state.effects.completions = effects.completions;
 3310            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3311            let (changed, result) = self.selections.change_with(cx, change);
 3312            state.changed |= changed;
 3313            return result;
 3314        }
 3315        let mut state = DeferredSelectionEffectsState {
 3316            changed: false,
 3317            effects,
 3318            old_cursor_position: self.selections.newest_anchor().head(),
 3319            history_entry: SelectionHistoryEntry {
 3320                selections: self.selections.disjoint_anchors(),
 3321                select_next_state: self.select_next_state.clone(),
 3322                select_prev_state: self.select_prev_state.clone(),
 3323                add_selections_state: self.add_selections_state.clone(),
 3324            },
 3325        };
 3326        let (changed, result) = self.selections.change_with(cx, change);
 3327        state.changed = state.changed || changed;
 3328        if self.defer_selection_effects {
 3329            self.deferred_selection_effects_state = Some(state);
 3330        } else {
 3331            self.apply_selection_effects(state, window, cx);
 3332        }
 3333        result
 3334    }
 3335
 3336    /// Defers the effects of selection change, so that the effects of multiple calls to
 3337    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3338    /// to selection history and the state of popovers based on selection position aren't
 3339    /// erroneously updated.
 3340    pub fn with_selection_effects_deferred<R>(
 3341        &mut self,
 3342        window: &mut Window,
 3343        cx: &mut Context<Self>,
 3344        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3345    ) -> R {
 3346        let already_deferred = self.defer_selection_effects;
 3347        self.defer_selection_effects = true;
 3348        let result = update(self, window, cx);
 3349        if !already_deferred {
 3350            self.defer_selection_effects = false;
 3351            if let Some(state) = self.deferred_selection_effects_state.take() {
 3352                self.apply_selection_effects(state, window, cx);
 3353            }
 3354        }
 3355        result
 3356    }
 3357
 3358    fn apply_selection_effects(
 3359        &mut self,
 3360        state: DeferredSelectionEffectsState,
 3361        window: &mut Window,
 3362        cx: &mut Context<Self>,
 3363    ) {
 3364        if state.changed {
 3365            self.selection_history.push(state.history_entry);
 3366
 3367            if let Some(autoscroll) = state.effects.scroll {
 3368                self.request_autoscroll(autoscroll, cx);
 3369            }
 3370
 3371            let old_cursor_position = &state.old_cursor_position;
 3372
 3373            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3374
 3375            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3376                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3377            }
 3378        }
 3379    }
 3380
 3381    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3382    where
 3383        I: IntoIterator<Item = (Range<S>, T)>,
 3384        S: ToOffset,
 3385        T: Into<Arc<str>>,
 3386    {
 3387        if self.read_only(cx) {
 3388            return;
 3389        }
 3390
 3391        self.buffer
 3392            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3393    }
 3394
 3395    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3396    where
 3397        I: IntoIterator<Item = (Range<S>, T)>,
 3398        S: ToOffset,
 3399        T: Into<Arc<str>>,
 3400    {
 3401        if self.read_only(cx) {
 3402            return;
 3403        }
 3404
 3405        self.buffer.update(cx, |buffer, cx| {
 3406            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3407        });
 3408    }
 3409
 3410    pub fn edit_with_block_indent<I, S, T>(
 3411        &mut self,
 3412        edits: I,
 3413        original_indent_columns: Vec<Option<u32>>,
 3414        cx: &mut Context<Self>,
 3415    ) where
 3416        I: IntoIterator<Item = (Range<S>, T)>,
 3417        S: ToOffset,
 3418        T: Into<Arc<str>>,
 3419    {
 3420        if self.read_only(cx) {
 3421            return;
 3422        }
 3423
 3424        self.buffer.update(cx, |buffer, cx| {
 3425            buffer.edit(
 3426                edits,
 3427                Some(AutoindentMode::Block {
 3428                    original_indent_columns,
 3429                }),
 3430                cx,
 3431            )
 3432        });
 3433    }
 3434
 3435    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3436        self.hide_context_menu(window, cx);
 3437
 3438        match phase {
 3439            SelectPhase::Begin {
 3440                position,
 3441                add,
 3442                click_count,
 3443            } => self.begin_selection(position, add, click_count, window, cx),
 3444            SelectPhase::BeginColumnar {
 3445                position,
 3446                goal_column,
 3447                reset,
 3448                mode,
 3449            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3450            SelectPhase::Extend {
 3451                position,
 3452                click_count,
 3453            } => self.extend_selection(position, click_count, window, cx),
 3454            SelectPhase::Update {
 3455                position,
 3456                goal_column,
 3457                scroll_delta,
 3458            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3459            SelectPhase::End => self.end_selection(window, cx),
 3460        }
 3461    }
 3462
 3463    fn extend_selection(
 3464        &mut self,
 3465        position: DisplayPoint,
 3466        click_count: usize,
 3467        window: &mut Window,
 3468        cx: &mut Context<Self>,
 3469    ) {
 3470        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3471        let tail = self.selections.newest::<usize>(cx).tail();
 3472        self.begin_selection(position, false, click_count, window, cx);
 3473
 3474        let position = position.to_offset(&display_map, Bias::Left);
 3475        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3476
 3477        let mut pending_selection = self
 3478            .selections
 3479            .pending_anchor()
 3480            .expect("extend_selection not called with pending selection");
 3481        if position >= tail {
 3482            pending_selection.start = tail_anchor;
 3483        } else {
 3484            pending_selection.end = tail_anchor;
 3485            pending_selection.reversed = true;
 3486        }
 3487
 3488        let mut pending_mode = self.selections.pending_mode().unwrap();
 3489        match &mut pending_mode {
 3490            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3491            _ => {}
 3492        }
 3493
 3494        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3495            SelectionEffects::scroll(Autoscroll::fit())
 3496        } else {
 3497            SelectionEffects::no_scroll()
 3498        };
 3499
 3500        self.change_selections(effects, window, cx, |s| {
 3501            s.set_pending(pending_selection, pending_mode)
 3502        });
 3503    }
 3504
 3505    fn begin_selection(
 3506        &mut self,
 3507        position: DisplayPoint,
 3508        add: bool,
 3509        click_count: usize,
 3510        window: &mut Window,
 3511        cx: &mut Context<Self>,
 3512    ) {
 3513        if !self.focus_handle.is_focused(window) {
 3514            self.last_focused_descendant = None;
 3515            window.focus(&self.focus_handle);
 3516        }
 3517
 3518        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3519        let buffer = &display_map.buffer_snapshot;
 3520        let position = display_map.clip_point(position, Bias::Left);
 3521
 3522        let start;
 3523        let end;
 3524        let mode;
 3525        let mut auto_scroll;
 3526        match click_count {
 3527            1 => {
 3528                start = buffer.anchor_before(position.to_point(&display_map));
 3529                end = start;
 3530                mode = SelectMode::Character;
 3531                auto_scroll = true;
 3532            }
 3533            2 => {
 3534                let position = display_map
 3535                    .clip_point(position, Bias::Left)
 3536                    .to_offset(&display_map, Bias::Left);
 3537                let (range, _) = buffer.surrounding_word(position, false);
 3538                start = buffer.anchor_before(range.start);
 3539                end = buffer.anchor_before(range.end);
 3540                mode = SelectMode::Word(start..end);
 3541                auto_scroll = true;
 3542            }
 3543            3 => {
 3544                let position = display_map
 3545                    .clip_point(position, Bias::Left)
 3546                    .to_point(&display_map);
 3547                let line_start = display_map.prev_line_boundary(position).0;
 3548                let next_line_start = buffer.clip_point(
 3549                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3550                    Bias::Left,
 3551                );
 3552                start = buffer.anchor_before(line_start);
 3553                end = buffer.anchor_before(next_line_start);
 3554                mode = SelectMode::Line(start..end);
 3555                auto_scroll = true;
 3556            }
 3557            _ => {
 3558                start = buffer.anchor_before(0);
 3559                end = buffer.anchor_before(buffer.len());
 3560                mode = SelectMode::All;
 3561                auto_scroll = false;
 3562            }
 3563        }
 3564        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3565
 3566        let point_to_delete: Option<usize> = {
 3567            let selected_points: Vec<Selection<Point>> =
 3568                self.selections.disjoint_in_range(start..end, cx);
 3569
 3570            if !add || click_count > 1 {
 3571                None
 3572            } else if !selected_points.is_empty() {
 3573                Some(selected_points[0].id)
 3574            } else {
 3575                let clicked_point_already_selected =
 3576                    self.selections.disjoint.iter().find(|selection| {
 3577                        selection.start.to_point(buffer) == start.to_point(buffer)
 3578                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3579                    });
 3580
 3581                clicked_point_already_selected.map(|selection| selection.id)
 3582            }
 3583        };
 3584
 3585        let selections_count = self.selections.count();
 3586        let effects = if auto_scroll {
 3587            SelectionEffects::default()
 3588        } else {
 3589            SelectionEffects::no_scroll()
 3590        };
 3591
 3592        self.change_selections(effects, window, cx, |s| {
 3593            if let Some(point_to_delete) = point_to_delete {
 3594                s.delete(point_to_delete);
 3595
 3596                if selections_count == 1 {
 3597                    s.set_pending_anchor_range(start..end, mode);
 3598                }
 3599            } else {
 3600                if !add {
 3601                    s.clear_disjoint();
 3602                }
 3603
 3604                s.set_pending_anchor_range(start..end, mode);
 3605            }
 3606        });
 3607    }
 3608
 3609    fn begin_columnar_selection(
 3610        &mut self,
 3611        position: DisplayPoint,
 3612        goal_column: u32,
 3613        reset: bool,
 3614        mode: ColumnarMode,
 3615        window: &mut Window,
 3616        cx: &mut Context<Self>,
 3617    ) {
 3618        if !self.focus_handle.is_focused(window) {
 3619            self.last_focused_descendant = None;
 3620            window.focus(&self.focus_handle);
 3621        }
 3622
 3623        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3624
 3625        if reset {
 3626            let pointer_position = display_map
 3627                .buffer_snapshot
 3628                .anchor_before(position.to_point(&display_map));
 3629
 3630            self.change_selections(
 3631                SelectionEffects::scroll(Autoscroll::newest()),
 3632                window,
 3633                cx,
 3634                |s| {
 3635                    s.clear_disjoint();
 3636                    s.set_pending_anchor_range(
 3637                        pointer_position..pointer_position,
 3638                        SelectMode::Character,
 3639                    );
 3640                },
 3641            );
 3642        };
 3643
 3644        let tail = self.selections.newest::<Point>(cx).tail();
 3645        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3646        self.columnar_selection_state = match mode {
 3647            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3648                selection_tail: selection_anchor,
 3649                display_point: if reset {
 3650                    if position.column() != goal_column {
 3651                        Some(DisplayPoint::new(position.row(), goal_column))
 3652                    } else {
 3653                        None
 3654                    }
 3655                } else {
 3656                    None
 3657                },
 3658            }),
 3659            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3660                selection_tail: selection_anchor,
 3661            }),
 3662        };
 3663
 3664        if !reset {
 3665            self.select_columns(position, goal_column, &display_map, window, cx);
 3666        }
 3667    }
 3668
 3669    fn update_selection(
 3670        &mut self,
 3671        position: DisplayPoint,
 3672        goal_column: u32,
 3673        scroll_delta: gpui::Point<f32>,
 3674        window: &mut Window,
 3675        cx: &mut Context<Self>,
 3676    ) {
 3677        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3678
 3679        if self.columnar_selection_state.is_some() {
 3680            self.select_columns(position, goal_column, &display_map, window, cx);
 3681        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3682            let buffer = &display_map.buffer_snapshot;
 3683            let head;
 3684            let tail;
 3685            let mode = self.selections.pending_mode().unwrap();
 3686            match &mode {
 3687                SelectMode::Character => {
 3688                    head = position.to_point(&display_map);
 3689                    tail = pending.tail().to_point(buffer);
 3690                }
 3691                SelectMode::Word(original_range) => {
 3692                    let offset = display_map
 3693                        .clip_point(position, Bias::Left)
 3694                        .to_offset(&display_map, Bias::Left);
 3695                    let original_range = original_range.to_offset(buffer);
 3696
 3697                    let head_offset = if buffer.is_inside_word(offset, false)
 3698                        || original_range.contains(&offset)
 3699                    {
 3700                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3701                        if word_range.start < original_range.start {
 3702                            word_range.start
 3703                        } else {
 3704                            word_range.end
 3705                        }
 3706                    } else {
 3707                        offset
 3708                    };
 3709
 3710                    head = head_offset.to_point(buffer);
 3711                    if head_offset <= original_range.start {
 3712                        tail = original_range.end.to_point(buffer);
 3713                    } else {
 3714                        tail = original_range.start.to_point(buffer);
 3715                    }
 3716                }
 3717                SelectMode::Line(original_range) => {
 3718                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3719
 3720                    let position = display_map
 3721                        .clip_point(position, Bias::Left)
 3722                        .to_point(&display_map);
 3723                    let line_start = display_map.prev_line_boundary(position).0;
 3724                    let next_line_start = buffer.clip_point(
 3725                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3726                        Bias::Left,
 3727                    );
 3728
 3729                    if line_start < original_range.start {
 3730                        head = line_start
 3731                    } else {
 3732                        head = next_line_start
 3733                    }
 3734
 3735                    if head <= original_range.start {
 3736                        tail = original_range.end;
 3737                    } else {
 3738                        tail = original_range.start;
 3739                    }
 3740                }
 3741                SelectMode::All => {
 3742                    return;
 3743                }
 3744            };
 3745
 3746            if head < tail {
 3747                pending.start = buffer.anchor_before(head);
 3748                pending.end = buffer.anchor_before(tail);
 3749                pending.reversed = true;
 3750            } else {
 3751                pending.start = buffer.anchor_before(tail);
 3752                pending.end = buffer.anchor_before(head);
 3753                pending.reversed = false;
 3754            }
 3755
 3756            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3757                s.set_pending(pending, mode);
 3758            });
 3759        } else {
 3760            log::error!("update_selection dispatched with no pending selection");
 3761            return;
 3762        }
 3763
 3764        self.apply_scroll_delta(scroll_delta, window, cx);
 3765        cx.notify();
 3766    }
 3767
 3768    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3769        self.columnar_selection_state.take();
 3770        if self.selections.pending_anchor().is_some() {
 3771            let selections = self.selections.all::<usize>(cx);
 3772            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3773                s.select(selections);
 3774                s.clear_pending();
 3775            });
 3776        }
 3777    }
 3778
 3779    fn select_columns(
 3780        &mut self,
 3781        head: DisplayPoint,
 3782        goal_column: u32,
 3783        display_map: &DisplaySnapshot,
 3784        window: &mut Window,
 3785        cx: &mut Context<Self>,
 3786    ) {
 3787        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3788            return;
 3789        };
 3790
 3791        let tail = match columnar_state {
 3792            ColumnarSelectionState::FromMouse {
 3793                selection_tail,
 3794                display_point,
 3795            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3796            ColumnarSelectionState::FromSelection { selection_tail } => {
 3797                selection_tail.to_display_point(display_map)
 3798            }
 3799        };
 3800
 3801        let start_row = cmp::min(tail.row(), head.row());
 3802        let end_row = cmp::max(tail.row(), head.row());
 3803        let start_column = cmp::min(tail.column(), goal_column);
 3804        let end_column = cmp::max(tail.column(), goal_column);
 3805        let reversed = start_column < tail.column();
 3806
 3807        let selection_ranges = (start_row.0..=end_row.0)
 3808            .map(DisplayRow)
 3809            .filter_map(|row| {
 3810                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3811                    || start_column <= display_map.line_len(row))
 3812                    && !display_map.is_block_line(row)
 3813                {
 3814                    let start = display_map
 3815                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3816                        .to_point(display_map);
 3817                    let end = display_map
 3818                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3819                        .to_point(display_map);
 3820                    if reversed {
 3821                        Some(end..start)
 3822                    } else {
 3823                        Some(start..end)
 3824                    }
 3825                } else {
 3826                    None
 3827                }
 3828            })
 3829            .collect::<Vec<_>>();
 3830
 3831        let ranges = match columnar_state {
 3832            ColumnarSelectionState::FromMouse { .. } => {
 3833                let mut non_empty_ranges = selection_ranges
 3834                    .iter()
 3835                    .filter(|selection_range| selection_range.start != selection_range.end)
 3836                    .peekable();
 3837                if non_empty_ranges.peek().is_some() {
 3838                    non_empty_ranges.cloned().collect()
 3839                } else {
 3840                    selection_ranges
 3841                }
 3842            }
 3843            _ => selection_ranges,
 3844        };
 3845
 3846        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3847            s.select_ranges(ranges);
 3848        });
 3849        cx.notify();
 3850    }
 3851
 3852    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3853        self.selections
 3854            .all_adjusted(cx)
 3855            .iter()
 3856            .any(|selection| !selection.is_empty())
 3857    }
 3858
 3859    pub fn has_pending_nonempty_selection(&self) -> bool {
 3860        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3861            Some(Selection { start, end, .. }) => start != end,
 3862            None => false,
 3863        };
 3864
 3865        pending_nonempty_selection
 3866            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3867    }
 3868
 3869    pub fn has_pending_selection(&self) -> bool {
 3870        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3871    }
 3872
 3873    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3874        self.selection_mark_mode = false;
 3875        self.selection_drag_state = SelectionDragState::None;
 3876
 3877        if self.clear_expanded_diff_hunks(cx) {
 3878            cx.notify();
 3879            return;
 3880        }
 3881        if self.dismiss_menus_and_popups(true, window, cx) {
 3882            return;
 3883        }
 3884
 3885        if self.mode.is_full()
 3886            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3887        {
 3888            return;
 3889        }
 3890
 3891        cx.propagate();
 3892    }
 3893
 3894    pub fn dismiss_menus_and_popups(
 3895        &mut self,
 3896        is_user_requested: bool,
 3897        window: &mut Window,
 3898        cx: &mut Context<Self>,
 3899    ) -> bool {
 3900        if self.take_rename(false, window, cx).is_some() {
 3901            return true;
 3902        }
 3903
 3904        if hide_hover(self, cx) {
 3905            return true;
 3906        }
 3907
 3908        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3909            return true;
 3910        }
 3911
 3912        if self.hide_context_menu(window, cx).is_some() {
 3913            return true;
 3914        }
 3915
 3916        if self.mouse_context_menu.take().is_some() {
 3917            return true;
 3918        }
 3919
 3920        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3921            return true;
 3922        }
 3923
 3924        if self.snippet_stack.pop().is_some() {
 3925            return true;
 3926        }
 3927
 3928        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3929            self.dismiss_diagnostics(cx);
 3930            return true;
 3931        }
 3932
 3933        false
 3934    }
 3935
 3936    fn linked_editing_ranges_for(
 3937        &self,
 3938        selection: Range<text::Anchor>,
 3939        cx: &App,
 3940    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3941        if self.linked_edit_ranges.is_empty() {
 3942            return None;
 3943        }
 3944        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3945            selection.end.buffer_id.and_then(|end_buffer_id| {
 3946                if selection.start.buffer_id != Some(end_buffer_id) {
 3947                    return None;
 3948                }
 3949                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3950                let snapshot = buffer.read(cx).snapshot();
 3951                self.linked_edit_ranges
 3952                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3953                    .map(|ranges| (ranges, snapshot, buffer))
 3954            })?;
 3955        use text::ToOffset as TO;
 3956        // find offset from the start of current range to current cursor position
 3957        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3958
 3959        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3960        let start_difference = start_offset - start_byte_offset;
 3961        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3962        let end_difference = end_offset - start_byte_offset;
 3963        // Current range has associated linked ranges.
 3964        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3965        for range in linked_ranges.iter() {
 3966            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3967            let end_offset = start_offset + end_difference;
 3968            let start_offset = start_offset + start_difference;
 3969            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3970                continue;
 3971            }
 3972            if self.selections.disjoint_anchor_ranges().any(|s| {
 3973                if s.start.buffer_id != selection.start.buffer_id
 3974                    || s.end.buffer_id != selection.end.buffer_id
 3975                {
 3976                    return false;
 3977                }
 3978                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3979                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3980            }) {
 3981                continue;
 3982            }
 3983            let start = buffer_snapshot.anchor_after(start_offset);
 3984            let end = buffer_snapshot.anchor_after(end_offset);
 3985            linked_edits
 3986                .entry(buffer.clone())
 3987                .or_default()
 3988                .push(start..end);
 3989        }
 3990        Some(linked_edits)
 3991    }
 3992
 3993    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3994        let text: Arc<str> = text.into();
 3995
 3996        if self.read_only(cx) {
 3997            return;
 3998        }
 3999
 4000        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4001
 4002        let selections = self.selections.all_adjusted(cx);
 4003        let mut bracket_inserted = false;
 4004        let mut edits = Vec::new();
 4005        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4006        let mut new_selections = Vec::with_capacity(selections.len());
 4007        let mut new_autoclose_regions = Vec::new();
 4008        let snapshot = self.buffer.read(cx).read(cx);
 4009        let mut clear_linked_edit_ranges = false;
 4010
 4011        for (selection, autoclose_region) in
 4012            self.selections_with_autoclose_regions(selections, &snapshot)
 4013        {
 4014            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4015                // Determine if the inserted text matches the opening or closing
 4016                // bracket of any of this language's bracket pairs.
 4017                let mut bracket_pair = None;
 4018                let mut is_bracket_pair_start = false;
 4019                let mut is_bracket_pair_end = false;
 4020                if !text.is_empty() {
 4021                    let mut bracket_pair_matching_end = None;
 4022                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4023                    //  and they are removing the character that triggered IME popup.
 4024                    for (pair, enabled) in scope.brackets() {
 4025                        if !pair.close && !pair.surround {
 4026                            continue;
 4027                        }
 4028
 4029                        if enabled && pair.start.ends_with(text.as_ref()) {
 4030                            let prefix_len = pair.start.len() - text.len();
 4031                            let preceding_text_matches_prefix = prefix_len == 0
 4032                                || (selection.start.column >= (prefix_len as u32)
 4033                                    && snapshot.contains_str_at(
 4034                                        Point::new(
 4035                                            selection.start.row,
 4036                                            selection.start.column - (prefix_len as u32),
 4037                                        ),
 4038                                        &pair.start[..prefix_len],
 4039                                    ));
 4040                            if preceding_text_matches_prefix {
 4041                                bracket_pair = Some(pair.clone());
 4042                                is_bracket_pair_start = true;
 4043                                break;
 4044                            }
 4045                        }
 4046                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4047                        {
 4048                            // take first bracket pair matching end, but don't break in case a later bracket
 4049                            // pair matches start
 4050                            bracket_pair_matching_end = Some(pair.clone());
 4051                        }
 4052                    }
 4053                    if let Some(end) = bracket_pair_matching_end
 4054                        && bracket_pair.is_none()
 4055                    {
 4056                        bracket_pair = Some(end);
 4057                        is_bracket_pair_end = true;
 4058                    }
 4059                }
 4060
 4061                if let Some(bracket_pair) = bracket_pair {
 4062                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4063                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4064                    let auto_surround =
 4065                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4066                    if selection.is_empty() {
 4067                        if is_bracket_pair_start {
 4068                            // If the inserted text is a suffix of an opening bracket and the
 4069                            // selection is preceded by the rest of the opening bracket, then
 4070                            // insert the closing bracket.
 4071                            let following_text_allows_autoclose = snapshot
 4072                                .chars_at(selection.start)
 4073                                .next()
 4074                                .is_none_or(|c| scope.should_autoclose_before(c));
 4075
 4076                            let preceding_text_allows_autoclose = selection.start.column == 0
 4077                                || snapshot
 4078                                    .reversed_chars_at(selection.start)
 4079                                    .next()
 4080                                    .is_none_or(|c| {
 4081                                        bracket_pair.start != bracket_pair.end
 4082                                            || !snapshot
 4083                                                .char_classifier_at(selection.start)
 4084                                                .is_word(c)
 4085                                    });
 4086
 4087                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4088                                && bracket_pair.start.len() == 1
 4089                            {
 4090                                let target = bracket_pair.start.chars().next().unwrap();
 4091                                let current_line_count = snapshot
 4092                                    .reversed_chars_at(selection.start)
 4093                                    .take_while(|&c| c != '\n')
 4094                                    .filter(|&c| c == target)
 4095                                    .count();
 4096                                current_line_count % 2 == 1
 4097                            } else {
 4098                                false
 4099                            };
 4100
 4101                            if autoclose
 4102                                && bracket_pair.close
 4103                                && following_text_allows_autoclose
 4104                                && preceding_text_allows_autoclose
 4105                                && !is_closing_quote
 4106                            {
 4107                                let anchor = snapshot.anchor_before(selection.end);
 4108                                new_selections.push((selection.map(|_| anchor), text.len()));
 4109                                new_autoclose_regions.push((
 4110                                    anchor,
 4111                                    text.len(),
 4112                                    selection.id,
 4113                                    bracket_pair.clone(),
 4114                                ));
 4115                                edits.push((
 4116                                    selection.range(),
 4117                                    format!("{}{}", text, bracket_pair.end).into(),
 4118                                ));
 4119                                bracket_inserted = true;
 4120                                continue;
 4121                            }
 4122                        }
 4123
 4124                        if let Some(region) = autoclose_region {
 4125                            // If the selection is followed by an auto-inserted closing bracket,
 4126                            // then don't insert that closing bracket again; just move the selection
 4127                            // past the closing bracket.
 4128                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4129                                && text.as_ref() == region.pair.end.as_str()
 4130                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4131                            if should_skip {
 4132                                let anchor = snapshot.anchor_after(selection.end);
 4133                                new_selections
 4134                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4135                                continue;
 4136                            }
 4137                        }
 4138
 4139                        let always_treat_brackets_as_autoclosed = snapshot
 4140                            .language_settings_at(selection.start, cx)
 4141                            .always_treat_brackets_as_autoclosed;
 4142                        if always_treat_brackets_as_autoclosed
 4143                            && is_bracket_pair_end
 4144                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4145                        {
 4146                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4147                            // and the inserted text is a closing bracket and the selection is followed
 4148                            // by the closing bracket then move the selection past the closing bracket.
 4149                            let anchor = snapshot.anchor_after(selection.end);
 4150                            new_selections.push((selection.map(|_| anchor), text.len()));
 4151                            continue;
 4152                        }
 4153                    }
 4154                    // If an opening bracket is 1 character long and is typed while
 4155                    // text is selected, then surround that text with the bracket pair.
 4156                    else if auto_surround
 4157                        && bracket_pair.surround
 4158                        && is_bracket_pair_start
 4159                        && bracket_pair.start.chars().count() == 1
 4160                    {
 4161                        edits.push((selection.start..selection.start, text.clone()));
 4162                        edits.push((
 4163                            selection.end..selection.end,
 4164                            bracket_pair.end.as_str().into(),
 4165                        ));
 4166                        bracket_inserted = true;
 4167                        new_selections.push((
 4168                            Selection {
 4169                                id: selection.id,
 4170                                start: snapshot.anchor_after(selection.start),
 4171                                end: snapshot.anchor_before(selection.end),
 4172                                reversed: selection.reversed,
 4173                                goal: selection.goal,
 4174                            },
 4175                            0,
 4176                        ));
 4177                        continue;
 4178                    }
 4179                }
 4180            }
 4181
 4182            if self.auto_replace_emoji_shortcode
 4183                && selection.is_empty()
 4184                && text.as_ref().ends_with(':')
 4185                && let Some(possible_emoji_short_code) =
 4186                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4187                && !possible_emoji_short_code.is_empty()
 4188                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4189            {
 4190                let emoji_shortcode_start = Point::new(
 4191                    selection.start.row,
 4192                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4193                );
 4194
 4195                // Remove shortcode from buffer
 4196                edits.push((
 4197                    emoji_shortcode_start..selection.start,
 4198                    "".to_string().into(),
 4199                ));
 4200                new_selections.push((
 4201                    Selection {
 4202                        id: selection.id,
 4203                        start: snapshot.anchor_after(emoji_shortcode_start),
 4204                        end: snapshot.anchor_before(selection.start),
 4205                        reversed: selection.reversed,
 4206                        goal: selection.goal,
 4207                    },
 4208                    0,
 4209                ));
 4210
 4211                // Insert emoji
 4212                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4213                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4214                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4215
 4216                continue;
 4217            }
 4218
 4219            // If not handling any auto-close operation, then just replace the selected
 4220            // text with the given input and move the selection to the end of the
 4221            // newly inserted text.
 4222            let anchor = snapshot.anchor_after(selection.end);
 4223            if !self.linked_edit_ranges.is_empty() {
 4224                let start_anchor = snapshot.anchor_before(selection.start);
 4225
 4226                let is_word_char = text.chars().next().is_none_or(|char| {
 4227                    let classifier = snapshot
 4228                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4229                        .ignore_punctuation(true);
 4230                    classifier.is_word(char)
 4231                });
 4232
 4233                if is_word_char {
 4234                    if let Some(ranges) = self
 4235                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4236                    {
 4237                        for (buffer, edits) in ranges {
 4238                            linked_edits
 4239                                .entry(buffer.clone())
 4240                                .or_default()
 4241                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4242                        }
 4243                    }
 4244                } else {
 4245                    clear_linked_edit_ranges = true;
 4246                }
 4247            }
 4248
 4249            new_selections.push((selection.map(|_| anchor), 0));
 4250            edits.push((selection.start..selection.end, text.clone()));
 4251        }
 4252
 4253        drop(snapshot);
 4254
 4255        self.transact(window, cx, |this, window, cx| {
 4256            if clear_linked_edit_ranges {
 4257                this.linked_edit_ranges.clear();
 4258            }
 4259            let initial_buffer_versions =
 4260                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4261
 4262            this.buffer.update(cx, |buffer, cx| {
 4263                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4264            });
 4265            for (buffer, edits) in linked_edits {
 4266                buffer.update(cx, |buffer, cx| {
 4267                    let snapshot = buffer.snapshot();
 4268                    let edits = edits
 4269                        .into_iter()
 4270                        .map(|(range, text)| {
 4271                            use text::ToPoint as TP;
 4272                            let end_point = TP::to_point(&range.end, &snapshot);
 4273                            let start_point = TP::to_point(&range.start, &snapshot);
 4274                            (start_point..end_point, text)
 4275                        })
 4276                        .sorted_by_key(|(range, _)| range.start);
 4277                    buffer.edit(edits, None, cx);
 4278                })
 4279            }
 4280            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4281            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4282            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4283            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4284                .zip(new_selection_deltas)
 4285                .map(|(selection, delta)| Selection {
 4286                    id: selection.id,
 4287                    start: selection.start + delta,
 4288                    end: selection.end + delta,
 4289                    reversed: selection.reversed,
 4290                    goal: SelectionGoal::None,
 4291                })
 4292                .collect::<Vec<_>>();
 4293
 4294            let mut i = 0;
 4295            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4296                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4297                let start = map.buffer_snapshot.anchor_before(position);
 4298                let end = map.buffer_snapshot.anchor_after(position);
 4299                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4300                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4301                        Ordering::Less => i += 1,
 4302                        Ordering::Greater => break,
 4303                        Ordering::Equal => {
 4304                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4305                                Ordering::Less => i += 1,
 4306                                Ordering::Equal => break,
 4307                                Ordering::Greater => break,
 4308                            }
 4309                        }
 4310                    }
 4311                }
 4312                this.autoclose_regions.insert(
 4313                    i,
 4314                    AutocloseRegion {
 4315                        selection_id,
 4316                        range: start..end,
 4317                        pair,
 4318                    },
 4319                );
 4320            }
 4321
 4322            let had_active_edit_prediction = this.has_active_edit_prediction();
 4323            this.change_selections(
 4324                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4325                window,
 4326                cx,
 4327                |s| s.select(new_selections),
 4328            );
 4329
 4330            if !bracket_inserted
 4331                && let Some(on_type_format_task) =
 4332                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4333            {
 4334                on_type_format_task.detach_and_log_err(cx);
 4335            }
 4336
 4337            let editor_settings = EditorSettings::get_global(cx);
 4338            if bracket_inserted
 4339                && (editor_settings.auto_signature_help
 4340                    || editor_settings.show_signature_help_after_edits)
 4341            {
 4342                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4343            }
 4344
 4345            let trigger_in_words =
 4346                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4347            if this.hard_wrap.is_some() {
 4348                let latest: Range<Point> = this.selections.newest(cx).range();
 4349                if latest.is_empty()
 4350                    && this
 4351                        .buffer()
 4352                        .read(cx)
 4353                        .snapshot(cx)
 4354                        .line_len(MultiBufferRow(latest.start.row))
 4355                        == latest.start.column
 4356                {
 4357                    this.rewrap_impl(
 4358                        RewrapOptions {
 4359                            override_language_settings: true,
 4360                            preserve_existing_whitespace: true,
 4361                        },
 4362                        cx,
 4363                    )
 4364                }
 4365            }
 4366            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4367            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4368            this.refresh_edit_prediction(true, false, window, cx);
 4369            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4370        });
 4371    }
 4372
 4373    fn find_possible_emoji_shortcode_at_position(
 4374        snapshot: &MultiBufferSnapshot,
 4375        position: Point,
 4376    ) -> Option<String> {
 4377        let mut chars = Vec::new();
 4378        let mut found_colon = false;
 4379        for char in snapshot.reversed_chars_at(position).take(100) {
 4380            // Found a possible emoji shortcode in the middle of the buffer
 4381            if found_colon {
 4382                if char.is_whitespace() {
 4383                    chars.reverse();
 4384                    return Some(chars.iter().collect());
 4385                }
 4386                // If the previous character is not a whitespace, we are in the middle of a word
 4387                // and we only want to complete the shortcode if the word is made up of other emojis
 4388                let mut containing_word = String::new();
 4389                for ch in snapshot
 4390                    .reversed_chars_at(position)
 4391                    .skip(chars.len() + 1)
 4392                    .take(100)
 4393                {
 4394                    if ch.is_whitespace() {
 4395                        break;
 4396                    }
 4397                    containing_word.push(ch);
 4398                }
 4399                let containing_word = containing_word.chars().rev().collect::<String>();
 4400                if util::word_consists_of_emojis(containing_word.as_str()) {
 4401                    chars.reverse();
 4402                    return Some(chars.iter().collect());
 4403                }
 4404            }
 4405
 4406            if char.is_whitespace() || !char.is_ascii() {
 4407                return None;
 4408            }
 4409            if char == ':' {
 4410                found_colon = true;
 4411            } else {
 4412                chars.push(char);
 4413            }
 4414        }
 4415        // Found a possible emoji shortcode at the beginning of the buffer
 4416        chars.reverse();
 4417        Some(chars.iter().collect())
 4418    }
 4419
 4420    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4421        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4422        self.transact(window, cx, |this, window, cx| {
 4423            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4424                let selections = this.selections.all::<usize>(cx);
 4425                let multi_buffer = this.buffer.read(cx);
 4426                let buffer = multi_buffer.snapshot(cx);
 4427                selections
 4428                    .iter()
 4429                    .map(|selection| {
 4430                        let start_point = selection.start.to_point(&buffer);
 4431                        let mut existing_indent =
 4432                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4433                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4434                        let start = selection.start;
 4435                        let end = selection.end;
 4436                        let selection_is_empty = start == end;
 4437                        let language_scope = buffer.language_scope_at(start);
 4438                        let (
 4439                            comment_delimiter,
 4440                            doc_delimiter,
 4441                            insert_extra_newline,
 4442                            indent_on_newline,
 4443                            indent_on_extra_newline,
 4444                        ) = if let Some(language) = &language_scope {
 4445                            let mut insert_extra_newline =
 4446                                insert_extra_newline_brackets(&buffer, start..end, language)
 4447                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4448
 4449                            // Comment extension on newline is allowed only for cursor selections
 4450                            let comment_delimiter = maybe!({
 4451                                if !selection_is_empty {
 4452                                    return None;
 4453                                }
 4454
 4455                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4456                                    return None;
 4457                                }
 4458
 4459                                let delimiters = language.line_comment_prefixes();
 4460                                let max_len_of_delimiter =
 4461                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4462                                let (snapshot, range) =
 4463                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4464
 4465                                let num_of_whitespaces = snapshot
 4466                                    .chars_for_range(range.clone())
 4467                                    .take_while(|c| c.is_whitespace())
 4468                                    .count();
 4469                                let comment_candidate = snapshot
 4470                                    .chars_for_range(range.clone())
 4471                                    .skip(num_of_whitespaces)
 4472                                    .take(max_len_of_delimiter)
 4473                                    .collect::<String>();
 4474                                let (delimiter, trimmed_len) = delimiters
 4475                                    .iter()
 4476                                    .filter_map(|delimiter| {
 4477                                        let prefix = delimiter.trim_end();
 4478                                        if comment_candidate.starts_with(prefix) {
 4479                                            Some((delimiter, prefix.len()))
 4480                                        } else {
 4481                                            None
 4482                                        }
 4483                                    })
 4484                                    .max_by_key(|(_, len)| *len)?;
 4485
 4486                                if let Some(BlockCommentConfig {
 4487                                    start: block_start, ..
 4488                                }) = language.block_comment()
 4489                                {
 4490                                    let block_start_trimmed = block_start.trim_end();
 4491                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4492                                        let line_content = snapshot
 4493                                            .chars_for_range(range)
 4494                                            .skip(num_of_whitespaces)
 4495                                            .take(block_start_trimmed.len())
 4496                                            .collect::<String>();
 4497
 4498                                        if line_content.starts_with(block_start_trimmed) {
 4499                                            return None;
 4500                                        }
 4501                                    }
 4502                                }
 4503
 4504                                let cursor_is_placed_after_comment_marker =
 4505                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4506                                if cursor_is_placed_after_comment_marker {
 4507                                    Some(delimiter.clone())
 4508                                } else {
 4509                                    None
 4510                                }
 4511                            });
 4512
 4513                            let mut indent_on_newline = IndentSize::spaces(0);
 4514                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4515
 4516                            let doc_delimiter = maybe!({
 4517                                if !selection_is_empty {
 4518                                    return None;
 4519                                }
 4520
 4521                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4522                                    return None;
 4523                                }
 4524
 4525                                let BlockCommentConfig {
 4526                                    start: start_tag,
 4527                                    end: end_tag,
 4528                                    prefix: delimiter,
 4529                                    tab_size: len,
 4530                                } = language.documentation_comment()?;
 4531                                let is_within_block_comment = buffer
 4532                                    .language_scope_at(start_point)
 4533                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4534                                if !is_within_block_comment {
 4535                                    return None;
 4536                                }
 4537
 4538                                let (snapshot, range) =
 4539                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4540
 4541                                let num_of_whitespaces = snapshot
 4542                                    .chars_for_range(range.clone())
 4543                                    .take_while(|c| c.is_whitespace())
 4544                                    .count();
 4545
 4546                                // 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.
 4547                                let column = start_point.column;
 4548                                let cursor_is_after_start_tag = {
 4549                                    let start_tag_len = start_tag.len();
 4550                                    let start_tag_line = snapshot
 4551                                        .chars_for_range(range.clone())
 4552                                        .skip(num_of_whitespaces)
 4553                                        .take(start_tag_len)
 4554                                        .collect::<String>();
 4555                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4556                                        num_of_whitespaces + start_tag_len <= column as usize
 4557                                    } else {
 4558                                        false
 4559                                    }
 4560                                };
 4561
 4562                                let cursor_is_after_delimiter = {
 4563                                    let delimiter_trim = delimiter.trim_end();
 4564                                    let delimiter_line = snapshot
 4565                                        .chars_for_range(range.clone())
 4566                                        .skip(num_of_whitespaces)
 4567                                        .take(delimiter_trim.len())
 4568                                        .collect::<String>();
 4569                                    if delimiter_line.starts_with(delimiter_trim) {
 4570                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4571                                    } else {
 4572                                        false
 4573                                    }
 4574                                };
 4575
 4576                                let cursor_is_before_end_tag_if_exists = {
 4577                                    let mut char_position = 0u32;
 4578                                    let mut end_tag_offset = None;
 4579
 4580                                    'outer: for chunk in snapshot.text_for_range(range) {
 4581                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4582                                            let chars_before_match =
 4583                                                chunk[..byte_pos].chars().count() as u32;
 4584                                            end_tag_offset =
 4585                                                Some(char_position + chars_before_match);
 4586                                            break 'outer;
 4587                                        }
 4588                                        char_position += chunk.chars().count() as u32;
 4589                                    }
 4590
 4591                                    if let Some(end_tag_offset) = end_tag_offset {
 4592                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4593                                        if cursor_is_after_start_tag {
 4594                                            if cursor_is_before_end_tag {
 4595                                                insert_extra_newline = true;
 4596                                            }
 4597                                            let cursor_is_at_start_of_end_tag =
 4598                                                column == end_tag_offset;
 4599                                            if cursor_is_at_start_of_end_tag {
 4600                                                indent_on_extra_newline.len = *len;
 4601                                            }
 4602                                        }
 4603                                        cursor_is_before_end_tag
 4604                                    } else {
 4605                                        true
 4606                                    }
 4607                                };
 4608
 4609                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4610                                    && cursor_is_before_end_tag_if_exists
 4611                                {
 4612                                    if cursor_is_after_start_tag {
 4613                                        indent_on_newline.len = *len;
 4614                                    }
 4615                                    Some(delimiter.clone())
 4616                                } else {
 4617                                    None
 4618                                }
 4619                            });
 4620
 4621                            (
 4622                                comment_delimiter,
 4623                                doc_delimiter,
 4624                                insert_extra_newline,
 4625                                indent_on_newline,
 4626                                indent_on_extra_newline,
 4627                            )
 4628                        } else {
 4629                            (
 4630                                None,
 4631                                None,
 4632                                false,
 4633                                IndentSize::default(),
 4634                                IndentSize::default(),
 4635                            )
 4636                        };
 4637
 4638                        let prevent_auto_indent = doc_delimiter.is_some();
 4639                        let delimiter = comment_delimiter.or(doc_delimiter);
 4640
 4641                        let capacity_for_delimiter =
 4642                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4643                        let mut new_text = String::with_capacity(
 4644                            1 + capacity_for_delimiter
 4645                                + existing_indent.len as usize
 4646                                + indent_on_newline.len as usize
 4647                                + indent_on_extra_newline.len as usize,
 4648                        );
 4649                        new_text.push('\n');
 4650                        new_text.extend(existing_indent.chars());
 4651                        new_text.extend(indent_on_newline.chars());
 4652
 4653                        if let Some(delimiter) = &delimiter {
 4654                            new_text.push_str(delimiter);
 4655                        }
 4656
 4657                        if insert_extra_newline {
 4658                            new_text.push('\n');
 4659                            new_text.extend(existing_indent.chars());
 4660                            new_text.extend(indent_on_extra_newline.chars());
 4661                        }
 4662
 4663                        let anchor = buffer.anchor_after(end);
 4664                        let new_selection = selection.map(|_| anchor);
 4665                        (
 4666                            ((start..end, new_text), prevent_auto_indent),
 4667                            (insert_extra_newline, new_selection),
 4668                        )
 4669                    })
 4670                    .unzip()
 4671            };
 4672
 4673            let mut auto_indent_edits = Vec::new();
 4674            let mut edits = Vec::new();
 4675            for (edit, prevent_auto_indent) in edits_with_flags {
 4676                if prevent_auto_indent {
 4677                    edits.push(edit);
 4678                } else {
 4679                    auto_indent_edits.push(edit);
 4680                }
 4681            }
 4682            if !edits.is_empty() {
 4683                this.edit(edits, cx);
 4684            }
 4685            if !auto_indent_edits.is_empty() {
 4686                this.edit_with_autoindent(auto_indent_edits, cx);
 4687            }
 4688
 4689            let buffer = this.buffer.read(cx).snapshot(cx);
 4690            let new_selections = selection_info
 4691                .into_iter()
 4692                .map(|(extra_newline_inserted, new_selection)| {
 4693                    let mut cursor = new_selection.end.to_point(&buffer);
 4694                    if extra_newline_inserted {
 4695                        cursor.row -= 1;
 4696                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4697                    }
 4698                    new_selection.map(|_| cursor)
 4699                })
 4700                .collect();
 4701
 4702            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4703            this.refresh_edit_prediction(true, false, window, cx);
 4704        });
 4705    }
 4706
 4707    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4708        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4709
 4710        let buffer = self.buffer.read(cx);
 4711        let snapshot = buffer.snapshot(cx);
 4712
 4713        let mut edits = Vec::new();
 4714        let mut rows = Vec::new();
 4715
 4716        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4717            let cursor = selection.head();
 4718            let row = cursor.row;
 4719
 4720            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4721
 4722            let newline = "\n".to_string();
 4723            edits.push((start_of_line..start_of_line, newline));
 4724
 4725            rows.push(row + rows_inserted as u32);
 4726        }
 4727
 4728        self.transact(window, cx, |editor, window, cx| {
 4729            editor.edit(edits, cx);
 4730
 4731            editor.change_selections(Default::default(), window, cx, |s| {
 4732                let mut index = 0;
 4733                s.move_cursors_with(|map, _, _| {
 4734                    let row = rows[index];
 4735                    index += 1;
 4736
 4737                    let point = Point::new(row, 0);
 4738                    let boundary = map.next_line_boundary(point).1;
 4739                    let clipped = map.clip_point(boundary, Bias::Left);
 4740
 4741                    (clipped, SelectionGoal::None)
 4742                });
 4743            });
 4744
 4745            let mut indent_edits = Vec::new();
 4746            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4747            for row in rows {
 4748                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4749                for (row, indent) in indents {
 4750                    if indent.len == 0 {
 4751                        continue;
 4752                    }
 4753
 4754                    let text = match indent.kind {
 4755                        IndentKind::Space => " ".repeat(indent.len as usize),
 4756                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4757                    };
 4758                    let point = Point::new(row.0, 0);
 4759                    indent_edits.push((point..point, text));
 4760                }
 4761            }
 4762            editor.edit(indent_edits, cx);
 4763        });
 4764    }
 4765
 4766    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4767        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4768
 4769        let buffer = self.buffer.read(cx);
 4770        let snapshot = buffer.snapshot(cx);
 4771
 4772        let mut edits = Vec::new();
 4773        let mut rows = Vec::new();
 4774        let mut rows_inserted = 0;
 4775
 4776        for selection in self.selections.all_adjusted(cx) {
 4777            let cursor = selection.head();
 4778            let row = cursor.row;
 4779
 4780            let point = Point::new(row + 1, 0);
 4781            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4782
 4783            let newline = "\n".to_string();
 4784            edits.push((start_of_line..start_of_line, newline));
 4785
 4786            rows_inserted += 1;
 4787            rows.push(row + rows_inserted);
 4788        }
 4789
 4790        self.transact(window, cx, |editor, window, cx| {
 4791            editor.edit(edits, cx);
 4792
 4793            editor.change_selections(Default::default(), window, cx, |s| {
 4794                let mut index = 0;
 4795                s.move_cursors_with(|map, _, _| {
 4796                    let row = rows[index];
 4797                    index += 1;
 4798
 4799                    let point = Point::new(row, 0);
 4800                    let boundary = map.next_line_boundary(point).1;
 4801                    let clipped = map.clip_point(boundary, Bias::Left);
 4802
 4803                    (clipped, SelectionGoal::None)
 4804                });
 4805            });
 4806
 4807            let mut indent_edits = Vec::new();
 4808            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4809            for row in rows {
 4810                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4811                for (row, indent) in indents {
 4812                    if indent.len == 0 {
 4813                        continue;
 4814                    }
 4815
 4816                    let text = match indent.kind {
 4817                        IndentKind::Space => " ".repeat(indent.len as usize),
 4818                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4819                    };
 4820                    let point = Point::new(row.0, 0);
 4821                    indent_edits.push((point..point, text));
 4822                }
 4823            }
 4824            editor.edit(indent_edits, cx);
 4825        });
 4826    }
 4827
 4828    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4829        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4830            original_indent_columns: Vec::new(),
 4831        });
 4832        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4833    }
 4834
 4835    fn insert_with_autoindent_mode(
 4836        &mut self,
 4837        text: &str,
 4838        autoindent_mode: Option<AutoindentMode>,
 4839        window: &mut Window,
 4840        cx: &mut Context<Self>,
 4841    ) {
 4842        if self.read_only(cx) {
 4843            return;
 4844        }
 4845
 4846        let text: Arc<str> = text.into();
 4847        self.transact(window, cx, |this, window, cx| {
 4848            let old_selections = this.selections.all_adjusted(cx);
 4849            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4850                let anchors = {
 4851                    let snapshot = buffer.read(cx);
 4852                    old_selections
 4853                        .iter()
 4854                        .map(|s| {
 4855                            let anchor = snapshot.anchor_after(s.head());
 4856                            s.map(|_| anchor)
 4857                        })
 4858                        .collect::<Vec<_>>()
 4859                };
 4860                buffer.edit(
 4861                    old_selections
 4862                        .iter()
 4863                        .map(|s| (s.start..s.end, text.clone())),
 4864                    autoindent_mode,
 4865                    cx,
 4866                );
 4867                anchors
 4868            });
 4869
 4870            this.change_selections(Default::default(), window, cx, |s| {
 4871                s.select_anchors(selection_anchors);
 4872            });
 4873
 4874            cx.notify();
 4875        });
 4876    }
 4877
 4878    fn trigger_completion_on_input(
 4879        &mut self,
 4880        text: &str,
 4881        trigger_in_words: bool,
 4882        window: &mut Window,
 4883        cx: &mut Context<Self>,
 4884    ) {
 4885        let completions_source = self
 4886            .context_menu
 4887            .borrow()
 4888            .as_ref()
 4889            .and_then(|menu| match menu {
 4890                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4891                CodeContextMenu::CodeActions(_) => None,
 4892            });
 4893
 4894        match completions_source {
 4895            Some(CompletionsMenuSource::Words) => {
 4896                self.show_word_completions(&ShowWordCompletions, window, cx)
 4897            }
 4898            Some(CompletionsMenuSource::Normal)
 4899            | Some(CompletionsMenuSource::SnippetChoices)
 4900            | None
 4901                if self.is_completion_trigger(
 4902                    text,
 4903                    trigger_in_words,
 4904                    completions_source.is_some(),
 4905                    cx,
 4906                ) =>
 4907            {
 4908                self.show_completions(
 4909                    &ShowCompletions {
 4910                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4911                    },
 4912                    window,
 4913                    cx,
 4914                )
 4915            }
 4916            _ => {
 4917                self.hide_context_menu(window, cx);
 4918            }
 4919        }
 4920    }
 4921
 4922    fn is_completion_trigger(
 4923        &self,
 4924        text: &str,
 4925        trigger_in_words: bool,
 4926        menu_is_open: bool,
 4927        cx: &mut Context<Self>,
 4928    ) -> bool {
 4929        let position = self.selections.newest_anchor().head();
 4930        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4931            return false;
 4932        };
 4933
 4934        if let Some(completion_provider) = &self.completion_provider {
 4935            completion_provider.is_completion_trigger(
 4936                &buffer,
 4937                position.text_anchor,
 4938                text,
 4939                trigger_in_words,
 4940                menu_is_open,
 4941                cx,
 4942            )
 4943        } else {
 4944            false
 4945        }
 4946    }
 4947
 4948    /// If any empty selections is touching the start of its innermost containing autoclose
 4949    /// region, expand it to select the brackets.
 4950    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4951        let selections = self.selections.all::<usize>(cx);
 4952        let buffer = self.buffer.read(cx).read(cx);
 4953        let new_selections = self
 4954            .selections_with_autoclose_regions(selections, &buffer)
 4955            .map(|(mut selection, region)| {
 4956                if !selection.is_empty() {
 4957                    return selection;
 4958                }
 4959
 4960                if let Some(region) = region {
 4961                    let mut range = region.range.to_offset(&buffer);
 4962                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4963                        range.start -= region.pair.start.len();
 4964                        if buffer.contains_str_at(range.start, &region.pair.start)
 4965                            && buffer.contains_str_at(range.end, &region.pair.end)
 4966                        {
 4967                            range.end += region.pair.end.len();
 4968                            selection.start = range.start;
 4969                            selection.end = range.end;
 4970
 4971                            return selection;
 4972                        }
 4973                    }
 4974                }
 4975
 4976                let always_treat_brackets_as_autoclosed = buffer
 4977                    .language_settings_at(selection.start, cx)
 4978                    .always_treat_brackets_as_autoclosed;
 4979
 4980                if !always_treat_brackets_as_autoclosed {
 4981                    return selection;
 4982                }
 4983
 4984                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4985                    for (pair, enabled) in scope.brackets() {
 4986                        if !enabled || !pair.close {
 4987                            continue;
 4988                        }
 4989
 4990                        if buffer.contains_str_at(selection.start, &pair.end) {
 4991                            let pair_start_len = pair.start.len();
 4992                            if buffer.contains_str_at(
 4993                                selection.start.saturating_sub(pair_start_len),
 4994                                &pair.start,
 4995                            ) {
 4996                                selection.start -= pair_start_len;
 4997                                selection.end += pair.end.len();
 4998
 4999                                return selection;
 5000                            }
 5001                        }
 5002                    }
 5003                }
 5004
 5005                selection
 5006            })
 5007            .collect();
 5008
 5009        drop(buffer);
 5010        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5011            selections.select(new_selections)
 5012        });
 5013    }
 5014
 5015    /// Iterate the given selections, and for each one, find the smallest surrounding
 5016    /// autoclose region. This uses the ordering of the selections and the autoclose
 5017    /// regions to avoid repeated comparisons.
 5018    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5019        &'a self,
 5020        selections: impl IntoIterator<Item = Selection<D>>,
 5021        buffer: &'a MultiBufferSnapshot,
 5022    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5023        let mut i = 0;
 5024        let mut regions = self.autoclose_regions.as_slice();
 5025        selections.into_iter().map(move |selection| {
 5026            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5027
 5028            let mut enclosing = None;
 5029            while let Some(pair_state) = regions.get(i) {
 5030                if pair_state.range.end.to_offset(buffer) < range.start {
 5031                    regions = &regions[i + 1..];
 5032                    i = 0;
 5033                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5034                    break;
 5035                } else {
 5036                    if pair_state.selection_id == selection.id {
 5037                        enclosing = Some(pair_state);
 5038                    }
 5039                    i += 1;
 5040                }
 5041            }
 5042
 5043            (selection, enclosing)
 5044        })
 5045    }
 5046
 5047    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5048    fn invalidate_autoclose_regions(
 5049        &mut self,
 5050        mut selections: &[Selection<Anchor>],
 5051        buffer: &MultiBufferSnapshot,
 5052    ) {
 5053        self.autoclose_regions.retain(|state| {
 5054            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5055                return false;
 5056            }
 5057
 5058            let mut i = 0;
 5059            while let Some(selection) = selections.get(i) {
 5060                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5061                    selections = &selections[1..];
 5062                    continue;
 5063                }
 5064                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5065                    break;
 5066                }
 5067                if selection.id == state.selection_id {
 5068                    return true;
 5069                } else {
 5070                    i += 1;
 5071                }
 5072            }
 5073            false
 5074        });
 5075    }
 5076
 5077    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5078        let offset = position.to_offset(buffer);
 5079        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5080        if offset > word_range.start && kind == Some(CharKind::Word) {
 5081            Some(
 5082                buffer
 5083                    .text_for_range(word_range.start..offset)
 5084                    .collect::<String>(),
 5085            )
 5086        } else {
 5087            None
 5088        }
 5089    }
 5090
 5091    pub fn toggle_inline_values(
 5092        &mut self,
 5093        _: &ToggleInlineValues,
 5094        _: &mut Window,
 5095        cx: &mut Context<Self>,
 5096    ) {
 5097        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5098
 5099        self.refresh_inline_values(cx);
 5100    }
 5101
 5102    pub fn toggle_inlay_hints(
 5103        &mut self,
 5104        _: &ToggleInlayHints,
 5105        _: &mut Window,
 5106        cx: &mut Context<Self>,
 5107    ) {
 5108        self.refresh_inlay_hints(
 5109            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5110            cx,
 5111        );
 5112    }
 5113
 5114    pub fn inlay_hints_enabled(&self) -> bool {
 5115        self.inlay_hint_cache.enabled
 5116    }
 5117
 5118    pub fn inline_values_enabled(&self) -> bool {
 5119        self.inline_value_cache.enabled
 5120    }
 5121
 5122    #[cfg(any(test, feature = "test-support"))]
 5123    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5124        self.display_map
 5125            .read(cx)
 5126            .current_inlays()
 5127            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5128            .cloned()
 5129            .collect()
 5130    }
 5131
 5132    #[cfg(any(test, feature = "test-support"))]
 5133    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5134        self.display_map
 5135            .read(cx)
 5136            .current_inlays()
 5137            .cloned()
 5138            .collect()
 5139    }
 5140
 5141    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5142        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5143            return;
 5144        }
 5145
 5146        let reason_description = reason.description();
 5147        let ignore_debounce = matches!(
 5148            reason,
 5149            InlayHintRefreshReason::SettingsChange(_)
 5150                | InlayHintRefreshReason::Toggle(_)
 5151                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5152                | InlayHintRefreshReason::ModifiersChanged(_)
 5153        );
 5154        let (invalidate_cache, required_languages) = match reason {
 5155            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5156                match self.inlay_hint_cache.modifiers_override(enabled) {
 5157                    Some(enabled) => {
 5158                        if enabled {
 5159                            (InvalidationStrategy::RefreshRequested, None)
 5160                        } else {
 5161                            self.splice_inlays(
 5162                                &self
 5163                                    .visible_inlay_hints(cx)
 5164                                    .iter()
 5165                                    .map(|inlay| inlay.id)
 5166                                    .collect::<Vec<InlayId>>(),
 5167                                Vec::new(),
 5168                                cx,
 5169                            );
 5170                            return;
 5171                        }
 5172                    }
 5173                    None => return,
 5174                }
 5175            }
 5176            InlayHintRefreshReason::Toggle(enabled) => {
 5177                if self.inlay_hint_cache.toggle(enabled) {
 5178                    if enabled {
 5179                        (InvalidationStrategy::RefreshRequested, None)
 5180                    } else {
 5181                        self.splice_inlays(
 5182                            &self
 5183                                .visible_inlay_hints(cx)
 5184                                .iter()
 5185                                .map(|inlay| inlay.id)
 5186                                .collect::<Vec<InlayId>>(),
 5187                            Vec::new(),
 5188                            cx,
 5189                        );
 5190                        return;
 5191                    }
 5192                } else {
 5193                    return;
 5194                }
 5195            }
 5196            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5197                match self.inlay_hint_cache.update_settings(
 5198                    &self.buffer,
 5199                    new_settings,
 5200                    self.visible_inlay_hints(cx),
 5201                    cx,
 5202                ) {
 5203                    ControlFlow::Break(Some(InlaySplice {
 5204                        to_remove,
 5205                        to_insert,
 5206                    })) => {
 5207                        self.splice_inlays(&to_remove, to_insert, cx);
 5208                        return;
 5209                    }
 5210                    ControlFlow::Break(None) => return,
 5211                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5212                }
 5213            }
 5214            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5215                if let Some(InlaySplice {
 5216                    to_remove,
 5217                    to_insert,
 5218                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5219                {
 5220                    self.splice_inlays(&to_remove, to_insert, cx);
 5221                }
 5222                self.display_map.update(cx, |display_map, _| {
 5223                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5224                });
 5225                return;
 5226            }
 5227            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5228            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5229                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5230            }
 5231            InlayHintRefreshReason::RefreshRequested => {
 5232                (InvalidationStrategy::RefreshRequested, None)
 5233            }
 5234        };
 5235
 5236        if let Some(InlaySplice {
 5237            to_remove,
 5238            to_insert,
 5239        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5240            reason_description,
 5241            self.visible_excerpts(required_languages.as_ref(), cx),
 5242            invalidate_cache,
 5243            ignore_debounce,
 5244            cx,
 5245        ) {
 5246            self.splice_inlays(&to_remove, to_insert, cx);
 5247        }
 5248    }
 5249
 5250    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5251        self.display_map
 5252            .read(cx)
 5253            .current_inlays()
 5254            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5255            .cloned()
 5256            .collect()
 5257    }
 5258
 5259    pub fn visible_excerpts(
 5260        &self,
 5261        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5262        cx: &mut Context<Editor>,
 5263    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5264        let Some(project) = self.project() else {
 5265            return HashMap::default();
 5266        };
 5267        let project = project.read(cx);
 5268        let multi_buffer = self.buffer().read(cx);
 5269        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5270        let multi_buffer_visible_start = self
 5271            .scroll_manager
 5272            .anchor()
 5273            .anchor
 5274            .to_point(&multi_buffer_snapshot);
 5275        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5276            multi_buffer_visible_start
 5277                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5278            Bias::Left,
 5279        );
 5280        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5281        multi_buffer_snapshot
 5282            .range_to_buffer_ranges(multi_buffer_visible_range)
 5283            .into_iter()
 5284            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5285            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5286                let buffer_file = project::File::from_dyn(buffer.file())?;
 5287                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5288                let worktree_entry = buffer_worktree
 5289                    .read(cx)
 5290                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5291                if worktree_entry.is_ignored {
 5292                    return None;
 5293                }
 5294
 5295                let language = buffer.language()?;
 5296                if let Some(restrict_to_languages) = restrict_to_languages
 5297                    && !restrict_to_languages.contains(language)
 5298                {
 5299                    return None;
 5300                }
 5301                Some((
 5302                    excerpt_id,
 5303                    (
 5304                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5305                        buffer.version().clone(),
 5306                        excerpt_visible_range,
 5307                    ),
 5308                ))
 5309            })
 5310            .collect()
 5311    }
 5312
 5313    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5314        TextLayoutDetails {
 5315            text_system: window.text_system().clone(),
 5316            editor_style: self.style.clone().unwrap(),
 5317            rem_size: window.rem_size(),
 5318            scroll_anchor: self.scroll_manager.anchor(),
 5319            visible_rows: self.visible_line_count(),
 5320            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5321        }
 5322    }
 5323
 5324    pub fn splice_inlays(
 5325        &self,
 5326        to_remove: &[InlayId],
 5327        to_insert: Vec<Inlay>,
 5328        cx: &mut Context<Self>,
 5329    ) {
 5330        self.display_map.update(cx, |display_map, cx| {
 5331            display_map.splice_inlays(to_remove, to_insert, cx)
 5332        });
 5333        cx.notify();
 5334    }
 5335
 5336    fn trigger_on_type_formatting(
 5337        &self,
 5338        input: String,
 5339        window: &mut Window,
 5340        cx: &mut Context<Self>,
 5341    ) -> Option<Task<Result<()>>> {
 5342        if input.len() != 1 {
 5343            return None;
 5344        }
 5345
 5346        let project = self.project()?;
 5347        let position = self.selections.newest_anchor().head();
 5348        let (buffer, buffer_position) = self
 5349            .buffer
 5350            .read(cx)
 5351            .text_anchor_for_position(position, cx)?;
 5352
 5353        let settings = language_settings::language_settings(
 5354            buffer
 5355                .read(cx)
 5356                .language_at(buffer_position)
 5357                .map(|l| l.name()),
 5358            buffer.read(cx).file(),
 5359            cx,
 5360        );
 5361        if !settings.use_on_type_format {
 5362            return None;
 5363        }
 5364
 5365        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5366        // hence we do LSP request & edit on host side only — add formats to host's history.
 5367        let push_to_lsp_host_history = true;
 5368        // If this is not the host, append its history with new edits.
 5369        let push_to_client_history = project.read(cx).is_via_collab();
 5370
 5371        let on_type_formatting = project.update(cx, |project, cx| {
 5372            project.on_type_format(
 5373                buffer.clone(),
 5374                buffer_position,
 5375                input,
 5376                push_to_lsp_host_history,
 5377                cx,
 5378            )
 5379        });
 5380        Some(cx.spawn_in(window, async move |editor, cx| {
 5381            if let Some(transaction) = on_type_formatting.await? {
 5382                if push_to_client_history {
 5383                    buffer
 5384                        .update(cx, |buffer, _| {
 5385                            buffer.push_transaction(transaction, Instant::now());
 5386                            buffer.finalize_last_transaction();
 5387                        })
 5388                        .ok();
 5389                }
 5390                editor.update(cx, |editor, cx| {
 5391                    editor.refresh_document_highlights(cx);
 5392                })?;
 5393            }
 5394            Ok(())
 5395        }))
 5396    }
 5397
 5398    pub fn show_word_completions(
 5399        &mut self,
 5400        _: &ShowWordCompletions,
 5401        window: &mut Window,
 5402        cx: &mut Context<Self>,
 5403    ) {
 5404        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5405    }
 5406
 5407    pub fn show_completions(
 5408        &mut self,
 5409        options: &ShowCompletions,
 5410        window: &mut Window,
 5411        cx: &mut Context<Self>,
 5412    ) {
 5413        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5414    }
 5415
 5416    fn open_or_update_completions_menu(
 5417        &mut self,
 5418        requested_source: Option<CompletionsMenuSource>,
 5419        trigger: Option<&str>,
 5420        window: &mut Window,
 5421        cx: &mut Context<Self>,
 5422    ) {
 5423        if self.pending_rename.is_some() {
 5424            return;
 5425        }
 5426
 5427        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5428
 5429        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5430        // inserted and selected. To handle that case, the start of the selection is used so that
 5431        // the menu starts with all choices.
 5432        let position = self
 5433            .selections
 5434            .newest_anchor()
 5435            .start
 5436            .bias_right(&multibuffer_snapshot);
 5437        if position.diff_base_anchor.is_some() {
 5438            return;
 5439        }
 5440        let (buffer, buffer_position) =
 5441            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5442                output
 5443            } else {
 5444                return;
 5445            };
 5446        let buffer_snapshot = buffer.read(cx).snapshot();
 5447
 5448        let query: Option<Arc<String>> =
 5449            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5450
 5451        drop(multibuffer_snapshot);
 5452
 5453        let provider = match requested_source {
 5454            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5455            Some(CompletionsMenuSource::Words) => None,
 5456            Some(CompletionsMenuSource::SnippetChoices) => {
 5457                log::error!("bug: SnippetChoices requested_source is not handled");
 5458                None
 5459            }
 5460        };
 5461
 5462        let sort_completions = provider
 5463            .as_ref()
 5464            .is_some_and(|provider| provider.sort_completions());
 5465
 5466        let filter_completions = provider
 5467            .as_ref()
 5468            .is_none_or(|provider| provider.filter_completions());
 5469
 5470        let trigger_kind = match trigger {
 5471            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5472                CompletionTriggerKind::TRIGGER_CHARACTER
 5473            }
 5474            _ => CompletionTriggerKind::INVOKED,
 5475        };
 5476        let completion_context = CompletionContext {
 5477            trigger_character: trigger.and_then(|trigger| {
 5478                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5479                    Some(String::from(trigger))
 5480                } else {
 5481                    None
 5482                }
 5483            }),
 5484            trigger_kind,
 5485        };
 5486
 5487        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5488        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5489        // involve trigger chars, so this is skipped in that case.
 5490        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5491        {
 5492            let menu_is_open = matches!(
 5493                self.context_menu.borrow().as_ref(),
 5494                Some(CodeContextMenu::Completions(_))
 5495            );
 5496            if menu_is_open {
 5497                self.hide_context_menu(window, cx);
 5498            }
 5499        }
 5500
 5501        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5502            if filter_completions {
 5503                menu.filter(query.clone(), provider.clone(), window, cx);
 5504            }
 5505            // When `is_incomplete` is false, no need to re-query completions when the current query
 5506            // is a suffix of the initial query.
 5507            if !menu.is_incomplete {
 5508                // If the new query is a suffix of the old query (typing more characters) and
 5509                // the previous result was complete, the existing completions can be filtered.
 5510                //
 5511                // Note that this is always true for snippet completions.
 5512                let query_matches = match (&menu.initial_query, &query) {
 5513                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5514                    (None, _) => true,
 5515                    _ => false,
 5516                };
 5517                if query_matches {
 5518                    let position_matches = if menu.initial_position == position {
 5519                        true
 5520                    } else {
 5521                        let snapshot = self.buffer.read(cx).read(cx);
 5522                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5523                    };
 5524                    if position_matches {
 5525                        return;
 5526                    }
 5527                }
 5528            }
 5529        };
 5530
 5531        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5532            buffer_snapshot.surrounding_word(buffer_position, false)
 5533        {
 5534            let word_to_exclude = buffer_snapshot
 5535                .text_for_range(word_range.clone())
 5536                .collect::<String>();
 5537            (
 5538                buffer_snapshot.anchor_before(word_range.start)
 5539                    ..buffer_snapshot.anchor_after(buffer_position),
 5540                Some(word_to_exclude),
 5541            )
 5542        } else {
 5543            (buffer_position..buffer_position, None)
 5544        };
 5545
 5546        let language = buffer_snapshot
 5547            .language_at(buffer_position)
 5548            .map(|language| language.name());
 5549
 5550        let completion_settings =
 5551            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5552
 5553        let show_completion_documentation = buffer_snapshot
 5554            .settings_at(buffer_position, cx)
 5555            .show_completion_documentation;
 5556
 5557        // The document can be large, so stay in reasonable bounds when searching for words,
 5558        // otherwise completion pop-up might be slow to appear.
 5559        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5560        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5561        let min_word_search = buffer_snapshot.clip_point(
 5562            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5563            Bias::Left,
 5564        );
 5565        let max_word_search = buffer_snapshot.clip_point(
 5566            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5567            Bias::Right,
 5568        );
 5569        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5570            ..buffer_snapshot.point_to_offset(max_word_search);
 5571
 5572        let skip_digits = query
 5573            .as_ref()
 5574            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5575
 5576        let omit_word_completions = match &query {
 5577            Some(query) => query.chars().count() < completion_settings.words_min_length,
 5578            None => completion_settings.words_min_length != 0,
 5579        };
 5580
 5581        let (mut words, provider_responses) = match &provider {
 5582            Some(provider) => {
 5583                let provider_responses = provider.completions(
 5584                    position.excerpt_id,
 5585                    &buffer,
 5586                    buffer_position,
 5587                    completion_context,
 5588                    window,
 5589                    cx,
 5590                );
 5591
 5592                let words = match (omit_word_completions, completion_settings.words) {
 5593                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5594                        Task::ready(BTreeMap::default())
 5595                    }
 5596                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5597                        .background_spawn(async move {
 5598                            buffer_snapshot.words_in_range(WordsQuery {
 5599                                fuzzy_contents: None,
 5600                                range: word_search_range,
 5601                                skip_digits,
 5602                            })
 5603                        }),
 5604                };
 5605
 5606                (words, provider_responses)
 5607            }
 5608            None => {
 5609                let words = if omit_word_completions {
 5610                    Task::ready(BTreeMap::default())
 5611                } else {
 5612                    cx.background_spawn(async move {
 5613                        buffer_snapshot.words_in_range(WordsQuery {
 5614                            fuzzy_contents: None,
 5615                            range: word_search_range,
 5616                            skip_digits,
 5617                        })
 5618                    })
 5619                };
 5620                (words, Task::ready(Ok(Vec::new())))
 5621            }
 5622        };
 5623
 5624        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5625
 5626        let id = post_inc(&mut self.next_completion_id);
 5627        let task = cx.spawn_in(window, async move |editor, cx| {
 5628            let Ok(()) = editor.update(cx, |this, _| {
 5629                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5630            }) else {
 5631                return;
 5632            };
 5633
 5634            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5635            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5636            let mut completions = Vec::new();
 5637            let mut is_incomplete = false;
 5638            let mut display_options: Option<CompletionDisplayOptions> = None;
 5639            if let Some(provider_responses) = provider_responses.await.log_err()
 5640                && !provider_responses.is_empty()
 5641            {
 5642                for response in provider_responses {
 5643                    completions.extend(response.completions);
 5644                    is_incomplete = is_incomplete || response.is_incomplete;
 5645                    match display_options.as_mut() {
 5646                        None => {
 5647                            display_options = Some(response.display_options);
 5648                        }
 5649                        Some(options) => options.merge(&response.display_options),
 5650                    }
 5651                }
 5652                if completion_settings.words == WordsCompletionMode::Fallback {
 5653                    words = Task::ready(BTreeMap::default());
 5654                }
 5655            }
 5656            let display_options = display_options.unwrap_or_default();
 5657
 5658            let mut words = words.await;
 5659            if let Some(word_to_exclude) = &word_to_exclude {
 5660                words.remove(word_to_exclude);
 5661            }
 5662            for lsp_completion in &completions {
 5663                words.remove(&lsp_completion.new_text);
 5664            }
 5665            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5666                replace_range: word_replace_range.clone(),
 5667                new_text: word.clone(),
 5668                label: CodeLabel::plain(word, None),
 5669                icon_path: None,
 5670                documentation: None,
 5671                source: CompletionSource::BufferWord {
 5672                    word_range,
 5673                    resolved: false,
 5674                },
 5675                insert_text_mode: Some(InsertTextMode::AS_IS),
 5676                confirm: None,
 5677            }));
 5678
 5679            let menu = if completions.is_empty() {
 5680                None
 5681            } else {
 5682                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5683                    let languages = editor
 5684                        .workspace
 5685                        .as_ref()
 5686                        .and_then(|(workspace, _)| workspace.upgrade())
 5687                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5688                    let menu = CompletionsMenu::new(
 5689                        id,
 5690                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5691                        sort_completions,
 5692                        show_completion_documentation,
 5693                        position,
 5694                        query.clone(),
 5695                        is_incomplete,
 5696                        buffer.clone(),
 5697                        completions.into(),
 5698                        display_options,
 5699                        snippet_sort_order,
 5700                        languages,
 5701                        language,
 5702                        cx,
 5703                    );
 5704
 5705                    let query = if filter_completions { query } else { None };
 5706                    let matches_task = if let Some(query) = query {
 5707                        menu.do_async_filtering(query, cx)
 5708                    } else {
 5709                        Task::ready(menu.unfiltered_matches())
 5710                    };
 5711                    (menu, matches_task)
 5712                }) else {
 5713                    return;
 5714                };
 5715
 5716                let matches = matches_task.await;
 5717
 5718                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5719                    // Newer menu already set, so exit.
 5720                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5721                        editor.context_menu.borrow().as_ref()
 5722                        && prev_menu.id > id
 5723                    {
 5724                        return;
 5725                    };
 5726
 5727                    // Only valid to take prev_menu because it the new menu is immediately set
 5728                    // below, or the menu is hidden.
 5729                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5730                        editor.context_menu.borrow_mut().take()
 5731                    {
 5732                        let position_matches =
 5733                            if prev_menu.initial_position == menu.initial_position {
 5734                                true
 5735                            } else {
 5736                                let snapshot = editor.buffer.read(cx).read(cx);
 5737                                prev_menu.initial_position.to_offset(&snapshot)
 5738                                    == menu.initial_position.to_offset(&snapshot)
 5739                            };
 5740                        if position_matches {
 5741                            // Preserve markdown cache before `set_filter_results` because it will
 5742                            // try to populate the documentation cache.
 5743                            menu.preserve_markdown_cache(prev_menu);
 5744                        }
 5745                    };
 5746
 5747                    menu.set_filter_results(matches, provider, window, cx);
 5748                }) else {
 5749                    return;
 5750                };
 5751
 5752                menu.visible().then_some(menu)
 5753            };
 5754
 5755            editor
 5756                .update_in(cx, |editor, window, cx| {
 5757                    if editor.focus_handle.is_focused(window)
 5758                        && let Some(menu) = menu
 5759                    {
 5760                        *editor.context_menu.borrow_mut() =
 5761                            Some(CodeContextMenu::Completions(menu));
 5762
 5763                        crate::hover_popover::hide_hover(editor, cx);
 5764                        if editor.show_edit_predictions_in_menu() {
 5765                            editor.update_visible_edit_prediction(window, cx);
 5766                        } else {
 5767                            editor.discard_edit_prediction(false, cx);
 5768                        }
 5769
 5770                        cx.notify();
 5771                        return;
 5772                    }
 5773
 5774                    if editor.completion_tasks.len() <= 1 {
 5775                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5776                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5777                        // If it was already hidden and we don't show edit predictions in the menu,
 5778                        // we should also show the edit prediction when available.
 5779                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5780                            editor.update_visible_edit_prediction(window, cx);
 5781                        }
 5782                    }
 5783                })
 5784                .ok();
 5785        });
 5786
 5787        self.completion_tasks.push((id, task));
 5788    }
 5789
 5790    #[cfg(feature = "test-support")]
 5791    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5792        let menu = self.context_menu.borrow();
 5793        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5794            let completions = menu.completions.borrow();
 5795            Some(completions.to_vec())
 5796        } else {
 5797            None
 5798        }
 5799    }
 5800
 5801    pub fn with_completions_menu_matching_id<R>(
 5802        &self,
 5803        id: CompletionId,
 5804        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5805    ) -> R {
 5806        let mut context_menu = self.context_menu.borrow_mut();
 5807        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5808            return f(None);
 5809        };
 5810        if completions_menu.id != id {
 5811            return f(None);
 5812        }
 5813        f(Some(completions_menu))
 5814    }
 5815
 5816    pub fn confirm_completion(
 5817        &mut self,
 5818        action: &ConfirmCompletion,
 5819        window: &mut Window,
 5820        cx: &mut Context<Self>,
 5821    ) -> Option<Task<Result<()>>> {
 5822        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5823        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5824    }
 5825
 5826    pub fn confirm_completion_insert(
 5827        &mut self,
 5828        _: &ConfirmCompletionInsert,
 5829        window: &mut Window,
 5830        cx: &mut Context<Self>,
 5831    ) -> Option<Task<Result<()>>> {
 5832        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5833        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5834    }
 5835
 5836    pub fn confirm_completion_replace(
 5837        &mut self,
 5838        _: &ConfirmCompletionReplace,
 5839        window: &mut Window,
 5840        cx: &mut Context<Self>,
 5841    ) -> Option<Task<Result<()>>> {
 5842        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5843        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5844    }
 5845
 5846    pub fn compose_completion(
 5847        &mut self,
 5848        action: &ComposeCompletion,
 5849        window: &mut Window,
 5850        cx: &mut Context<Self>,
 5851    ) -> Option<Task<Result<()>>> {
 5852        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5853        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5854    }
 5855
 5856    fn do_completion(
 5857        &mut self,
 5858        item_ix: Option<usize>,
 5859        intent: CompletionIntent,
 5860        window: &mut Window,
 5861        cx: &mut Context<Editor>,
 5862    ) -> Option<Task<Result<()>>> {
 5863        use language::ToOffset as _;
 5864
 5865        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5866        else {
 5867            return None;
 5868        };
 5869
 5870        let candidate_id = {
 5871            let entries = completions_menu.entries.borrow();
 5872            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5873            if self.show_edit_predictions_in_menu() {
 5874                self.discard_edit_prediction(true, cx);
 5875            }
 5876            mat.candidate_id
 5877        };
 5878
 5879        let completion = completions_menu
 5880            .completions
 5881            .borrow()
 5882            .get(candidate_id)?
 5883            .clone();
 5884        cx.stop_propagation();
 5885
 5886        let buffer_handle = completions_menu.buffer.clone();
 5887
 5888        let CompletionEdit {
 5889            new_text,
 5890            snippet,
 5891            replace_range,
 5892        } = process_completion_for_edit(
 5893            &completion,
 5894            intent,
 5895            &buffer_handle,
 5896            &completions_menu.initial_position.text_anchor,
 5897            cx,
 5898        );
 5899
 5900        let buffer = buffer_handle.read(cx);
 5901        let snapshot = self.buffer.read(cx).snapshot(cx);
 5902        let newest_anchor = self.selections.newest_anchor();
 5903        let replace_range_multibuffer = {
 5904            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5905            let multibuffer_anchor = snapshot
 5906                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5907                .unwrap()
 5908                ..snapshot
 5909                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5910                    .unwrap();
 5911            multibuffer_anchor.start.to_offset(&snapshot)
 5912                ..multibuffer_anchor.end.to_offset(&snapshot)
 5913        };
 5914        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5915            return None;
 5916        }
 5917
 5918        let old_text = buffer
 5919            .text_for_range(replace_range.clone())
 5920            .collect::<String>();
 5921        let lookbehind = newest_anchor
 5922            .start
 5923            .text_anchor
 5924            .to_offset(buffer)
 5925            .saturating_sub(replace_range.start);
 5926        let lookahead = replace_range
 5927            .end
 5928            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5929        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5930        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5931
 5932        let selections = self.selections.all::<usize>(cx);
 5933        let mut ranges = Vec::new();
 5934        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5935
 5936        for selection in &selections {
 5937            let range = if selection.id == newest_anchor.id {
 5938                replace_range_multibuffer.clone()
 5939            } else {
 5940                let mut range = selection.range();
 5941
 5942                // if prefix is present, don't duplicate it
 5943                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5944                    range.start = range.start.saturating_sub(lookbehind);
 5945
 5946                    // if suffix is also present, mimic the newest cursor and replace it
 5947                    if selection.id != newest_anchor.id
 5948                        && snapshot.contains_str_at(range.end, suffix)
 5949                    {
 5950                        range.end += lookahead;
 5951                    }
 5952                }
 5953                range
 5954            };
 5955
 5956            ranges.push(range.clone());
 5957
 5958            if !self.linked_edit_ranges.is_empty() {
 5959                let start_anchor = snapshot.anchor_before(range.start);
 5960                let end_anchor = snapshot.anchor_after(range.end);
 5961                if let Some(ranges) = self
 5962                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5963                {
 5964                    for (buffer, edits) in ranges {
 5965                        linked_edits
 5966                            .entry(buffer.clone())
 5967                            .or_default()
 5968                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5969                    }
 5970                }
 5971            }
 5972        }
 5973
 5974        let common_prefix_len = old_text
 5975            .chars()
 5976            .zip(new_text.chars())
 5977            .take_while(|(a, b)| a == b)
 5978            .map(|(a, _)| a.len_utf8())
 5979            .sum::<usize>();
 5980
 5981        cx.emit(EditorEvent::InputHandled {
 5982            utf16_range_to_replace: None,
 5983            text: new_text[common_prefix_len..].into(),
 5984        });
 5985
 5986        self.transact(window, cx, |editor, window, cx| {
 5987            if let Some(mut snippet) = snippet {
 5988                snippet.text = new_text.to_string();
 5989                editor
 5990                    .insert_snippet(&ranges, snippet, window, cx)
 5991                    .log_err();
 5992            } else {
 5993                editor.buffer.update(cx, |multi_buffer, cx| {
 5994                    let auto_indent = match completion.insert_text_mode {
 5995                        Some(InsertTextMode::AS_IS) => None,
 5996                        _ => editor.autoindent_mode.clone(),
 5997                    };
 5998                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5999                    multi_buffer.edit(edits, auto_indent, cx);
 6000                });
 6001            }
 6002            for (buffer, edits) in linked_edits {
 6003                buffer.update(cx, |buffer, cx| {
 6004                    let snapshot = buffer.snapshot();
 6005                    let edits = edits
 6006                        .into_iter()
 6007                        .map(|(range, text)| {
 6008                            use text::ToPoint as TP;
 6009                            let end_point = TP::to_point(&range.end, &snapshot);
 6010                            let start_point = TP::to_point(&range.start, &snapshot);
 6011                            (start_point..end_point, text)
 6012                        })
 6013                        .sorted_by_key(|(range, _)| range.start);
 6014                    buffer.edit(edits, None, cx);
 6015                })
 6016            }
 6017
 6018            editor.refresh_edit_prediction(true, false, window, cx);
 6019        });
 6020        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6021
 6022        let show_new_completions_on_confirm = completion
 6023            .confirm
 6024            .as_ref()
 6025            .is_some_and(|confirm| confirm(intent, window, cx));
 6026        if show_new_completions_on_confirm {
 6027            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6028        }
 6029
 6030        let provider = self.completion_provider.as_ref()?;
 6031        drop(completion);
 6032        let apply_edits = provider.apply_additional_edits_for_completion(
 6033            buffer_handle,
 6034            completions_menu.completions.clone(),
 6035            candidate_id,
 6036            true,
 6037            cx,
 6038        );
 6039
 6040        let editor_settings = EditorSettings::get_global(cx);
 6041        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6042            // After the code completion is finished, users often want to know what signatures are needed.
 6043            // so we should automatically call signature_help
 6044            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6045        }
 6046
 6047        Some(cx.foreground_executor().spawn(async move {
 6048            apply_edits.await?;
 6049            Ok(())
 6050        }))
 6051    }
 6052
 6053    pub fn toggle_code_actions(
 6054        &mut self,
 6055        action: &ToggleCodeActions,
 6056        window: &mut Window,
 6057        cx: &mut Context<Self>,
 6058    ) {
 6059        let quick_launch = action.quick_launch;
 6060        let mut context_menu = self.context_menu.borrow_mut();
 6061        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6062            if code_actions.deployed_from == action.deployed_from {
 6063                // Toggle if we're selecting the same one
 6064                *context_menu = None;
 6065                cx.notify();
 6066                return;
 6067            } else {
 6068                // Otherwise, clear it and start a new one
 6069                *context_menu = None;
 6070                cx.notify();
 6071            }
 6072        }
 6073        drop(context_menu);
 6074        let snapshot = self.snapshot(window, cx);
 6075        let deployed_from = action.deployed_from.clone();
 6076        let action = action.clone();
 6077        self.completion_tasks.clear();
 6078        self.discard_edit_prediction(false, cx);
 6079
 6080        let multibuffer_point = match &action.deployed_from {
 6081            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6082                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6083            }
 6084            _ => self.selections.newest::<Point>(cx).head(),
 6085        };
 6086        let Some((buffer, buffer_row)) = snapshot
 6087            .buffer_snapshot
 6088            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6089            .and_then(|(buffer_snapshot, range)| {
 6090                self.buffer()
 6091                    .read(cx)
 6092                    .buffer(buffer_snapshot.remote_id())
 6093                    .map(|buffer| (buffer, range.start.row))
 6094            })
 6095        else {
 6096            return;
 6097        };
 6098        let buffer_id = buffer.read(cx).remote_id();
 6099        let tasks = self
 6100            .tasks
 6101            .get(&(buffer_id, buffer_row))
 6102            .map(|t| Arc::new(t.to_owned()));
 6103
 6104        if !self.focus_handle.is_focused(window) {
 6105            return;
 6106        }
 6107        let project = self.project.clone();
 6108
 6109        let code_actions_task = match deployed_from {
 6110            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6111            _ => self.code_actions(buffer_row, window, cx),
 6112        };
 6113
 6114        let runnable_task = match deployed_from {
 6115            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6116            _ => {
 6117                let mut task_context_task = Task::ready(None);
 6118                if let Some(tasks) = &tasks
 6119                    && let Some(project) = project
 6120                {
 6121                    task_context_task =
 6122                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6123                }
 6124
 6125                cx.spawn_in(window, {
 6126                    let buffer = buffer.clone();
 6127                    async move |editor, cx| {
 6128                        let task_context = task_context_task.await;
 6129
 6130                        let resolved_tasks =
 6131                            tasks
 6132                                .zip(task_context.clone())
 6133                                .map(|(tasks, task_context)| ResolvedTasks {
 6134                                    templates: tasks.resolve(&task_context).collect(),
 6135                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6136                                        multibuffer_point.row,
 6137                                        tasks.column,
 6138                                    )),
 6139                                });
 6140                        let debug_scenarios = editor
 6141                            .update(cx, |editor, cx| {
 6142                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6143                            })?
 6144                            .await;
 6145                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6146                    }
 6147                })
 6148            }
 6149        };
 6150
 6151        cx.spawn_in(window, async move |editor, cx| {
 6152            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6153            let code_actions = code_actions_task.await;
 6154            let spawn_straight_away = quick_launch
 6155                && resolved_tasks
 6156                    .as_ref()
 6157                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6158                && code_actions
 6159                    .as_ref()
 6160                    .is_none_or(|actions| actions.is_empty())
 6161                && debug_scenarios.is_empty();
 6162
 6163            editor.update_in(cx, |editor, window, cx| {
 6164                crate::hover_popover::hide_hover(editor, cx);
 6165                let actions = CodeActionContents::new(
 6166                    resolved_tasks,
 6167                    code_actions,
 6168                    debug_scenarios,
 6169                    task_context.unwrap_or_default(),
 6170                );
 6171
 6172                // Don't show the menu if there are no actions available
 6173                if actions.is_empty() {
 6174                    cx.notify();
 6175                    return Task::ready(Ok(()));
 6176                }
 6177
 6178                *editor.context_menu.borrow_mut() =
 6179                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6180                        buffer,
 6181                        actions,
 6182                        selected_item: Default::default(),
 6183                        scroll_handle: UniformListScrollHandle::default(),
 6184                        deployed_from,
 6185                    }));
 6186                cx.notify();
 6187                if spawn_straight_away
 6188                    && let Some(task) = editor.confirm_code_action(
 6189                        &ConfirmCodeAction { item_ix: Some(0) },
 6190                        window,
 6191                        cx,
 6192                    )
 6193                {
 6194                    return task;
 6195                }
 6196
 6197                Task::ready(Ok(()))
 6198            })
 6199        })
 6200        .detach_and_log_err(cx);
 6201    }
 6202
 6203    fn debug_scenarios(
 6204        &mut self,
 6205        resolved_tasks: &Option<ResolvedTasks>,
 6206        buffer: &Entity<Buffer>,
 6207        cx: &mut App,
 6208    ) -> Task<Vec<task::DebugScenario>> {
 6209        maybe!({
 6210            let project = self.project()?;
 6211            let dap_store = project.read(cx).dap_store();
 6212            let mut scenarios = vec![];
 6213            let resolved_tasks = resolved_tasks.as_ref()?;
 6214            let buffer = buffer.read(cx);
 6215            let language = buffer.language()?;
 6216            let file = buffer.file();
 6217            let debug_adapter = language_settings(language.name().into(), file, cx)
 6218                .debuggers
 6219                .first()
 6220                .map(SharedString::from)
 6221                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6222
 6223            dap_store.update(cx, |dap_store, cx| {
 6224                for (_, task) in &resolved_tasks.templates {
 6225                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6226                        task.original_task().clone(),
 6227                        debug_adapter.clone().into(),
 6228                        task.display_label().to_owned().into(),
 6229                        cx,
 6230                    );
 6231                    scenarios.push(maybe_scenario);
 6232                }
 6233            });
 6234            Some(cx.background_spawn(async move {
 6235                futures::future::join_all(scenarios)
 6236                    .await
 6237                    .into_iter()
 6238                    .flatten()
 6239                    .collect::<Vec<_>>()
 6240            }))
 6241        })
 6242        .unwrap_or_else(|| Task::ready(vec![]))
 6243    }
 6244
 6245    fn code_actions(
 6246        &mut self,
 6247        buffer_row: u32,
 6248        window: &mut Window,
 6249        cx: &mut Context<Self>,
 6250    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6251        let mut task = self.code_actions_task.take();
 6252        cx.spawn_in(window, async move |editor, cx| {
 6253            while let Some(prev_task) = task {
 6254                prev_task.await.log_err();
 6255                task = editor
 6256                    .update(cx, |this, _| this.code_actions_task.take())
 6257                    .ok()?;
 6258            }
 6259
 6260            editor
 6261                .update(cx, |editor, cx| {
 6262                    editor
 6263                        .available_code_actions
 6264                        .clone()
 6265                        .and_then(|(location, code_actions)| {
 6266                            let snapshot = location.buffer.read(cx).snapshot();
 6267                            let point_range = location.range.to_point(&snapshot);
 6268                            let point_range = point_range.start.row..=point_range.end.row;
 6269                            if point_range.contains(&buffer_row) {
 6270                                Some(code_actions)
 6271                            } else {
 6272                                None
 6273                            }
 6274                        })
 6275                })
 6276                .ok()
 6277                .flatten()
 6278        })
 6279    }
 6280
 6281    pub fn confirm_code_action(
 6282        &mut self,
 6283        action: &ConfirmCodeAction,
 6284        window: &mut Window,
 6285        cx: &mut Context<Self>,
 6286    ) -> Option<Task<Result<()>>> {
 6287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6288
 6289        let actions_menu =
 6290            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6291                menu
 6292            } else {
 6293                return None;
 6294            };
 6295
 6296        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6297        let action = actions_menu.actions.get(action_ix)?;
 6298        let title = action.label();
 6299        let buffer = actions_menu.buffer;
 6300        let workspace = self.workspace()?;
 6301
 6302        match action {
 6303            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6304                workspace.update(cx, |workspace, cx| {
 6305                    workspace.schedule_resolved_task(
 6306                        task_source_kind,
 6307                        resolved_task,
 6308                        false,
 6309                        window,
 6310                        cx,
 6311                    );
 6312
 6313                    Some(Task::ready(Ok(())))
 6314                })
 6315            }
 6316            CodeActionsItem::CodeAction {
 6317                excerpt_id,
 6318                action,
 6319                provider,
 6320            } => {
 6321                let apply_code_action =
 6322                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6323                let workspace = workspace.downgrade();
 6324                Some(cx.spawn_in(window, async move |editor, cx| {
 6325                    let project_transaction = apply_code_action.await?;
 6326                    Self::open_project_transaction(
 6327                        &editor,
 6328                        workspace,
 6329                        project_transaction,
 6330                        title,
 6331                        cx,
 6332                    )
 6333                    .await
 6334                }))
 6335            }
 6336            CodeActionsItem::DebugScenario(scenario) => {
 6337                let context = actions_menu.actions.context;
 6338
 6339                workspace.update(cx, |workspace, cx| {
 6340                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6341                    workspace.start_debug_session(
 6342                        scenario,
 6343                        context,
 6344                        Some(buffer),
 6345                        None,
 6346                        window,
 6347                        cx,
 6348                    );
 6349                });
 6350                Some(Task::ready(Ok(())))
 6351            }
 6352        }
 6353    }
 6354
 6355    pub async fn open_project_transaction(
 6356        editor: &WeakEntity<Editor>,
 6357        workspace: WeakEntity<Workspace>,
 6358        transaction: ProjectTransaction,
 6359        title: String,
 6360        cx: &mut AsyncWindowContext,
 6361    ) -> Result<()> {
 6362        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6363        cx.update(|_, cx| {
 6364            entries.sort_unstable_by_key(|(buffer, _)| {
 6365                buffer.read(cx).file().map(|f| f.path().clone())
 6366            });
 6367        })?;
 6368
 6369        // If the project transaction's edits are all contained within this editor, then
 6370        // avoid opening a new editor to display them.
 6371
 6372        if let Some((buffer, transaction)) = entries.first() {
 6373            if entries.len() == 1 {
 6374                let excerpt = editor.update(cx, |editor, cx| {
 6375                    editor
 6376                        .buffer()
 6377                        .read(cx)
 6378                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6379                })?;
 6380                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6381                    && excerpted_buffer == *buffer
 6382                {
 6383                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6384                        let excerpt_range = excerpt_range.to_offset(buffer);
 6385                        buffer
 6386                            .edited_ranges_for_transaction::<usize>(transaction)
 6387                            .all(|range| {
 6388                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6389                            })
 6390                    })?;
 6391
 6392                    if all_edits_within_excerpt {
 6393                        return Ok(());
 6394                    }
 6395                }
 6396            }
 6397        } else {
 6398            return Ok(());
 6399        }
 6400
 6401        let mut ranges_to_highlight = Vec::new();
 6402        let excerpt_buffer = cx.new(|cx| {
 6403            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6404            for (buffer_handle, transaction) in &entries {
 6405                let edited_ranges = buffer_handle
 6406                    .read(cx)
 6407                    .edited_ranges_for_transaction::<Point>(transaction)
 6408                    .collect::<Vec<_>>();
 6409                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6410                    PathKey::for_buffer(buffer_handle, cx),
 6411                    buffer_handle.clone(),
 6412                    edited_ranges,
 6413                    multibuffer_context_lines(cx),
 6414                    cx,
 6415                );
 6416
 6417                ranges_to_highlight.extend(ranges);
 6418            }
 6419            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6420            multibuffer
 6421        })?;
 6422
 6423        workspace.update_in(cx, |workspace, window, cx| {
 6424            let project = workspace.project().clone();
 6425            let editor =
 6426                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6427            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6428            editor.update(cx, |editor, cx| {
 6429                editor.highlight_background::<Self>(
 6430                    &ranges_to_highlight,
 6431                    |theme| theme.colors().editor_highlighted_line_background,
 6432                    cx,
 6433                );
 6434            });
 6435        })?;
 6436
 6437        Ok(())
 6438    }
 6439
 6440    pub fn clear_code_action_providers(&mut self) {
 6441        self.code_action_providers.clear();
 6442        self.available_code_actions.take();
 6443    }
 6444
 6445    pub fn add_code_action_provider(
 6446        &mut self,
 6447        provider: Rc<dyn CodeActionProvider>,
 6448        window: &mut Window,
 6449        cx: &mut Context<Self>,
 6450    ) {
 6451        if self
 6452            .code_action_providers
 6453            .iter()
 6454            .any(|existing_provider| existing_provider.id() == provider.id())
 6455        {
 6456            return;
 6457        }
 6458
 6459        self.code_action_providers.push(provider);
 6460        self.refresh_code_actions(window, cx);
 6461    }
 6462
 6463    pub fn remove_code_action_provider(
 6464        &mut self,
 6465        id: Arc<str>,
 6466        window: &mut Window,
 6467        cx: &mut Context<Self>,
 6468    ) {
 6469        self.code_action_providers
 6470            .retain(|provider| provider.id() != id);
 6471        self.refresh_code_actions(window, cx);
 6472    }
 6473
 6474    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6475        !self.code_action_providers.is_empty()
 6476            && EditorSettings::get_global(cx).toolbar.code_actions
 6477    }
 6478
 6479    pub fn has_available_code_actions(&self) -> bool {
 6480        self.available_code_actions
 6481            .as_ref()
 6482            .is_some_and(|(_, actions)| !actions.is_empty())
 6483    }
 6484
 6485    fn render_inline_code_actions(
 6486        &self,
 6487        icon_size: ui::IconSize,
 6488        display_row: DisplayRow,
 6489        is_active: bool,
 6490        cx: &mut Context<Self>,
 6491    ) -> AnyElement {
 6492        let show_tooltip = !self.context_menu_visible();
 6493        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6494            .icon_size(icon_size)
 6495            .shape(ui::IconButtonShape::Square)
 6496            .icon_color(ui::Color::Hidden)
 6497            .toggle_state(is_active)
 6498            .when(show_tooltip, |this| {
 6499                this.tooltip({
 6500                    let focus_handle = self.focus_handle.clone();
 6501                    move |window, cx| {
 6502                        Tooltip::for_action_in(
 6503                            "Toggle Code Actions",
 6504                            &ToggleCodeActions {
 6505                                deployed_from: None,
 6506                                quick_launch: false,
 6507                            },
 6508                            &focus_handle,
 6509                            window,
 6510                            cx,
 6511                        )
 6512                    }
 6513                })
 6514            })
 6515            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6516                window.focus(&editor.focus_handle(cx));
 6517                editor.toggle_code_actions(
 6518                    &crate::actions::ToggleCodeActions {
 6519                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6520                            display_row,
 6521                        )),
 6522                        quick_launch: false,
 6523                    },
 6524                    window,
 6525                    cx,
 6526                );
 6527            }))
 6528            .into_any_element()
 6529    }
 6530
 6531    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6532        &self.context_menu
 6533    }
 6534
 6535    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6536        let newest_selection = self.selections.newest_anchor().clone();
 6537        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6538        let buffer = self.buffer.read(cx);
 6539        if newest_selection.head().diff_base_anchor.is_some() {
 6540            return None;
 6541        }
 6542        let (start_buffer, start) =
 6543            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6544        let (end_buffer, end) =
 6545            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6546        if start_buffer != end_buffer {
 6547            return None;
 6548        }
 6549
 6550        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6551            cx.background_executor()
 6552                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6553                .await;
 6554
 6555            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6556                let providers = this.code_action_providers.clone();
 6557                let tasks = this
 6558                    .code_action_providers
 6559                    .iter()
 6560                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6561                    .collect::<Vec<_>>();
 6562                (providers, tasks)
 6563            })?;
 6564
 6565            let mut actions = Vec::new();
 6566            for (provider, provider_actions) in
 6567                providers.into_iter().zip(future::join_all(tasks).await)
 6568            {
 6569                if let Some(provider_actions) = provider_actions.log_err() {
 6570                    actions.extend(provider_actions.into_iter().map(|action| {
 6571                        AvailableCodeAction {
 6572                            excerpt_id: newest_selection.start.excerpt_id,
 6573                            action,
 6574                            provider: provider.clone(),
 6575                        }
 6576                    }));
 6577                }
 6578            }
 6579
 6580            this.update(cx, |this, cx| {
 6581                this.available_code_actions = if actions.is_empty() {
 6582                    None
 6583                } else {
 6584                    Some((
 6585                        Location {
 6586                            buffer: start_buffer,
 6587                            range: start..end,
 6588                        },
 6589                        actions.into(),
 6590                    ))
 6591                };
 6592                cx.notify();
 6593            })
 6594        }));
 6595        None
 6596    }
 6597
 6598    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6599        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6600            self.show_git_blame_inline = false;
 6601
 6602            self.show_git_blame_inline_delay_task =
 6603                Some(cx.spawn_in(window, async move |this, cx| {
 6604                    cx.background_executor().timer(delay).await;
 6605
 6606                    this.update(cx, |this, cx| {
 6607                        this.show_git_blame_inline = true;
 6608                        cx.notify();
 6609                    })
 6610                    .log_err();
 6611                }));
 6612        }
 6613    }
 6614
 6615    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6616        let snapshot = self.snapshot(window, cx);
 6617        let cursor = self.selections.newest::<Point>(cx).head();
 6618        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6619        else {
 6620            return;
 6621        };
 6622
 6623        let Some(blame) = self.blame.as_ref() else {
 6624            return;
 6625        };
 6626
 6627        let row_info = RowInfo {
 6628            buffer_id: Some(buffer.remote_id()),
 6629            buffer_row: Some(point.row),
 6630            ..Default::default()
 6631        };
 6632        let Some((buffer, blame_entry)) = blame
 6633            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6634            .flatten()
 6635        else {
 6636            return;
 6637        };
 6638
 6639        let anchor = self.selections.newest_anchor().head();
 6640        let position = self.to_pixel_point(anchor, &snapshot, window);
 6641        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6642            self.show_blame_popover(
 6643                buffer,
 6644                &blame_entry,
 6645                position + last_bounds.origin,
 6646                true,
 6647                cx,
 6648            );
 6649        };
 6650    }
 6651
 6652    fn show_blame_popover(
 6653        &mut self,
 6654        buffer: BufferId,
 6655        blame_entry: &BlameEntry,
 6656        position: gpui::Point<Pixels>,
 6657        ignore_timeout: bool,
 6658        cx: &mut Context<Self>,
 6659    ) {
 6660        if let Some(state) = &mut self.inline_blame_popover {
 6661            state.hide_task.take();
 6662        } else {
 6663            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6664            let blame_entry = blame_entry.clone();
 6665            let show_task = cx.spawn(async move |editor, cx| {
 6666                if !ignore_timeout {
 6667                    cx.background_executor()
 6668                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6669                        .await;
 6670                }
 6671                editor
 6672                    .update(cx, |editor, cx| {
 6673                        editor.inline_blame_popover_show_task.take();
 6674                        let Some(blame) = editor.blame.as_ref() else {
 6675                            return;
 6676                        };
 6677                        let blame = blame.read(cx);
 6678                        let details = blame.details_for_entry(buffer, &blame_entry);
 6679                        let markdown = cx.new(|cx| {
 6680                            Markdown::new(
 6681                                details
 6682                                    .as_ref()
 6683                                    .map(|message| message.message.clone())
 6684                                    .unwrap_or_default(),
 6685                                None,
 6686                                None,
 6687                                cx,
 6688                            )
 6689                        });
 6690                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6691                            position,
 6692                            hide_task: None,
 6693                            popover_bounds: None,
 6694                            popover_state: InlineBlamePopoverState {
 6695                                scroll_handle: ScrollHandle::new(),
 6696                                commit_message: details,
 6697                                markdown,
 6698                            },
 6699                            keyboard_grace: ignore_timeout,
 6700                        });
 6701                        cx.notify();
 6702                    })
 6703                    .ok();
 6704            });
 6705            self.inline_blame_popover_show_task = Some(show_task);
 6706        }
 6707    }
 6708
 6709    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6710        self.inline_blame_popover_show_task.take();
 6711        if let Some(state) = &mut self.inline_blame_popover {
 6712            let hide_task = cx.spawn(async move |editor, cx| {
 6713                cx.background_executor()
 6714                    .timer(std::time::Duration::from_millis(100))
 6715                    .await;
 6716                editor
 6717                    .update(cx, |editor, cx| {
 6718                        editor.inline_blame_popover.take();
 6719                        cx.notify();
 6720                    })
 6721                    .ok();
 6722            });
 6723            state.hide_task = Some(hide_task);
 6724        }
 6725    }
 6726
 6727    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6728        if self.pending_rename.is_some() {
 6729            return None;
 6730        }
 6731
 6732        let provider = self.semantics_provider.clone()?;
 6733        let buffer = self.buffer.read(cx);
 6734        let newest_selection = self.selections.newest_anchor().clone();
 6735        let cursor_position = newest_selection.head();
 6736        let (cursor_buffer, cursor_buffer_position) =
 6737            buffer.text_anchor_for_position(cursor_position, cx)?;
 6738        let (tail_buffer, tail_buffer_position) =
 6739            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6740        if cursor_buffer != tail_buffer {
 6741            return None;
 6742        }
 6743
 6744        let snapshot = cursor_buffer.read(cx).snapshot();
 6745        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6746        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6747        if start_word_range != end_word_range {
 6748            self.document_highlights_task.take();
 6749            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6750            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6751            return None;
 6752        }
 6753
 6754        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6755        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6756            cx.background_executor()
 6757                .timer(Duration::from_millis(debounce))
 6758                .await;
 6759
 6760            let highlights = if let Some(highlights) = cx
 6761                .update(|cx| {
 6762                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6763                })
 6764                .ok()
 6765                .flatten()
 6766            {
 6767                highlights.await.log_err()
 6768            } else {
 6769                None
 6770            };
 6771
 6772            if let Some(highlights) = highlights {
 6773                this.update(cx, |this, cx| {
 6774                    if this.pending_rename.is_some() {
 6775                        return;
 6776                    }
 6777
 6778                    let buffer = this.buffer.read(cx);
 6779                    if buffer
 6780                        .text_anchor_for_position(cursor_position, cx)
 6781                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6782                    {
 6783                        return;
 6784                    }
 6785
 6786                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6787                    let mut write_ranges = Vec::new();
 6788                    let mut read_ranges = Vec::new();
 6789                    for highlight in highlights {
 6790                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6791                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6792                        {
 6793                            let start = highlight
 6794                                .range
 6795                                .start
 6796                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6797                            let end = highlight
 6798                                .range
 6799                                .end
 6800                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6801                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6802                                continue;
 6803                            }
 6804
 6805                            let range = Anchor {
 6806                                buffer_id: Some(buffer_id),
 6807                                excerpt_id,
 6808                                text_anchor: start,
 6809                                diff_base_anchor: None,
 6810                            }..Anchor {
 6811                                buffer_id: Some(buffer_id),
 6812                                excerpt_id,
 6813                                text_anchor: end,
 6814                                diff_base_anchor: None,
 6815                            };
 6816                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6817                                write_ranges.push(range);
 6818                            } else {
 6819                                read_ranges.push(range);
 6820                            }
 6821                        }
 6822                    }
 6823
 6824                    this.highlight_background::<DocumentHighlightRead>(
 6825                        &read_ranges,
 6826                        |theme| theme.colors().editor_document_highlight_read_background,
 6827                        cx,
 6828                    );
 6829                    this.highlight_background::<DocumentHighlightWrite>(
 6830                        &write_ranges,
 6831                        |theme| theme.colors().editor_document_highlight_write_background,
 6832                        cx,
 6833                    );
 6834                    cx.notify();
 6835                })
 6836                .log_err();
 6837            }
 6838        }));
 6839        None
 6840    }
 6841
 6842    fn prepare_highlight_query_from_selection(
 6843        &mut self,
 6844        cx: &mut Context<Editor>,
 6845    ) -> Option<(String, Range<Anchor>)> {
 6846        if matches!(self.mode, EditorMode::SingleLine) {
 6847            return None;
 6848        }
 6849        if !EditorSettings::get_global(cx).selection_highlight {
 6850            return None;
 6851        }
 6852        if self.selections.count() != 1 || self.selections.line_mode {
 6853            return None;
 6854        }
 6855        let selection = self.selections.newest::<Point>(cx);
 6856        if selection.is_empty() || selection.start.row != selection.end.row {
 6857            return None;
 6858        }
 6859        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6860        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6861        let query = multi_buffer_snapshot
 6862            .text_for_range(selection_anchor_range.clone())
 6863            .collect::<String>();
 6864        if query.trim().is_empty() {
 6865            return None;
 6866        }
 6867        Some((query, selection_anchor_range))
 6868    }
 6869
 6870    fn update_selection_occurrence_highlights(
 6871        &mut self,
 6872        query_text: String,
 6873        query_range: Range<Anchor>,
 6874        multi_buffer_range_to_query: Range<Point>,
 6875        use_debounce: bool,
 6876        window: &mut Window,
 6877        cx: &mut Context<Editor>,
 6878    ) -> Task<()> {
 6879        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6880        cx.spawn_in(window, async move |editor, cx| {
 6881            if use_debounce {
 6882                cx.background_executor()
 6883                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6884                    .await;
 6885            }
 6886            let match_task = cx.background_spawn(async move {
 6887                let buffer_ranges = multi_buffer_snapshot
 6888                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6889                    .into_iter()
 6890                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6891                let mut match_ranges = Vec::new();
 6892                let Ok(regex) = project::search::SearchQuery::text(
 6893                    query_text.clone(),
 6894                    false,
 6895                    false,
 6896                    false,
 6897                    Default::default(),
 6898                    Default::default(),
 6899                    false,
 6900                    None,
 6901                ) else {
 6902                    return Vec::default();
 6903                };
 6904                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6905                    match_ranges.extend(
 6906                        regex
 6907                            .search(buffer_snapshot, Some(search_range.clone()))
 6908                            .await
 6909                            .into_iter()
 6910                            .filter_map(|match_range| {
 6911                                let match_start = buffer_snapshot
 6912                                    .anchor_after(search_range.start + match_range.start);
 6913                                let match_end = buffer_snapshot
 6914                                    .anchor_before(search_range.start + match_range.end);
 6915                                let match_anchor_range = Anchor::range_in_buffer(
 6916                                    excerpt_id,
 6917                                    buffer_snapshot.remote_id(),
 6918                                    match_start..match_end,
 6919                                );
 6920                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6921                            }),
 6922                    );
 6923                }
 6924                match_ranges
 6925            });
 6926            let match_ranges = match_task.await;
 6927            editor
 6928                .update_in(cx, |editor, _, cx| {
 6929                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6930                    if !match_ranges.is_empty() {
 6931                        editor.highlight_background::<SelectedTextHighlight>(
 6932                            &match_ranges,
 6933                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6934                            cx,
 6935                        )
 6936                    }
 6937                })
 6938                .log_err();
 6939        })
 6940    }
 6941
 6942    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6943        struct NewlineFold;
 6944        let type_id = std::any::TypeId::of::<NewlineFold>();
 6945        if !self.mode.is_single_line() {
 6946            return;
 6947        }
 6948        let snapshot = self.snapshot(window, cx);
 6949        if snapshot.buffer_snapshot.max_point().row == 0 {
 6950            return;
 6951        }
 6952        let task = cx.background_spawn(async move {
 6953            let new_newlines = snapshot
 6954                .buffer_chars_at(0)
 6955                .filter_map(|(c, i)| {
 6956                    if c == '\n' {
 6957                        Some(
 6958                            snapshot.buffer_snapshot.anchor_after(i)
 6959                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6960                        )
 6961                    } else {
 6962                        None
 6963                    }
 6964                })
 6965                .collect::<Vec<_>>();
 6966            let existing_newlines = snapshot
 6967                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6968                .filter_map(|fold| {
 6969                    if fold.placeholder.type_tag == Some(type_id) {
 6970                        Some(fold.range.start..fold.range.end)
 6971                    } else {
 6972                        None
 6973                    }
 6974                })
 6975                .collect::<Vec<_>>();
 6976
 6977            (new_newlines, existing_newlines)
 6978        });
 6979        self.folding_newlines = cx.spawn(async move |this, cx| {
 6980            let (new_newlines, existing_newlines) = task.await;
 6981            if new_newlines == existing_newlines {
 6982                return;
 6983            }
 6984            let placeholder = FoldPlaceholder {
 6985                render: Arc::new(move |_, _, cx| {
 6986                    div()
 6987                        .bg(cx.theme().status().hint_background)
 6988                        .border_b_1()
 6989                        .size_full()
 6990                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6991                        .border_color(cx.theme().status().hint)
 6992                        .child("\\n")
 6993                        .into_any()
 6994                }),
 6995                constrain_width: false,
 6996                merge_adjacent: false,
 6997                type_tag: Some(type_id),
 6998            };
 6999            let creases = new_newlines
 7000                .into_iter()
 7001                .map(|range| Crease::simple(range, placeholder.clone()))
 7002                .collect();
 7003            this.update(cx, |this, cx| {
 7004                this.display_map.update(cx, |display_map, cx| {
 7005                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7006                    display_map.fold(creases, cx);
 7007                });
 7008            })
 7009            .ok();
 7010        });
 7011    }
 7012
 7013    fn refresh_selected_text_highlights(
 7014        &mut self,
 7015        on_buffer_edit: bool,
 7016        window: &mut Window,
 7017        cx: &mut Context<Editor>,
 7018    ) {
 7019        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7020        else {
 7021            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7022            self.quick_selection_highlight_task.take();
 7023            self.debounced_selection_highlight_task.take();
 7024            return;
 7025        };
 7026        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7027        if on_buffer_edit
 7028            || self
 7029                .quick_selection_highlight_task
 7030                .as_ref()
 7031                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7032        {
 7033            let multi_buffer_visible_start = self
 7034                .scroll_manager
 7035                .anchor()
 7036                .anchor
 7037                .to_point(&multi_buffer_snapshot);
 7038            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7039                multi_buffer_visible_start
 7040                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7041                Bias::Left,
 7042            );
 7043            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7044            self.quick_selection_highlight_task = Some((
 7045                query_range.clone(),
 7046                self.update_selection_occurrence_highlights(
 7047                    query_text.clone(),
 7048                    query_range.clone(),
 7049                    multi_buffer_visible_range,
 7050                    false,
 7051                    window,
 7052                    cx,
 7053                ),
 7054            ));
 7055        }
 7056        if on_buffer_edit
 7057            || self
 7058                .debounced_selection_highlight_task
 7059                .as_ref()
 7060                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7061        {
 7062            let multi_buffer_start = multi_buffer_snapshot
 7063                .anchor_before(0)
 7064                .to_point(&multi_buffer_snapshot);
 7065            let multi_buffer_end = multi_buffer_snapshot
 7066                .anchor_after(multi_buffer_snapshot.len())
 7067                .to_point(&multi_buffer_snapshot);
 7068            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7069            self.debounced_selection_highlight_task = Some((
 7070                query_range.clone(),
 7071                self.update_selection_occurrence_highlights(
 7072                    query_text,
 7073                    query_range,
 7074                    multi_buffer_full_range,
 7075                    true,
 7076                    window,
 7077                    cx,
 7078                ),
 7079            ));
 7080        }
 7081    }
 7082
 7083    pub fn refresh_edit_prediction(
 7084        &mut self,
 7085        debounce: bool,
 7086        user_requested: bool,
 7087        window: &mut Window,
 7088        cx: &mut Context<Self>,
 7089    ) -> Option<()> {
 7090        if DisableAiSettings::get_global(cx).disable_ai {
 7091            return None;
 7092        }
 7093
 7094        let provider = self.edit_prediction_provider()?;
 7095        let cursor = self.selections.newest_anchor().head();
 7096        let (buffer, cursor_buffer_position) =
 7097            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7098
 7099        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7100            self.discard_edit_prediction(false, cx);
 7101            return None;
 7102        }
 7103
 7104        if !user_requested
 7105            && (!self.should_show_edit_predictions()
 7106                || !self.is_focused(window)
 7107                || buffer.read(cx).is_empty())
 7108        {
 7109            self.discard_edit_prediction(false, cx);
 7110            return None;
 7111        }
 7112
 7113        self.update_visible_edit_prediction(window, cx);
 7114        provider.refresh(
 7115            self.project.clone(),
 7116            buffer,
 7117            cursor_buffer_position,
 7118            debounce,
 7119            cx,
 7120        );
 7121        Some(())
 7122    }
 7123
 7124    fn show_edit_predictions_in_menu(&self) -> bool {
 7125        match self.edit_prediction_settings {
 7126            EditPredictionSettings::Disabled => false,
 7127            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7128        }
 7129    }
 7130
 7131    pub fn edit_predictions_enabled(&self) -> bool {
 7132        match self.edit_prediction_settings {
 7133            EditPredictionSettings::Disabled => false,
 7134            EditPredictionSettings::Enabled { .. } => true,
 7135        }
 7136    }
 7137
 7138    fn edit_prediction_requires_modifier(&self) -> bool {
 7139        match self.edit_prediction_settings {
 7140            EditPredictionSettings::Disabled => false,
 7141            EditPredictionSettings::Enabled {
 7142                preview_requires_modifier,
 7143                ..
 7144            } => preview_requires_modifier,
 7145        }
 7146    }
 7147
 7148    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7149        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7150            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7151            self.discard_edit_prediction(false, cx);
 7152        } else {
 7153            let selection = self.selections.newest_anchor();
 7154            let cursor = selection.head();
 7155
 7156            if let Some((buffer, cursor_buffer_position)) =
 7157                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7158            {
 7159                self.edit_prediction_settings =
 7160                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7161            }
 7162        }
 7163    }
 7164
 7165    fn edit_prediction_settings_at_position(
 7166        &self,
 7167        buffer: &Entity<Buffer>,
 7168        buffer_position: language::Anchor,
 7169        cx: &App,
 7170    ) -> EditPredictionSettings {
 7171        if !self.mode.is_full()
 7172            || !self.show_edit_predictions_override.unwrap_or(true)
 7173            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7174        {
 7175            return EditPredictionSettings::Disabled;
 7176        }
 7177
 7178        let buffer = buffer.read(cx);
 7179
 7180        let file = buffer.file();
 7181
 7182        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7183            return EditPredictionSettings::Disabled;
 7184        };
 7185
 7186        let by_provider = matches!(
 7187            self.menu_edit_predictions_policy,
 7188            MenuEditPredictionsPolicy::ByProvider
 7189        );
 7190
 7191        let show_in_menu = by_provider
 7192            && self
 7193                .edit_prediction_provider
 7194                .as_ref()
 7195                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7196
 7197        let preview_requires_modifier =
 7198            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7199
 7200        EditPredictionSettings::Enabled {
 7201            show_in_menu,
 7202            preview_requires_modifier,
 7203        }
 7204    }
 7205
 7206    fn should_show_edit_predictions(&self) -> bool {
 7207        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7208    }
 7209
 7210    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7211        matches!(
 7212            self.edit_prediction_preview,
 7213            EditPredictionPreview::Active { .. }
 7214        )
 7215    }
 7216
 7217    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7218        let cursor = self.selections.newest_anchor().head();
 7219        if let Some((buffer, cursor_position)) =
 7220            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7221        {
 7222            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7223        } else {
 7224            false
 7225        }
 7226    }
 7227
 7228    pub fn supports_minimap(&self, cx: &App) -> bool {
 7229        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7230    }
 7231
 7232    fn edit_predictions_enabled_in_buffer(
 7233        &self,
 7234        buffer: &Entity<Buffer>,
 7235        buffer_position: language::Anchor,
 7236        cx: &App,
 7237    ) -> bool {
 7238        maybe!({
 7239            if self.read_only(cx) {
 7240                return Some(false);
 7241            }
 7242            let provider = self.edit_prediction_provider()?;
 7243            if !provider.is_enabled(buffer, buffer_position, cx) {
 7244                return Some(false);
 7245            }
 7246            let buffer = buffer.read(cx);
 7247            let Some(file) = buffer.file() else {
 7248                return Some(true);
 7249            };
 7250            let settings = all_language_settings(Some(file), cx);
 7251            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7252        })
 7253        .unwrap_or(false)
 7254    }
 7255
 7256    fn cycle_edit_prediction(
 7257        &mut self,
 7258        direction: Direction,
 7259        window: &mut Window,
 7260        cx: &mut Context<Self>,
 7261    ) -> Option<()> {
 7262        let provider = self.edit_prediction_provider()?;
 7263        let cursor = self.selections.newest_anchor().head();
 7264        let (buffer, cursor_buffer_position) =
 7265            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7266        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7267            return None;
 7268        }
 7269
 7270        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7271        self.update_visible_edit_prediction(window, cx);
 7272
 7273        Some(())
 7274    }
 7275
 7276    pub fn show_edit_prediction(
 7277        &mut self,
 7278        _: &ShowEditPrediction,
 7279        window: &mut Window,
 7280        cx: &mut Context<Self>,
 7281    ) {
 7282        if !self.has_active_edit_prediction() {
 7283            self.refresh_edit_prediction(false, true, window, cx);
 7284            return;
 7285        }
 7286
 7287        self.update_visible_edit_prediction(window, cx);
 7288    }
 7289
 7290    pub fn display_cursor_names(
 7291        &mut self,
 7292        _: &DisplayCursorNames,
 7293        window: &mut Window,
 7294        cx: &mut Context<Self>,
 7295    ) {
 7296        self.show_cursor_names(window, cx);
 7297    }
 7298
 7299    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7300        self.show_cursor_names = true;
 7301        cx.notify();
 7302        cx.spawn_in(window, async move |this, cx| {
 7303            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7304            this.update(cx, |this, cx| {
 7305                this.show_cursor_names = false;
 7306                cx.notify()
 7307            })
 7308            .ok()
 7309        })
 7310        .detach();
 7311    }
 7312
 7313    pub fn next_edit_prediction(
 7314        &mut self,
 7315        _: &NextEditPrediction,
 7316        window: &mut Window,
 7317        cx: &mut Context<Self>,
 7318    ) {
 7319        if self.has_active_edit_prediction() {
 7320            self.cycle_edit_prediction(Direction::Next, window, cx);
 7321        } else {
 7322            let is_copilot_disabled = self
 7323                .refresh_edit_prediction(false, true, window, cx)
 7324                .is_none();
 7325            if is_copilot_disabled {
 7326                cx.propagate();
 7327            }
 7328        }
 7329    }
 7330
 7331    pub fn previous_edit_prediction(
 7332        &mut self,
 7333        _: &PreviousEditPrediction,
 7334        window: &mut Window,
 7335        cx: &mut Context<Self>,
 7336    ) {
 7337        if self.has_active_edit_prediction() {
 7338            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7339        } else {
 7340            let is_copilot_disabled = self
 7341                .refresh_edit_prediction(false, true, window, cx)
 7342                .is_none();
 7343            if is_copilot_disabled {
 7344                cx.propagate();
 7345            }
 7346        }
 7347    }
 7348
 7349    pub fn accept_edit_prediction(
 7350        &mut self,
 7351        _: &AcceptEditPrediction,
 7352        window: &mut Window,
 7353        cx: &mut Context<Self>,
 7354    ) {
 7355        if self.show_edit_predictions_in_menu() {
 7356            self.hide_context_menu(window, cx);
 7357        }
 7358
 7359        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7360            return;
 7361        };
 7362
 7363        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7364
 7365        match &active_edit_prediction.completion {
 7366            EditPrediction::Move { target, .. } => {
 7367                let target = *target;
 7368
 7369                if let Some(position_map) = &self.last_position_map {
 7370                    if position_map
 7371                        .visible_row_range
 7372                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7373                        || !self.edit_prediction_requires_modifier()
 7374                    {
 7375                        self.unfold_ranges(&[target..target], true, false, cx);
 7376                        // Note that this is also done in vim's handler of the Tab action.
 7377                        self.change_selections(
 7378                            SelectionEffects::scroll(Autoscroll::newest()),
 7379                            window,
 7380                            cx,
 7381                            |selections| {
 7382                                selections.select_anchor_ranges([target..target]);
 7383                            },
 7384                        );
 7385                        self.clear_row_highlights::<EditPredictionPreview>();
 7386
 7387                        self.edit_prediction_preview
 7388                            .set_previous_scroll_position(None);
 7389                    } else {
 7390                        self.edit_prediction_preview
 7391                            .set_previous_scroll_position(Some(
 7392                                position_map.snapshot.scroll_anchor,
 7393                            ));
 7394
 7395                        self.highlight_rows::<EditPredictionPreview>(
 7396                            target..target,
 7397                            cx.theme().colors().editor_highlighted_line_background,
 7398                            RowHighlightOptions {
 7399                                autoscroll: true,
 7400                                ..Default::default()
 7401                            },
 7402                            cx,
 7403                        );
 7404                        self.request_autoscroll(Autoscroll::fit(), cx);
 7405                    }
 7406                }
 7407            }
 7408            EditPrediction::Edit { edits, .. } => {
 7409                if let Some(provider) = self.edit_prediction_provider() {
 7410                    provider.accept(cx);
 7411                }
 7412
 7413                // Store the transaction ID and selections before applying the edit
 7414                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7415
 7416                let snapshot = self.buffer.read(cx).snapshot(cx);
 7417                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7418
 7419                self.buffer.update(cx, |buffer, cx| {
 7420                    buffer.edit(edits.iter().cloned(), None, cx)
 7421                });
 7422
 7423                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7424                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7425                });
 7426
 7427                let selections = self.selections.disjoint_anchors();
 7428                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7429                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7430                    if has_new_transaction {
 7431                        self.selection_history
 7432                            .insert_transaction(transaction_id_now, selections);
 7433                    }
 7434                }
 7435
 7436                self.update_visible_edit_prediction(window, cx);
 7437                if self.active_edit_prediction.is_none() {
 7438                    self.refresh_edit_prediction(true, true, window, cx);
 7439                }
 7440
 7441                cx.notify();
 7442            }
 7443        }
 7444
 7445        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7446    }
 7447
 7448    pub fn accept_partial_edit_prediction(
 7449        &mut self,
 7450        _: &AcceptPartialEditPrediction,
 7451        window: &mut Window,
 7452        cx: &mut Context<Self>,
 7453    ) {
 7454        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7455            return;
 7456        };
 7457        if self.selections.count() != 1 {
 7458            return;
 7459        }
 7460
 7461        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7462
 7463        match &active_edit_prediction.completion {
 7464            EditPrediction::Move { target, .. } => {
 7465                let target = *target;
 7466                self.change_selections(
 7467                    SelectionEffects::scroll(Autoscroll::newest()),
 7468                    window,
 7469                    cx,
 7470                    |selections| {
 7471                        selections.select_anchor_ranges([target..target]);
 7472                    },
 7473                );
 7474            }
 7475            EditPrediction::Edit { edits, .. } => {
 7476                // Find an insertion that starts at the cursor position.
 7477                let snapshot = self.buffer.read(cx).snapshot(cx);
 7478                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7479                let insertion = edits.iter().find_map(|(range, text)| {
 7480                    let range = range.to_offset(&snapshot);
 7481                    if range.is_empty() && range.start == cursor_offset {
 7482                        Some(text)
 7483                    } else {
 7484                        None
 7485                    }
 7486                });
 7487
 7488                if let Some(text) = insertion {
 7489                    let mut partial_completion = text
 7490                        .chars()
 7491                        .by_ref()
 7492                        .take_while(|c| c.is_alphabetic())
 7493                        .collect::<String>();
 7494                    if partial_completion.is_empty() {
 7495                        partial_completion = text
 7496                            .chars()
 7497                            .by_ref()
 7498                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7499                            .collect::<String>();
 7500                    }
 7501
 7502                    cx.emit(EditorEvent::InputHandled {
 7503                        utf16_range_to_replace: None,
 7504                        text: partial_completion.clone().into(),
 7505                    });
 7506
 7507                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7508
 7509                    self.refresh_edit_prediction(true, true, window, cx);
 7510                    cx.notify();
 7511                } else {
 7512                    self.accept_edit_prediction(&Default::default(), window, cx);
 7513                }
 7514            }
 7515        }
 7516    }
 7517
 7518    fn discard_edit_prediction(
 7519        &mut self,
 7520        should_report_edit_prediction_event: bool,
 7521        cx: &mut Context<Self>,
 7522    ) -> bool {
 7523        if should_report_edit_prediction_event {
 7524            let completion_id = self
 7525                .active_edit_prediction
 7526                .as_ref()
 7527                .and_then(|active_completion| active_completion.completion_id.clone());
 7528
 7529            self.report_edit_prediction_event(completion_id, false, cx);
 7530        }
 7531
 7532        if let Some(provider) = self.edit_prediction_provider() {
 7533            provider.discard(cx);
 7534        }
 7535
 7536        self.take_active_edit_prediction(cx)
 7537    }
 7538
 7539    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7540        let Some(provider) = self.edit_prediction_provider() else {
 7541            return;
 7542        };
 7543
 7544        let Some((_, buffer, _)) = self
 7545            .buffer
 7546            .read(cx)
 7547            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7548        else {
 7549            return;
 7550        };
 7551
 7552        let extension = buffer
 7553            .read(cx)
 7554            .file()
 7555            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7556
 7557        let event_type = match accepted {
 7558            true => "Edit Prediction Accepted",
 7559            false => "Edit Prediction Discarded",
 7560        };
 7561        telemetry::event!(
 7562            event_type,
 7563            provider = provider.name(),
 7564            prediction_id = id,
 7565            suggestion_accepted = accepted,
 7566            file_extension = extension,
 7567        );
 7568    }
 7569
 7570    pub fn has_active_edit_prediction(&self) -> bool {
 7571        self.active_edit_prediction.is_some()
 7572    }
 7573
 7574    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7575        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7576            return false;
 7577        };
 7578
 7579        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7580        self.clear_highlights::<EditPredictionHighlight>(cx);
 7581        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7582        true
 7583    }
 7584
 7585    /// Returns true when we're displaying the edit prediction popover below the cursor
 7586    /// like we are not previewing and the LSP autocomplete menu is visible
 7587    /// or we are in `when_holding_modifier` mode.
 7588    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7589        if self.edit_prediction_preview_is_active()
 7590            || !self.show_edit_predictions_in_menu()
 7591            || !self.edit_predictions_enabled()
 7592        {
 7593            return false;
 7594        }
 7595
 7596        if self.has_visible_completions_menu() {
 7597            return true;
 7598        }
 7599
 7600        has_completion && self.edit_prediction_requires_modifier()
 7601    }
 7602
 7603    fn handle_modifiers_changed(
 7604        &mut self,
 7605        modifiers: Modifiers,
 7606        position_map: &PositionMap,
 7607        window: &mut Window,
 7608        cx: &mut Context<Self>,
 7609    ) {
 7610        if self.show_edit_predictions_in_menu() {
 7611            self.update_edit_prediction_preview(&modifiers, window, cx);
 7612        }
 7613
 7614        self.update_selection_mode(&modifiers, position_map, window, cx);
 7615
 7616        let mouse_position = window.mouse_position();
 7617        if !position_map.text_hitbox.is_hovered(window) {
 7618            return;
 7619        }
 7620
 7621        self.update_hovered_link(
 7622            position_map.point_for_position(mouse_position),
 7623            &position_map.snapshot,
 7624            modifiers,
 7625            window,
 7626            cx,
 7627        )
 7628    }
 7629
 7630    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7631        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7632        if invert {
 7633            match multi_cursor_setting {
 7634                MultiCursorModifier::Alt => modifiers.alt,
 7635                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7636            }
 7637        } else {
 7638            match multi_cursor_setting {
 7639                MultiCursorModifier::Alt => modifiers.secondary(),
 7640                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7641            }
 7642        }
 7643    }
 7644
 7645    fn columnar_selection_mode(
 7646        modifiers: &Modifiers,
 7647        cx: &mut Context<Self>,
 7648    ) -> Option<ColumnarMode> {
 7649        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7650            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7651                Some(ColumnarMode::FromMouse)
 7652            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7653                Some(ColumnarMode::FromSelection)
 7654            } else {
 7655                None
 7656            }
 7657        } else {
 7658            None
 7659        }
 7660    }
 7661
 7662    fn update_selection_mode(
 7663        &mut self,
 7664        modifiers: &Modifiers,
 7665        position_map: &PositionMap,
 7666        window: &mut Window,
 7667        cx: &mut Context<Self>,
 7668    ) {
 7669        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7670            return;
 7671        };
 7672        if self.selections.pending.is_none() {
 7673            return;
 7674        }
 7675
 7676        let mouse_position = window.mouse_position();
 7677        let point_for_position = position_map.point_for_position(mouse_position);
 7678        let position = point_for_position.previous_valid;
 7679
 7680        self.select(
 7681            SelectPhase::BeginColumnar {
 7682                position,
 7683                reset: false,
 7684                mode,
 7685                goal_column: point_for_position.exact_unclipped.column(),
 7686            },
 7687            window,
 7688            cx,
 7689        );
 7690    }
 7691
 7692    fn update_edit_prediction_preview(
 7693        &mut self,
 7694        modifiers: &Modifiers,
 7695        window: &mut Window,
 7696        cx: &mut Context<Self>,
 7697    ) {
 7698        let mut modifiers_held = false;
 7699        if let Some(accept_keystroke) = self
 7700            .accept_edit_prediction_keybind(false, window, cx)
 7701            .keystroke()
 7702        {
 7703            modifiers_held = modifiers_held
 7704                || (accept_keystroke.modifiers() == modifiers
 7705                    && accept_keystroke.modifiers().modified());
 7706        };
 7707        if let Some(accept_partial_keystroke) = self
 7708            .accept_edit_prediction_keybind(true, window, cx)
 7709            .keystroke()
 7710        {
 7711            modifiers_held = modifiers_held
 7712                || (accept_partial_keystroke.modifiers() == modifiers
 7713                    && accept_partial_keystroke.modifiers().modified());
 7714        }
 7715
 7716        if modifiers_held {
 7717            if matches!(
 7718                self.edit_prediction_preview,
 7719                EditPredictionPreview::Inactive { .. }
 7720            ) {
 7721                self.edit_prediction_preview = EditPredictionPreview::Active {
 7722                    previous_scroll_position: None,
 7723                    since: Instant::now(),
 7724                };
 7725
 7726                self.update_visible_edit_prediction(window, cx);
 7727                cx.notify();
 7728            }
 7729        } else if let EditPredictionPreview::Active {
 7730            previous_scroll_position,
 7731            since,
 7732        } = self.edit_prediction_preview
 7733        {
 7734            if let (Some(previous_scroll_position), Some(position_map)) =
 7735                (previous_scroll_position, self.last_position_map.as_ref())
 7736            {
 7737                self.set_scroll_position(
 7738                    previous_scroll_position
 7739                        .scroll_position(&position_map.snapshot.display_snapshot),
 7740                    window,
 7741                    cx,
 7742                );
 7743            }
 7744
 7745            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7746                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7747            };
 7748            self.clear_row_highlights::<EditPredictionPreview>();
 7749            self.update_visible_edit_prediction(window, cx);
 7750            cx.notify();
 7751        }
 7752    }
 7753
 7754    fn update_visible_edit_prediction(
 7755        &mut self,
 7756        _window: &mut Window,
 7757        cx: &mut Context<Self>,
 7758    ) -> Option<()> {
 7759        if DisableAiSettings::get_global(cx).disable_ai {
 7760            return None;
 7761        }
 7762
 7763        if self.ime_transaction.is_some() {
 7764            self.discard_edit_prediction(false, cx);
 7765            return None;
 7766        }
 7767
 7768        let selection = self.selections.newest_anchor();
 7769        let cursor = selection.head();
 7770        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7771        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7772        let excerpt_id = cursor.excerpt_id;
 7773
 7774        let show_in_menu = self.show_edit_predictions_in_menu();
 7775        let completions_menu_has_precedence = !show_in_menu
 7776            && (self.context_menu.borrow().is_some()
 7777                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7778
 7779        if completions_menu_has_precedence
 7780            || !offset_selection.is_empty()
 7781            || self
 7782                .active_edit_prediction
 7783                .as_ref()
 7784                .is_some_and(|completion| {
 7785                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7786                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7787                    !invalidation_range.contains(&offset_selection.head())
 7788                })
 7789        {
 7790            self.discard_edit_prediction(false, cx);
 7791            return None;
 7792        }
 7793
 7794        self.take_active_edit_prediction(cx);
 7795        let Some(provider) = self.edit_prediction_provider() else {
 7796            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7797            return None;
 7798        };
 7799
 7800        let (buffer, cursor_buffer_position) =
 7801            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7802
 7803        self.edit_prediction_settings =
 7804            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7805
 7806        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7807            self.discard_edit_prediction(false, cx);
 7808            return None;
 7809        };
 7810
 7811        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7812
 7813        if self.edit_prediction_indent_conflict {
 7814            let cursor_point = cursor.to_point(&multibuffer);
 7815
 7816            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7817
 7818            if let Some((_, indent)) = indents.iter().next()
 7819                && indent.len == cursor_point.column
 7820            {
 7821                self.edit_prediction_indent_conflict = false;
 7822            }
 7823        }
 7824
 7825        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7826        let edits = edit_prediction
 7827            .edits
 7828            .into_iter()
 7829            .flat_map(|(range, new_text)| {
 7830                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7831                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7832                Some((start..end, new_text))
 7833            })
 7834            .collect::<Vec<_>>();
 7835        if edits.is_empty() {
 7836            return None;
 7837        }
 7838
 7839        let first_edit_start = edits.first().unwrap().0.start;
 7840        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7841        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7842
 7843        let last_edit_end = edits.last().unwrap().0.end;
 7844        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7845        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7846
 7847        let cursor_row = cursor.to_point(&multibuffer).row;
 7848
 7849        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7850
 7851        let mut inlay_ids = Vec::new();
 7852        let invalidation_row_range;
 7853        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7854            Some(cursor_row..edit_end_row)
 7855        } else if cursor_row > edit_end_row {
 7856            Some(edit_start_row..cursor_row)
 7857        } else {
 7858            None
 7859        };
 7860        let supports_jump = self
 7861            .edit_prediction_provider
 7862            .as_ref()
 7863            .map(|provider| provider.provider.supports_jump_to_edit())
 7864            .unwrap_or(true);
 7865
 7866        let is_move = supports_jump
 7867            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7868        let completion = if is_move {
 7869            invalidation_row_range =
 7870                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7871            let target = first_edit_start;
 7872            EditPrediction::Move { target, snapshot }
 7873        } else {
 7874            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7875                && !self.edit_predictions_hidden_for_vim_mode;
 7876
 7877            if show_completions_in_buffer {
 7878                if edits
 7879                    .iter()
 7880                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7881                {
 7882                    let mut inlays = Vec::new();
 7883                    for (range, new_text) in &edits {
 7884                        let inlay = Inlay::edit_prediction(
 7885                            post_inc(&mut self.next_inlay_id),
 7886                            range.start,
 7887                            new_text.as_str(),
 7888                        );
 7889                        inlay_ids.push(inlay.id);
 7890                        inlays.push(inlay);
 7891                    }
 7892
 7893                    self.splice_inlays(&[], inlays, cx);
 7894                } else {
 7895                    let background_color = cx.theme().status().deleted_background;
 7896                    self.highlight_text::<EditPredictionHighlight>(
 7897                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7898                        HighlightStyle {
 7899                            background_color: Some(background_color),
 7900                            ..Default::default()
 7901                        },
 7902                        cx,
 7903                    );
 7904                }
 7905            }
 7906
 7907            invalidation_row_range = edit_start_row..edit_end_row;
 7908
 7909            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7910                if provider.show_tab_accept_marker() {
 7911                    EditDisplayMode::TabAccept
 7912                } else {
 7913                    EditDisplayMode::Inline
 7914                }
 7915            } else {
 7916                EditDisplayMode::DiffPopover
 7917            };
 7918
 7919            EditPrediction::Edit {
 7920                edits,
 7921                edit_preview: edit_prediction.edit_preview,
 7922                display_mode,
 7923                snapshot,
 7924            }
 7925        };
 7926
 7927        let invalidation_range = multibuffer
 7928            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7929            ..multibuffer.anchor_after(Point::new(
 7930                invalidation_row_range.end,
 7931                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7932            ));
 7933
 7934        self.stale_edit_prediction_in_menu = None;
 7935        self.active_edit_prediction = Some(EditPredictionState {
 7936            inlay_ids,
 7937            completion,
 7938            completion_id: edit_prediction.id,
 7939            invalidation_range,
 7940        });
 7941
 7942        cx.notify();
 7943
 7944        Some(())
 7945    }
 7946
 7947    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7948        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7949    }
 7950
 7951    fn clear_tasks(&mut self) {
 7952        self.tasks.clear()
 7953    }
 7954
 7955    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7956        if self.tasks.insert(key, value).is_some() {
 7957            // This case should hopefully be rare, but just in case...
 7958            log::error!(
 7959                "multiple different run targets found on a single line, only the last target will be rendered"
 7960            )
 7961        }
 7962    }
 7963
 7964    /// Get all display points of breakpoints that will be rendered within editor
 7965    ///
 7966    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7967    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7968    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7969    fn active_breakpoints(
 7970        &self,
 7971        range: Range<DisplayRow>,
 7972        window: &mut Window,
 7973        cx: &mut Context<Self>,
 7974    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7975        let mut breakpoint_display_points = HashMap::default();
 7976
 7977        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7978            return breakpoint_display_points;
 7979        };
 7980
 7981        let snapshot = self.snapshot(window, cx);
 7982
 7983        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7984        let Some(project) = self.project() else {
 7985            return breakpoint_display_points;
 7986        };
 7987
 7988        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7989            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7990
 7991        for (buffer_snapshot, range, excerpt_id) in
 7992            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7993        {
 7994            let Some(buffer) = project
 7995                .read(cx)
 7996                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7997            else {
 7998                continue;
 7999            };
 8000            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8001                &buffer,
 8002                Some(
 8003                    buffer_snapshot.anchor_before(range.start)
 8004                        ..buffer_snapshot.anchor_after(range.end),
 8005                ),
 8006                buffer_snapshot,
 8007                cx,
 8008            );
 8009            for (breakpoint, state) in breakpoints {
 8010                let multi_buffer_anchor =
 8011                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8012                let position = multi_buffer_anchor
 8013                    .to_point(multi_buffer_snapshot)
 8014                    .to_display_point(&snapshot);
 8015
 8016                breakpoint_display_points.insert(
 8017                    position.row(),
 8018                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8019                );
 8020            }
 8021        }
 8022
 8023        breakpoint_display_points
 8024    }
 8025
 8026    fn breakpoint_context_menu(
 8027        &self,
 8028        anchor: Anchor,
 8029        window: &mut Window,
 8030        cx: &mut Context<Self>,
 8031    ) -> Entity<ui::ContextMenu> {
 8032        let weak_editor = cx.weak_entity();
 8033        let focus_handle = self.focus_handle(cx);
 8034
 8035        let row = self
 8036            .buffer
 8037            .read(cx)
 8038            .snapshot(cx)
 8039            .summary_for_anchor::<Point>(&anchor)
 8040            .row;
 8041
 8042        let breakpoint = self
 8043            .breakpoint_at_row(row, window, cx)
 8044            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8045
 8046        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8047            "Edit Log Breakpoint"
 8048        } else {
 8049            "Set Log Breakpoint"
 8050        };
 8051
 8052        let condition_breakpoint_msg = if breakpoint
 8053            .as_ref()
 8054            .is_some_and(|bp| bp.1.condition.is_some())
 8055        {
 8056            "Edit Condition Breakpoint"
 8057        } else {
 8058            "Set Condition Breakpoint"
 8059        };
 8060
 8061        let hit_condition_breakpoint_msg = if breakpoint
 8062            .as_ref()
 8063            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8064        {
 8065            "Edit Hit Condition Breakpoint"
 8066        } else {
 8067            "Set Hit Condition Breakpoint"
 8068        };
 8069
 8070        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8071            "Unset Breakpoint"
 8072        } else {
 8073            "Set Breakpoint"
 8074        };
 8075
 8076        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8077
 8078        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8079            BreakpointState::Enabled => Some("Disable"),
 8080            BreakpointState::Disabled => Some("Enable"),
 8081        });
 8082
 8083        let (anchor, breakpoint) =
 8084            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8085
 8086        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8087            menu.on_blur_subscription(Subscription::new(|| {}))
 8088                .context(focus_handle)
 8089                .when(run_to_cursor, |this| {
 8090                    let weak_editor = weak_editor.clone();
 8091                    this.entry("Run to cursor", None, move |window, cx| {
 8092                        weak_editor
 8093                            .update(cx, |editor, cx| {
 8094                                editor.change_selections(
 8095                                    SelectionEffects::no_scroll(),
 8096                                    window,
 8097                                    cx,
 8098                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8099                                );
 8100                            })
 8101                            .ok();
 8102
 8103                        window.dispatch_action(Box::new(RunToCursor), cx);
 8104                    })
 8105                    .separator()
 8106                })
 8107                .when_some(toggle_state_msg, |this, msg| {
 8108                    this.entry(msg, None, {
 8109                        let weak_editor = weak_editor.clone();
 8110                        let breakpoint = breakpoint.clone();
 8111                        move |_window, cx| {
 8112                            weak_editor
 8113                                .update(cx, |this, cx| {
 8114                                    this.edit_breakpoint_at_anchor(
 8115                                        anchor,
 8116                                        breakpoint.as_ref().clone(),
 8117                                        BreakpointEditAction::InvertState,
 8118                                        cx,
 8119                                    );
 8120                                })
 8121                                .log_err();
 8122                        }
 8123                    })
 8124                })
 8125                .entry(set_breakpoint_msg, None, {
 8126                    let weak_editor = weak_editor.clone();
 8127                    let breakpoint = breakpoint.clone();
 8128                    move |_window, cx| {
 8129                        weak_editor
 8130                            .update(cx, |this, cx| {
 8131                                this.edit_breakpoint_at_anchor(
 8132                                    anchor,
 8133                                    breakpoint.as_ref().clone(),
 8134                                    BreakpointEditAction::Toggle,
 8135                                    cx,
 8136                                );
 8137                            })
 8138                            .log_err();
 8139                    }
 8140                })
 8141                .entry(log_breakpoint_msg, None, {
 8142                    let breakpoint = breakpoint.clone();
 8143                    let weak_editor = weak_editor.clone();
 8144                    move |window, cx| {
 8145                        weak_editor
 8146                            .update(cx, |this, cx| {
 8147                                this.add_edit_breakpoint_block(
 8148                                    anchor,
 8149                                    breakpoint.as_ref(),
 8150                                    BreakpointPromptEditAction::Log,
 8151                                    window,
 8152                                    cx,
 8153                                );
 8154                            })
 8155                            .log_err();
 8156                    }
 8157                })
 8158                .entry(condition_breakpoint_msg, None, {
 8159                    let breakpoint = breakpoint.clone();
 8160                    let weak_editor = weak_editor.clone();
 8161                    move |window, cx| {
 8162                        weak_editor
 8163                            .update(cx, |this, cx| {
 8164                                this.add_edit_breakpoint_block(
 8165                                    anchor,
 8166                                    breakpoint.as_ref(),
 8167                                    BreakpointPromptEditAction::Condition,
 8168                                    window,
 8169                                    cx,
 8170                                );
 8171                            })
 8172                            .log_err();
 8173                    }
 8174                })
 8175                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8176                    weak_editor
 8177                        .update(cx, |this, cx| {
 8178                            this.add_edit_breakpoint_block(
 8179                                anchor,
 8180                                breakpoint.as_ref(),
 8181                                BreakpointPromptEditAction::HitCondition,
 8182                                window,
 8183                                cx,
 8184                            );
 8185                        })
 8186                        .log_err();
 8187                })
 8188        })
 8189    }
 8190
 8191    fn render_breakpoint(
 8192        &self,
 8193        position: Anchor,
 8194        row: DisplayRow,
 8195        breakpoint: &Breakpoint,
 8196        state: Option<BreakpointSessionState>,
 8197        cx: &mut Context<Self>,
 8198    ) -> IconButton {
 8199        let is_rejected = state.is_some_and(|s| !s.verified);
 8200        // Is it a breakpoint that shows up when hovering over gutter?
 8201        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8202            (false, false),
 8203            |PhantomBreakpointIndicator {
 8204                 is_active,
 8205                 display_row,
 8206                 collides_with_existing_breakpoint,
 8207             }| {
 8208                (
 8209                    is_active && display_row == row,
 8210                    collides_with_existing_breakpoint,
 8211                )
 8212            },
 8213        );
 8214
 8215        let (color, icon) = {
 8216            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8217                (false, false) => ui::IconName::DebugBreakpoint,
 8218                (true, false) => ui::IconName::DebugLogBreakpoint,
 8219                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8220                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8221            };
 8222
 8223            let color = if is_phantom {
 8224                Color::Hint
 8225            } else if is_rejected {
 8226                Color::Disabled
 8227            } else {
 8228                Color::Debugger
 8229            };
 8230
 8231            (color, icon)
 8232        };
 8233
 8234        let breakpoint = Arc::from(breakpoint.clone());
 8235
 8236        let alt_as_text = gpui::Keystroke {
 8237            modifiers: Modifiers::secondary_key(),
 8238            ..Default::default()
 8239        };
 8240        let primary_action_text = if breakpoint.is_disabled() {
 8241            "Enable breakpoint"
 8242        } else if is_phantom && !collides_with_existing {
 8243            "Set breakpoint"
 8244        } else {
 8245            "Unset breakpoint"
 8246        };
 8247        let focus_handle = self.focus_handle.clone();
 8248
 8249        let meta = if is_rejected {
 8250            SharedString::from("No executable code is associated with this line.")
 8251        } else if collides_with_existing && !breakpoint.is_disabled() {
 8252            SharedString::from(format!(
 8253                "{alt_as_text}-click to disable,\nright-click for more options."
 8254            ))
 8255        } else {
 8256            SharedString::from("Right-click for more options.")
 8257        };
 8258        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8259            .icon_size(IconSize::XSmall)
 8260            .size(ui::ButtonSize::None)
 8261            .when(is_rejected, |this| {
 8262                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8263            })
 8264            .icon_color(color)
 8265            .style(ButtonStyle::Transparent)
 8266            .on_click(cx.listener({
 8267                move |editor, event: &ClickEvent, window, cx| {
 8268                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8269                        BreakpointEditAction::InvertState
 8270                    } else {
 8271                        BreakpointEditAction::Toggle
 8272                    };
 8273
 8274                    window.focus(&editor.focus_handle(cx));
 8275                    editor.edit_breakpoint_at_anchor(
 8276                        position,
 8277                        breakpoint.as_ref().clone(),
 8278                        edit_action,
 8279                        cx,
 8280                    );
 8281                }
 8282            }))
 8283            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8284                editor.set_breakpoint_context_menu(
 8285                    row,
 8286                    Some(position),
 8287                    event.position(),
 8288                    window,
 8289                    cx,
 8290                );
 8291            }))
 8292            .tooltip(move |window, cx| {
 8293                Tooltip::with_meta_in(
 8294                    primary_action_text,
 8295                    Some(&ToggleBreakpoint),
 8296                    meta.clone(),
 8297                    &focus_handle,
 8298                    window,
 8299                    cx,
 8300                )
 8301            })
 8302    }
 8303
 8304    fn build_tasks_context(
 8305        project: &Entity<Project>,
 8306        buffer: &Entity<Buffer>,
 8307        buffer_row: u32,
 8308        tasks: &Arc<RunnableTasks>,
 8309        cx: &mut Context<Self>,
 8310    ) -> Task<Option<task::TaskContext>> {
 8311        let position = Point::new(buffer_row, tasks.column);
 8312        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8313        let location = Location {
 8314            buffer: buffer.clone(),
 8315            range: range_start..range_start,
 8316        };
 8317        // Fill in the environmental variables from the tree-sitter captures
 8318        let mut captured_task_variables = TaskVariables::default();
 8319        for (capture_name, value) in tasks.extra_variables.clone() {
 8320            captured_task_variables.insert(
 8321                task::VariableName::Custom(capture_name.into()),
 8322                value.clone(),
 8323            );
 8324        }
 8325        project.update(cx, |project, cx| {
 8326            project.task_store().update(cx, |task_store, cx| {
 8327                task_store.task_context_for_location(captured_task_variables, location, cx)
 8328            })
 8329        })
 8330    }
 8331
 8332    pub fn spawn_nearest_task(
 8333        &mut self,
 8334        action: &SpawnNearestTask,
 8335        window: &mut Window,
 8336        cx: &mut Context<Self>,
 8337    ) {
 8338        let Some((workspace, _)) = self.workspace.clone() else {
 8339            return;
 8340        };
 8341        let Some(project) = self.project.clone() else {
 8342            return;
 8343        };
 8344
 8345        // Try to find a closest, enclosing node using tree-sitter that has a task
 8346        let Some((buffer, buffer_row, tasks)) = self
 8347            .find_enclosing_node_task(cx)
 8348            // Or find the task that's closest in row-distance.
 8349            .or_else(|| self.find_closest_task(cx))
 8350        else {
 8351            return;
 8352        };
 8353
 8354        let reveal_strategy = action.reveal;
 8355        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8356        cx.spawn_in(window, async move |_, cx| {
 8357            let context = task_context.await?;
 8358            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8359
 8360            let resolved = &mut resolved_task.resolved;
 8361            resolved.reveal = reveal_strategy;
 8362
 8363            workspace
 8364                .update_in(cx, |workspace, window, cx| {
 8365                    workspace.schedule_resolved_task(
 8366                        task_source_kind,
 8367                        resolved_task,
 8368                        false,
 8369                        window,
 8370                        cx,
 8371                    );
 8372                })
 8373                .ok()
 8374        })
 8375        .detach();
 8376    }
 8377
 8378    fn find_closest_task(
 8379        &mut self,
 8380        cx: &mut Context<Self>,
 8381    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8382        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8383
 8384        let ((buffer_id, row), tasks) = self
 8385            .tasks
 8386            .iter()
 8387            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8388
 8389        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8390        let tasks = Arc::new(tasks.to_owned());
 8391        Some((buffer, *row, tasks))
 8392    }
 8393
 8394    fn find_enclosing_node_task(
 8395        &mut self,
 8396        cx: &mut Context<Self>,
 8397    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8398        let snapshot = self.buffer.read(cx).snapshot(cx);
 8399        let offset = self.selections.newest::<usize>(cx).head();
 8400        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8401        let buffer_id = excerpt.buffer().remote_id();
 8402
 8403        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8404        let mut cursor = layer.node().walk();
 8405
 8406        while cursor.goto_first_child_for_byte(offset).is_some() {
 8407            if cursor.node().end_byte() == offset {
 8408                cursor.goto_next_sibling();
 8409            }
 8410        }
 8411
 8412        // Ascend to the smallest ancestor that contains the range and has a task.
 8413        loop {
 8414            let node = cursor.node();
 8415            let node_range = node.byte_range();
 8416            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8417
 8418            // Check if this node contains our offset
 8419            if node_range.start <= offset && node_range.end >= offset {
 8420                // If it contains offset, check for task
 8421                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8422                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8423                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8424                }
 8425            }
 8426
 8427            if !cursor.goto_parent() {
 8428                break;
 8429            }
 8430        }
 8431        None
 8432    }
 8433
 8434    fn render_run_indicator(
 8435        &self,
 8436        _style: &EditorStyle,
 8437        is_active: bool,
 8438        row: DisplayRow,
 8439        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8440        cx: &mut Context<Self>,
 8441    ) -> IconButton {
 8442        let color = Color::Muted;
 8443        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8444
 8445        IconButton::new(
 8446            ("run_indicator", row.0 as usize),
 8447            ui::IconName::PlayOutlined,
 8448        )
 8449        .shape(ui::IconButtonShape::Square)
 8450        .icon_size(IconSize::XSmall)
 8451        .icon_color(color)
 8452        .toggle_state(is_active)
 8453        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8454            let quick_launch = match e {
 8455                ClickEvent::Keyboard(_) => true,
 8456                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8457            };
 8458
 8459            window.focus(&editor.focus_handle(cx));
 8460            editor.toggle_code_actions(
 8461                &ToggleCodeActions {
 8462                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8463                    quick_launch,
 8464                },
 8465                window,
 8466                cx,
 8467            );
 8468        }))
 8469        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8470            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8471        }))
 8472    }
 8473
 8474    pub fn context_menu_visible(&self) -> bool {
 8475        !self.edit_prediction_preview_is_active()
 8476            && self
 8477                .context_menu
 8478                .borrow()
 8479                .as_ref()
 8480                .is_some_and(|menu| menu.visible())
 8481    }
 8482
 8483    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8484        self.context_menu
 8485            .borrow()
 8486            .as_ref()
 8487            .map(|menu| menu.origin())
 8488    }
 8489
 8490    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8491        self.context_menu_options = Some(options);
 8492    }
 8493
 8494    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8495    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8496
 8497    fn render_edit_prediction_popover(
 8498        &mut self,
 8499        text_bounds: &Bounds<Pixels>,
 8500        content_origin: gpui::Point<Pixels>,
 8501        right_margin: Pixels,
 8502        editor_snapshot: &EditorSnapshot,
 8503        visible_row_range: Range<DisplayRow>,
 8504        scroll_top: f32,
 8505        scroll_bottom: f32,
 8506        line_layouts: &[LineWithInvisibles],
 8507        line_height: Pixels,
 8508        scroll_pixel_position: gpui::Point<Pixels>,
 8509        newest_selection_head: Option<DisplayPoint>,
 8510        editor_width: Pixels,
 8511        style: &EditorStyle,
 8512        window: &mut Window,
 8513        cx: &mut App,
 8514    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8515        if self.mode().is_minimap() {
 8516            return None;
 8517        }
 8518        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8519
 8520        if self.edit_prediction_visible_in_cursor_popover(true) {
 8521            return None;
 8522        }
 8523
 8524        match &active_edit_prediction.completion {
 8525            EditPrediction::Move { target, .. } => {
 8526                let target_display_point = target.to_display_point(editor_snapshot);
 8527
 8528                if self.edit_prediction_requires_modifier() {
 8529                    if !self.edit_prediction_preview_is_active() {
 8530                        return None;
 8531                    }
 8532
 8533                    self.render_edit_prediction_modifier_jump_popover(
 8534                        text_bounds,
 8535                        content_origin,
 8536                        visible_row_range,
 8537                        line_layouts,
 8538                        line_height,
 8539                        scroll_pixel_position,
 8540                        newest_selection_head,
 8541                        target_display_point,
 8542                        window,
 8543                        cx,
 8544                    )
 8545                } else {
 8546                    self.render_edit_prediction_eager_jump_popover(
 8547                        text_bounds,
 8548                        content_origin,
 8549                        editor_snapshot,
 8550                        visible_row_range,
 8551                        scroll_top,
 8552                        scroll_bottom,
 8553                        line_height,
 8554                        scroll_pixel_position,
 8555                        target_display_point,
 8556                        editor_width,
 8557                        window,
 8558                        cx,
 8559                    )
 8560                }
 8561            }
 8562            EditPrediction::Edit {
 8563                display_mode: EditDisplayMode::Inline,
 8564                ..
 8565            } => None,
 8566            EditPrediction::Edit {
 8567                display_mode: EditDisplayMode::TabAccept,
 8568                edits,
 8569                ..
 8570            } => {
 8571                let range = &edits.first()?.0;
 8572                let target_display_point = range.end.to_display_point(editor_snapshot);
 8573
 8574                self.render_edit_prediction_end_of_line_popover(
 8575                    "Accept",
 8576                    editor_snapshot,
 8577                    visible_row_range,
 8578                    target_display_point,
 8579                    line_height,
 8580                    scroll_pixel_position,
 8581                    content_origin,
 8582                    editor_width,
 8583                    window,
 8584                    cx,
 8585                )
 8586            }
 8587            EditPrediction::Edit {
 8588                edits,
 8589                edit_preview,
 8590                display_mode: EditDisplayMode::DiffPopover,
 8591                snapshot,
 8592            } => self.render_edit_prediction_diff_popover(
 8593                text_bounds,
 8594                content_origin,
 8595                right_margin,
 8596                editor_snapshot,
 8597                visible_row_range,
 8598                line_layouts,
 8599                line_height,
 8600                scroll_pixel_position,
 8601                newest_selection_head,
 8602                editor_width,
 8603                style,
 8604                edits,
 8605                edit_preview,
 8606                snapshot,
 8607                window,
 8608                cx,
 8609            ),
 8610        }
 8611    }
 8612
 8613    fn render_edit_prediction_modifier_jump_popover(
 8614        &mut self,
 8615        text_bounds: &Bounds<Pixels>,
 8616        content_origin: gpui::Point<Pixels>,
 8617        visible_row_range: Range<DisplayRow>,
 8618        line_layouts: &[LineWithInvisibles],
 8619        line_height: Pixels,
 8620        scroll_pixel_position: gpui::Point<Pixels>,
 8621        newest_selection_head: Option<DisplayPoint>,
 8622        target_display_point: DisplayPoint,
 8623        window: &mut Window,
 8624        cx: &mut App,
 8625    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8626        let scrolled_content_origin =
 8627            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8628
 8629        const SCROLL_PADDING_Y: Pixels = px(12.);
 8630
 8631        if target_display_point.row() < visible_row_range.start {
 8632            return self.render_edit_prediction_scroll_popover(
 8633                |_| SCROLL_PADDING_Y,
 8634                IconName::ArrowUp,
 8635                visible_row_range,
 8636                line_layouts,
 8637                newest_selection_head,
 8638                scrolled_content_origin,
 8639                window,
 8640                cx,
 8641            );
 8642        } else if target_display_point.row() >= visible_row_range.end {
 8643            return self.render_edit_prediction_scroll_popover(
 8644                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8645                IconName::ArrowDown,
 8646                visible_row_range,
 8647                line_layouts,
 8648                newest_selection_head,
 8649                scrolled_content_origin,
 8650                window,
 8651                cx,
 8652            );
 8653        }
 8654
 8655        const POLE_WIDTH: Pixels = px(2.);
 8656
 8657        let line_layout =
 8658            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8659        let target_column = target_display_point.column() as usize;
 8660
 8661        let target_x = line_layout.x_for_index(target_column);
 8662        let target_y =
 8663            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8664
 8665        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8666
 8667        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8668        border_color.l += 0.001;
 8669
 8670        let mut element = v_flex()
 8671            .items_end()
 8672            .when(flag_on_right, |el| el.items_start())
 8673            .child(if flag_on_right {
 8674                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8675                    .rounded_bl(px(0.))
 8676                    .rounded_tl(px(0.))
 8677                    .border_l_2()
 8678                    .border_color(border_color)
 8679            } else {
 8680                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8681                    .rounded_br(px(0.))
 8682                    .rounded_tr(px(0.))
 8683                    .border_r_2()
 8684                    .border_color(border_color)
 8685            })
 8686            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8687            .into_any();
 8688
 8689        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8690
 8691        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8692            - point(
 8693                if flag_on_right {
 8694                    POLE_WIDTH
 8695                } else {
 8696                    size.width - POLE_WIDTH
 8697                },
 8698                size.height - line_height,
 8699            );
 8700
 8701        origin.x = origin.x.max(content_origin.x);
 8702
 8703        element.prepaint_at(origin, window, cx);
 8704
 8705        Some((element, origin))
 8706    }
 8707
 8708    fn render_edit_prediction_scroll_popover(
 8709        &mut self,
 8710        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8711        scroll_icon: IconName,
 8712        visible_row_range: Range<DisplayRow>,
 8713        line_layouts: &[LineWithInvisibles],
 8714        newest_selection_head: Option<DisplayPoint>,
 8715        scrolled_content_origin: gpui::Point<Pixels>,
 8716        window: &mut Window,
 8717        cx: &mut App,
 8718    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8719        let mut element = self
 8720            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8721            .into_any();
 8722
 8723        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8724
 8725        let cursor = newest_selection_head?;
 8726        let cursor_row_layout =
 8727            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8728        let cursor_column = cursor.column() as usize;
 8729
 8730        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8731
 8732        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8733
 8734        element.prepaint_at(origin, window, cx);
 8735        Some((element, origin))
 8736    }
 8737
 8738    fn render_edit_prediction_eager_jump_popover(
 8739        &mut self,
 8740        text_bounds: &Bounds<Pixels>,
 8741        content_origin: gpui::Point<Pixels>,
 8742        editor_snapshot: &EditorSnapshot,
 8743        visible_row_range: Range<DisplayRow>,
 8744        scroll_top: f32,
 8745        scroll_bottom: f32,
 8746        line_height: Pixels,
 8747        scroll_pixel_position: gpui::Point<Pixels>,
 8748        target_display_point: DisplayPoint,
 8749        editor_width: Pixels,
 8750        window: &mut Window,
 8751        cx: &mut App,
 8752    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8753        if target_display_point.row().as_f32() < scroll_top {
 8754            let mut element = self
 8755                .render_edit_prediction_line_popover(
 8756                    "Jump to Edit",
 8757                    Some(IconName::ArrowUp),
 8758                    window,
 8759                    cx,
 8760                )?
 8761                .into_any();
 8762
 8763            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8764            let offset = point(
 8765                (text_bounds.size.width - size.width) / 2.,
 8766                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8767            );
 8768
 8769            let origin = text_bounds.origin + offset;
 8770            element.prepaint_at(origin, window, cx);
 8771            Some((element, origin))
 8772        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8773            let mut element = self
 8774                .render_edit_prediction_line_popover(
 8775                    "Jump to Edit",
 8776                    Some(IconName::ArrowDown),
 8777                    window,
 8778                    cx,
 8779                )?
 8780                .into_any();
 8781
 8782            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8783            let offset = point(
 8784                (text_bounds.size.width - size.width) / 2.,
 8785                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8786            );
 8787
 8788            let origin = text_bounds.origin + offset;
 8789            element.prepaint_at(origin, window, cx);
 8790            Some((element, origin))
 8791        } else {
 8792            self.render_edit_prediction_end_of_line_popover(
 8793                "Jump to Edit",
 8794                editor_snapshot,
 8795                visible_row_range,
 8796                target_display_point,
 8797                line_height,
 8798                scroll_pixel_position,
 8799                content_origin,
 8800                editor_width,
 8801                window,
 8802                cx,
 8803            )
 8804        }
 8805    }
 8806
 8807    fn render_edit_prediction_end_of_line_popover(
 8808        self: &mut Editor,
 8809        label: &'static str,
 8810        editor_snapshot: &EditorSnapshot,
 8811        visible_row_range: Range<DisplayRow>,
 8812        target_display_point: DisplayPoint,
 8813        line_height: Pixels,
 8814        scroll_pixel_position: gpui::Point<Pixels>,
 8815        content_origin: gpui::Point<Pixels>,
 8816        editor_width: Pixels,
 8817        window: &mut Window,
 8818        cx: &mut App,
 8819    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8820        let target_line_end = DisplayPoint::new(
 8821            target_display_point.row(),
 8822            editor_snapshot.line_len(target_display_point.row()),
 8823        );
 8824
 8825        let mut element = self
 8826            .render_edit_prediction_line_popover(label, None, window, cx)?
 8827            .into_any();
 8828
 8829        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8830
 8831        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8832
 8833        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8834        let mut origin = start_point
 8835            + line_origin
 8836            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8837        origin.x = origin.x.max(content_origin.x);
 8838
 8839        let max_x = content_origin.x + editor_width - size.width;
 8840
 8841        if origin.x > max_x {
 8842            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8843
 8844            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8845                origin.y += offset;
 8846                IconName::ArrowUp
 8847            } else {
 8848                origin.y -= offset;
 8849                IconName::ArrowDown
 8850            };
 8851
 8852            element = self
 8853                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8854                .into_any();
 8855
 8856            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8857
 8858            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8859        }
 8860
 8861        element.prepaint_at(origin, window, cx);
 8862        Some((element, origin))
 8863    }
 8864
 8865    fn render_edit_prediction_diff_popover(
 8866        self: &Editor,
 8867        text_bounds: &Bounds<Pixels>,
 8868        content_origin: gpui::Point<Pixels>,
 8869        right_margin: Pixels,
 8870        editor_snapshot: &EditorSnapshot,
 8871        visible_row_range: Range<DisplayRow>,
 8872        line_layouts: &[LineWithInvisibles],
 8873        line_height: Pixels,
 8874        scroll_pixel_position: gpui::Point<Pixels>,
 8875        newest_selection_head: Option<DisplayPoint>,
 8876        editor_width: Pixels,
 8877        style: &EditorStyle,
 8878        edits: &Vec<(Range<Anchor>, String)>,
 8879        edit_preview: &Option<language::EditPreview>,
 8880        snapshot: &language::BufferSnapshot,
 8881        window: &mut Window,
 8882        cx: &mut App,
 8883    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8884        let edit_start = edits
 8885            .first()
 8886            .unwrap()
 8887            .0
 8888            .start
 8889            .to_display_point(editor_snapshot);
 8890        let edit_end = edits
 8891            .last()
 8892            .unwrap()
 8893            .0
 8894            .end
 8895            .to_display_point(editor_snapshot);
 8896
 8897        let is_visible = visible_row_range.contains(&edit_start.row())
 8898            || visible_row_range.contains(&edit_end.row());
 8899        if !is_visible {
 8900            return None;
 8901        }
 8902
 8903        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8904            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8905        } else {
 8906            // Fallback for providers without edit_preview
 8907            crate::edit_prediction_fallback_text(edits, cx)
 8908        };
 8909
 8910        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8911        let line_count = highlighted_edits.text.lines().count();
 8912
 8913        const BORDER_WIDTH: Pixels = px(1.);
 8914
 8915        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8916        let has_keybind = keybind.is_some();
 8917
 8918        let mut element = h_flex()
 8919            .items_start()
 8920            .child(
 8921                h_flex()
 8922                    .bg(cx.theme().colors().editor_background)
 8923                    .border(BORDER_WIDTH)
 8924                    .shadow_xs()
 8925                    .border_color(cx.theme().colors().border)
 8926                    .rounded_l_lg()
 8927                    .when(line_count > 1, |el| el.rounded_br_lg())
 8928                    .pr_1()
 8929                    .child(styled_text),
 8930            )
 8931            .child(
 8932                h_flex()
 8933                    .h(line_height + BORDER_WIDTH * 2.)
 8934                    .px_1p5()
 8935                    .gap_1()
 8936                    // Workaround: For some reason, there's a gap if we don't do this
 8937                    .ml(-BORDER_WIDTH)
 8938                    .shadow(vec![gpui::BoxShadow {
 8939                        color: gpui::black().opacity(0.05),
 8940                        offset: point(px(1.), px(1.)),
 8941                        blur_radius: px(2.),
 8942                        spread_radius: px(0.),
 8943                    }])
 8944                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8945                    .border(BORDER_WIDTH)
 8946                    .border_color(cx.theme().colors().border)
 8947                    .rounded_r_lg()
 8948                    .id("edit_prediction_diff_popover_keybind")
 8949                    .when(!has_keybind, |el| {
 8950                        let status_colors = cx.theme().status();
 8951
 8952                        el.bg(status_colors.error_background)
 8953                            .border_color(status_colors.error.opacity(0.6))
 8954                            .child(Icon::new(IconName::Info).color(Color::Error))
 8955                            .cursor_default()
 8956                            .hoverable_tooltip(move |_window, cx| {
 8957                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8958                            })
 8959                    })
 8960                    .children(keybind),
 8961            )
 8962            .into_any();
 8963
 8964        let longest_row =
 8965            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8966        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8967            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8968        } else {
 8969            layout_line(
 8970                longest_row,
 8971                editor_snapshot,
 8972                style,
 8973                editor_width,
 8974                |_| false,
 8975                window,
 8976                cx,
 8977            )
 8978            .width
 8979        };
 8980
 8981        let viewport_bounds =
 8982            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8983                right: -right_margin,
 8984                ..Default::default()
 8985            });
 8986
 8987        let x_after_longest =
 8988            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8989                - scroll_pixel_position.x;
 8990
 8991        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8992
 8993        // Fully visible if it can be displayed within the window (allow overlapping other
 8994        // panes). However, this is only allowed if the popover starts within text_bounds.
 8995        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8996            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8997
 8998        let mut origin = if can_position_to_the_right {
 8999            point(
 9000                x_after_longest,
 9001                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9002                    - scroll_pixel_position.y,
 9003            )
 9004        } else {
 9005            let cursor_row = newest_selection_head.map(|head| head.row());
 9006            let above_edit = edit_start
 9007                .row()
 9008                .0
 9009                .checked_sub(line_count as u32)
 9010                .map(DisplayRow);
 9011            let below_edit = Some(edit_end.row() + 1);
 9012            let above_cursor =
 9013                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9014            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9015
 9016            // Place the edit popover adjacent to the edit if there is a location
 9017            // available that is onscreen and does not obscure the cursor. Otherwise,
 9018            // place it adjacent to the cursor.
 9019            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9020                .into_iter()
 9021                .flatten()
 9022                .find(|&start_row| {
 9023                    let end_row = start_row + line_count as u32;
 9024                    visible_row_range.contains(&start_row)
 9025                        && visible_row_range.contains(&end_row)
 9026                        && cursor_row
 9027                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9028                })?;
 9029
 9030            content_origin
 9031                + point(
 9032                    -scroll_pixel_position.x,
 9033                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9034                )
 9035        };
 9036
 9037        origin.x -= BORDER_WIDTH;
 9038
 9039        window.defer_draw(element, origin, 1);
 9040
 9041        // Do not return an element, since it will already be drawn due to defer_draw.
 9042        None
 9043    }
 9044
 9045    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9046        px(30.)
 9047    }
 9048
 9049    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9050        if self.read_only(cx) {
 9051            cx.theme().players().read_only()
 9052        } else {
 9053            self.style.as_ref().unwrap().local_player
 9054        }
 9055    }
 9056
 9057    fn render_edit_prediction_accept_keybind(
 9058        &self,
 9059        window: &mut Window,
 9060        cx: &App,
 9061    ) -> Option<AnyElement> {
 9062        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9063        let accept_keystroke = accept_binding.keystroke()?;
 9064
 9065        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9066
 9067        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9068            Color::Accent
 9069        } else {
 9070            Color::Muted
 9071        };
 9072
 9073        h_flex()
 9074            .px_0p5()
 9075            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9076            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9077            .text_size(TextSize::XSmall.rems(cx))
 9078            .child(h_flex().children(ui::render_modifiers(
 9079                accept_keystroke.modifiers(),
 9080                PlatformStyle::platform(),
 9081                Some(modifiers_color),
 9082                Some(IconSize::XSmall.rems().into()),
 9083                true,
 9084            )))
 9085            .when(is_platform_style_mac, |parent| {
 9086                parent.child(accept_keystroke.key().to_string())
 9087            })
 9088            .when(!is_platform_style_mac, |parent| {
 9089                parent.child(
 9090                    Key::new(
 9091                        util::capitalize(accept_keystroke.key()),
 9092                        Some(Color::Default),
 9093                    )
 9094                    .size(Some(IconSize::XSmall.rems().into())),
 9095                )
 9096            })
 9097            .into_any()
 9098            .into()
 9099    }
 9100
 9101    fn render_edit_prediction_line_popover(
 9102        &self,
 9103        label: impl Into<SharedString>,
 9104        icon: Option<IconName>,
 9105        window: &mut Window,
 9106        cx: &App,
 9107    ) -> Option<Stateful<Div>> {
 9108        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9109
 9110        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9111        let has_keybind = keybind.is_some();
 9112
 9113        let result = h_flex()
 9114            .id("ep-line-popover")
 9115            .py_0p5()
 9116            .pl_1()
 9117            .pr(padding_right)
 9118            .gap_1()
 9119            .rounded_md()
 9120            .border_1()
 9121            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9122            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9123            .shadow_xs()
 9124            .when(!has_keybind, |el| {
 9125                let status_colors = cx.theme().status();
 9126
 9127                el.bg(status_colors.error_background)
 9128                    .border_color(status_colors.error.opacity(0.6))
 9129                    .pl_2()
 9130                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9131                    .cursor_default()
 9132                    .hoverable_tooltip(move |_window, cx| {
 9133                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9134                    })
 9135            })
 9136            .children(keybind)
 9137            .child(
 9138                Label::new(label)
 9139                    .size(LabelSize::Small)
 9140                    .when(!has_keybind, |el| {
 9141                        el.color(cx.theme().status().error.into()).strikethrough()
 9142                    }),
 9143            )
 9144            .when(!has_keybind, |el| {
 9145                el.child(
 9146                    h_flex().ml_1().child(
 9147                        Icon::new(IconName::Info)
 9148                            .size(IconSize::Small)
 9149                            .color(cx.theme().status().error.into()),
 9150                    ),
 9151                )
 9152            })
 9153            .when_some(icon, |element, icon| {
 9154                element.child(
 9155                    div()
 9156                        .mt(px(1.5))
 9157                        .child(Icon::new(icon).size(IconSize::Small)),
 9158                )
 9159            });
 9160
 9161        Some(result)
 9162    }
 9163
 9164    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9165        let accent_color = cx.theme().colors().text_accent;
 9166        let editor_bg_color = cx.theme().colors().editor_background;
 9167        editor_bg_color.blend(accent_color.opacity(0.1))
 9168    }
 9169
 9170    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9171        let accent_color = cx.theme().colors().text_accent;
 9172        let editor_bg_color = cx.theme().colors().editor_background;
 9173        editor_bg_color.blend(accent_color.opacity(0.6))
 9174    }
 9175    fn get_prediction_provider_icon_name(
 9176        provider: &Option<RegisteredEditPredictionProvider>,
 9177    ) -> IconName {
 9178        match provider {
 9179            Some(provider) => match provider.provider.name() {
 9180                "copilot" => IconName::Copilot,
 9181                "supermaven" => IconName::Supermaven,
 9182                _ => IconName::ZedPredict,
 9183            },
 9184            None => IconName::ZedPredict,
 9185        }
 9186    }
 9187
 9188    fn render_edit_prediction_cursor_popover(
 9189        &self,
 9190        min_width: Pixels,
 9191        max_width: Pixels,
 9192        cursor_point: Point,
 9193        style: &EditorStyle,
 9194        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9195        _window: &Window,
 9196        cx: &mut Context<Editor>,
 9197    ) -> Option<AnyElement> {
 9198        let provider = self.edit_prediction_provider.as_ref()?;
 9199        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9200
 9201        let is_refreshing = provider.provider.is_refreshing(cx);
 9202
 9203        fn pending_completion_container(icon: IconName) -> Div {
 9204            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9205        }
 9206
 9207        let completion = match &self.active_edit_prediction {
 9208            Some(prediction) => {
 9209                if !self.has_visible_completions_menu() {
 9210                    const RADIUS: Pixels = px(6.);
 9211                    const BORDER_WIDTH: Pixels = px(1.);
 9212
 9213                    return Some(
 9214                        h_flex()
 9215                            .elevation_2(cx)
 9216                            .border(BORDER_WIDTH)
 9217                            .border_color(cx.theme().colors().border)
 9218                            .when(accept_keystroke.is_none(), |el| {
 9219                                el.border_color(cx.theme().status().error)
 9220                            })
 9221                            .rounded(RADIUS)
 9222                            .rounded_tl(px(0.))
 9223                            .overflow_hidden()
 9224                            .child(div().px_1p5().child(match &prediction.completion {
 9225                                EditPrediction::Move { target, snapshot } => {
 9226                                    use text::ToPoint as _;
 9227                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9228                                    {
 9229                                        Icon::new(IconName::ZedPredictDown)
 9230                                    } else {
 9231                                        Icon::new(IconName::ZedPredictUp)
 9232                                    }
 9233                                }
 9234                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9235                            }))
 9236                            .child(
 9237                                h_flex()
 9238                                    .gap_1()
 9239                                    .py_1()
 9240                                    .px_2()
 9241                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9242                                    .border_l_1()
 9243                                    .border_color(cx.theme().colors().border)
 9244                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9245                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9246                                        el.child(
 9247                                            Label::new("Hold")
 9248                                                .size(LabelSize::Small)
 9249                                                .when(accept_keystroke.is_none(), |el| {
 9250                                                    el.strikethrough()
 9251                                                })
 9252                                                .line_height_style(LineHeightStyle::UiLabel),
 9253                                        )
 9254                                    })
 9255                                    .id("edit_prediction_cursor_popover_keybind")
 9256                                    .when(accept_keystroke.is_none(), |el| {
 9257                                        let status_colors = cx.theme().status();
 9258
 9259                                        el.bg(status_colors.error_background)
 9260                                            .border_color(status_colors.error.opacity(0.6))
 9261                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9262                                            .cursor_default()
 9263                                            .hoverable_tooltip(move |_window, cx| {
 9264                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9265                                                    .into()
 9266                                            })
 9267                                    })
 9268                                    .when_some(
 9269                                        accept_keystroke.as_ref(),
 9270                                        |el, accept_keystroke| {
 9271                                            el.child(h_flex().children(ui::render_modifiers(
 9272                                                accept_keystroke.modifiers(),
 9273                                                PlatformStyle::platform(),
 9274                                                Some(Color::Default),
 9275                                                Some(IconSize::XSmall.rems().into()),
 9276                                                false,
 9277                                            )))
 9278                                        },
 9279                                    ),
 9280                            )
 9281                            .into_any(),
 9282                    );
 9283                }
 9284
 9285                self.render_edit_prediction_cursor_popover_preview(
 9286                    prediction,
 9287                    cursor_point,
 9288                    style,
 9289                    cx,
 9290                )?
 9291            }
 9292
 9293            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9294                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9295                    stale_completion,
 9296                    cursor_point,
 9297                    style,
 9298                    cx,
 9299                )?,
 9300
 9301                None => pending_completion_container(provider_icon)
 9302                    .child(Label::new("...").size(LabelSize::Small)),
 9303            },
 9304
 9305            None => pending_completion_container(provider_icon)
 9306                .child(Label::new("...").size(LabelSize::Small)),
 9307        };
 9308
 9309        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9310            completion
 9311                .with_animation(
 9312                    "loading-completion",
 9313                    Animation::new(Duration::from_secs(2))
 9314                        .repeat()
 9315                        .with_easing(pulsating_between(0.4, 0.8)),
 9316                    |label, delta| label.opacity(delta),
 9317                )
 9318                .into_any_element()
 9319        } else {
 9320            completion.into_any_element()
 9321        };
 9322
 9323        let has_completion = self.active_edit_prediction.is_some();
 9324
 9325        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9326        Some(
 9327            h_flex()
 9328                .min_w(min_width)
 9329                .max_w(max_width)
 9330                .flex_1()
 9331                .elevation_2(cx)
 9332                .border_color(cx.theme().colors().border)
 9333                .child(
 9334                    div()
 9335                        .flex_1()
 9336                        .py_1()
 9337                        .px_2()
 9338                        .overflow_hidden()
 9339                        .child(completion),
 9340                )
 9341                .when_some(accept_keystroke, |el, accept_keystroke| {
 9342                    if !accept_keystroke.modifiers().modified() {
 9343                        return el;
 9344                    }
 9345
 9346                    el.child(
 9347                        h_flex()
 9348                            .h_full()
 9349                            .border_l_1()
 9350                            .rounded_r_lg()
 9351                            .border_color(cx.theme().colors().border)
 9352                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9353                            .gap_1()
 9354                            .py_1()
 9355                            .px_2()
 9356                            .child(
 9357                                h_flex()
 9358                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9359                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9360                                    .child(h_flex().children(ui::render_modifiers(
 9361                                        accept_keystroke.modifiers(),
 9362                                        PlatformStyle::platform(),
 9363                                        Some(if !has_completion {
 9364                                            Color::Muted
 9365                                        } else {
 9366                                            Color::Default
 9367                                        }),
 9368                                        None,
 9369                                        false,
 9370                                    ))),
 9371                            )
 9372                            .child(Label::new("Preview").into_any_element())
 9373                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9374                    )
 9375                })
 9376                .into_any(),
 9377        )
 9378    }
 9379
 9380    fn render_edit_prediction_cursor_popover_preview(
 9381        &self,
 9382        completion: &EditPredictionState,
 9383        cursor_point: Point,
 9384        style: &EditorStyle,
 9385        cx: &mut Context<Editor>,
 9386    ) -> Option<Div> {
 9387        use text::ToPoint as _;
 9388
 9389        fn render_relative_row_jump(
 9390            prefix: impl Into<String>,
 9391            current_row: u32,
 9392            target_row: u32,
 9393        ) -> Div {
 9394            let (row_diff, arrow) = if target_row < current_row {
 9395                (current_row - target_row, IconName::ArrowUp)
 9396            } else {
 9397                (target_row - current_row, IconName::ArrowDown)
 9398            };
 9399
 9400            h_flex()
 9401                .child(
 9402                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9403                        .color(Color::Muted)
 9404                        .size(LabelSize::Small),
 9405                )
 9406                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9407        }
 9408
 9409        let supports_jump = self
 9410            .edit_prediction_provider
 9411            .as_ref()
 9412            .map(|provider| provider.provider.supports_jump_to_edit())
 9413            .unwrap_or(true);
 9414
 9415        match &completion.completion {
 9416            EditPrediction::Move {
 9417                target, snapshot, ..
 9418            } => {
 9419                if !supports_jump {
 9420                    return None;
 9421                }
 9422
 9423                Some(
 9424                    h_flex()
 9425                        .px_2()
 9426                        .gap_2()
 9427                        .flex_1()
 9428                        .child(
 9429                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9430                                Icon::new(IconName::ZedPredictDown)
 9431                            } else {
 9432                                Icon::new(IconName::ZedPredictUp)
 9433                            },
 9434                        )
 9435                        .child(Label::new("Jump to Edit")),
 9436                )
 9437            }
 9438
 9439            EditPrediction::Edit {
 9440                edits,
 9441                edit_preview,
 9442                snapshot,
 9443                display_mode: _,
 9444            } => {
 9445                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9446
 9447                let (highlighted_edits, has_more_lines) =
 9448                    if let Some(edit_preview) = edit_preview.as_ref() {
 9449                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9450                            .first_line_preview()
 9451                    } else {
 9452                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9453                    };
 9454
 9455                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9456                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9457
 9458                let preview = h_flex()
 9459                    .gap_1()
 9460                    .min_w_16()
 9461                    .child(styled_text)
 9462                    .when(has_more_lines, |parent| parent.child(""));
 9463
 9464                let left = if supports_jump && first_edit_row != cursor_point.row {
 9465                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9466                        .into_any_element()
 9467                } else {
 9468                    let icon_name =
 9469                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9470                    Icon::new(icon_name).into_any_element()
 9471                };
 9472
 9473                Some(
 9474                    h_flex()
 9475                        .h_full()
 9476                        .flex_1()
 9477                        .gap_2()
 9478                        .pr_1()
 9479                        .overflow_x_hidden()
 9480                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9481                        .child(left)
 9482                        .child(preview),
 9483                )
 9484            }
 9485        }
 9486    }
 9487
 9488    pub fn render_context_menu(
 9489        &self,
 9490        style: &EditorStyle,
 9491        max_height_in_lines: u32,
 9492        window: &mut Window,
 9493        cx: &mut Context<Editor>,
 9494    ) -> Option<AnyElement> {
 9495        let menu = self.context_menu.borrow();
 9496        let menu = menu.as_ref()?;
 9497        if !menu.visible() {
 9498            return None;
 9499        };
 9500        Some(menu.render(style, max_height_in_lines, window, cx))
 9501    }
 9502
 9503    fn render_context_menu_aside(
 9504        &mut self,
 9505        max_size: Size<Pixels>,
 9506        window: &mut Window,
 9507        cx: &mut Context<Editor>,
 9508    ) -> Option<AnyElement> {
 9509        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9510            if menu.visible() {
 9511                menu.render_aside(max_size, window, cx)
 9512            } else {
 9513                None
 9514            }
 9515        })
 9516    }
 9517
 9518    fn hide_context_menu(
 9519        &mut self,
 9520        window: &mut Window,
 9521        cx: &mut Context<Self>,
 9522    ) -> Option<CodeContextMenu> {
 9523        cx.notify();
 9524        self.completion_tasks.clear();
 9525        let context_menu = self.context_menu.borrow_mut().take();
 9526        self.stale_edit_prediction_in_menu.take();
 9527        self.update_visible_edit_prediction(window, cx);
 9528        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9529            && let Some(completion_provider) = &self.completion_provider
 9530        {
 9531            completion_provider.selection_changed(None, window, cx);
 9532        }
 9533        context_menu
 9534    }
 9535
 9536    fn show_snippet_choices(
 9537        &mut self,
 9538        choices: &Vec<String>,
 9539        selection: Range<Anchor>,
 9540        cx: &mut Context<Self>,
 9541    ) {
 9542        let Some((_, buffer, _)) = self
 9543            .buffer()
 9544            .read(cx)
 9545            .excerpt_containing(selection.start, cx)
 9546        else {
 9547            return;
 9548        };
 9549        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9550        else {
 9551            return;
 9552        };
 9553        if buffer != end_buffer {
 9554            log::error!("expected anchor range to have matching buffer IDs");
 9555            return;
 9556        }
 9557
 9558        let id = post_inc(&mut self.next_completion_id);
 9559        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9560        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9561            CompletionsMenu::new_snippet_choices(
 9562                id,
 9563                true,
 9564                choices,
 9565                selection,
 9566                buffer,
 9567                snippet_sort_order,
 9568            ),
 9569        ));
 9570    }
 9571
 9572    pub fn insert_snippet(
 9573        &mut self,
 9574        insertion_ranges: &[Range<usize>],
 9575        snippet: Snippet,
 9576        window: &mut Window,
 9577        cx: &mut Context<Self>,
 9578    ) -> Result<()> {
 9579        struct Tabstop<T> {
 9580            is_end_tabstop: bool,
 9581            ranges: Vec<Range<T>>,
 9582            choices: Option<Vec<String>>,
 9583        }
 9584
 9585        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9586            let snippet_text: Arc<str> = snippet.text.clone().into();
 9587            let edits = insertion_ranges
 9588                .iter()
 9589                .cloned()
 9590                .map(|range| (range, snippet_text.clone()));
 9591            let autoindent_mode = AutoindentMode::Block {
 9592                original_indent_columns: Vec::new(),
 9593            };
 9594            buffer.edit(edits, Some(autoindent_mode), cx);
 9595
 9596            let snapshot = &*buffer.read(cx);
 9597            let snippet = &snippet;
 9598            snippet
 9599                .tabstops
 9600                .iter()
 9601                .map(|tabstop| {
 9602                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9603                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9604                    });
 9605                    let mut tabstop_ranges = tabstop
 9606                        .ranges
 9607                        .iter()
 9608                        .flat_map(|tabstop_range| {
 9609                            let mut delta = 0_isize;
 9610                            insertion_ranges.iter().map(move |insertion_range| {
 9611                                let insertion_start = insertion_range.start as isize + delta;
 9612                                delta +=
 9613                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9614
 9615                                let start = ((insertion_start + tabstop_range.start) as usize)
 9616                                    .min(snapshot.len());
 9617                                let end = ((insertion_start + tabstop_range.end) as usize)
 9618                                    .min(snapshot.len());
 9619                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9620                            })
 9621                        })
 9622                        .collect::<Vec<_>>();
 9623                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9624
 9625                    Tabstop {
 9626                        is_end_tabstop,
 9627                        ranges: tabstop_ranges,
 9628                        choices: tabstop.choices.clone(),
 9629                    }
 9630                })
 9631                .collect::<Vec<_>>()
 9632        });
 9633        if let Some(tabstop) = tabstops.first() {
 9634            self.change_selections(Default::default(), window, cx, |s| {
 9635                // Reverse order so that the first range is the newest created selection.
 9636                // Completions will use it and autoscroll will prioritize it.
 9637                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9638            });
 9639
 9640            if let Some(choices) = &tabstop.choices
 9641                && let Some(selection) = tabstop.ranges.first()
 9642            {
 9643                self.show_snippet_choices(choices, selection.clone(), cx)
 9644            }
 9645
 9646            // If we're already at the last tabstop and it's at the end of the snippet,
 9647            // we're done, we don't need to keep the state around.
 9648            if !tabstop.is_end_tabstop {
 9649                let choices = tabstops
 9650                    .iter()
 9651                    .map(|tabstop| tabstop.choices.clone())
 9652                    .collect();
 9653
 9654                let ranges = tabstops
 9655                    .into_iter()
 9656                    .map(|tabstop| tabstop.ranges)
 9657                    .collect::<Vec<_>>();
 9658
 9659                self.snippet_stack.push(SnippetState {
 9660                    active_index: 0,
 9661                    ranges,
 9662                    choices,
 9663                });
 9664            }
 9665
 9666            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9667            if self.autoclose_regions.is_empty() {
 9668                let snapshot = self.buffer.read(cx).snapshot(cx);
 9669                let mut all_selections = self.selections.all::<Point>(cx);
 9670                for selection in &mut all_selections {
 9671                    let selection_head = selection.head();
 9672                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9673                        continue;
 9674                    };
 9675
 9676                    let mut bracket_pair = None;
 9677                    let max_lookup_length = scope
 9678                        .brackets()
 9679                        .map(|(pair, _)| {
 9680                            pair.start
 9681                                .as_str()
 9682                                .chars()
 9683                                .count()
 9684                                .max(pair.end.as_str().chars().count())
 9685                        })
 9686                        .max();
 9687                    if let Some(max_lookup_length) = max_lookup_length {
 9688                        let next_text = snapshot
 9689                            .chars_at(selection_head)
 9690                            .take(max_lookup_length)
 9691                            .collect::<String>();
 9692                        let prev_text = snapshot
 9693                            .reversed_chars_at(selection_head)
 9694                            .take(max_lookup_length)
 9695                            .collect::<String>();
 9696
 9697                        for (pair, enabled) in scope.brackets() {
 9698                            if enabled
 9699                                && pair.close
 9700                                && prev_text.starts_with(pair.start.as_str())
 9701                                && next_text.starts_with(pair.end.as_str())
 9702                            {
 9703                                bracket_pair = Some(pair.clone());
 9704                                break;
 9705                            }
 9706                        }
 9707                    }
 9708
 9709                    if let Some(pair) = bracket_pair {
 9710                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9711                        let autoclose_enabled =
 9712                            self.use_autoclose && snapshot_settings.use_autoclose;
 9713                        if autoclose_enabled {
 9714                            let start = snapshot.anchor_after(selection_head);
 9715                            let end = snapshot.anchor_after(selection_head);
 9716                            self.autoclose_regions.push(AutocloseRegion {
 9717                                selection_id: selection.id,
 9718                                range: start..end,
 9719                                pair,
 9720                            });
 9721                        }
 9722                    }
 9723                }
 9724            }
 9725        }
 9726        Ok(())
 9727    }
 9728
 9729    pub fn move_to_next_snippet_tabstop(
 9730        &mut self,
 9731        window: &mut Window,
 9732        cx: &mut Context<Self>,
 9733    ) -> bool {
 9734        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9735    }
 9736
 9737    pub fn move_to_prev_snippet_tabstop(
 9738        &mut self,
 9739        window: &mut Window,
 9740        cx: &mut Context<Self>,
 9741    ) -> bool {
 9742        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9743    }
 9744
 9745    pub fn move_to_snippet_tabstop(
 9746        &mut self,
 9747        bias: Bias,
 9748        window: &mut Window,
 9749        cx: &mut Context<Self>,
 9750    ) -> bool {
 9751        if let Some(mut snippet) = self.snippet_stack.pop() {
 9752            match bias {
 9753                Bias::Left => {
 9754                    if snippet.active_index > 0 {
 9755                        snippet.active_index -= 1;
 9756                    } else {
 9757                        self.snippet_stack.push(snippet);
 9758                        return false;
 9759                    }
 9760                }
 9761                Bias::Right => {
 9762                    if snippet.active_index + 1 < snippet.ranges.len() {
 9763                        snippet.active_index += 1;
 9764                    } else {
 9765                        self.snippet_stack.push(snippet);
 9766                        return false;
 9767                    }
 9768                }
 9769            }
 9770            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9771                self.change_selections(Default::default(), window, cx, |s| {
 9772                    // Reverse order so that the first range is the newest created selection.
 9773                    // Completions will use it and autoscroll will prioritize it.
 9774                    s.select_ranges(current_ranges.iter().rev().cloned())
 9775                });
 9776
 9777                if let Some(choices) = &snippet.choices[snippet.active_index]
 9778                    && let Some(selection) = current_ranges.first()
 9779                {
 9780                    self.show_snippet_choices(choices, selection.clone(), cx);
 9781                }
 9782
 9783                // If snippet state is not at the last tabstop, push it back on the stack
 9784                if snippet.active_index + 1 < snippet.ranges.len() {
 9785                    self.snippet_stack.push(snippet);
 9786                }
 9787                return true;
 9788            }
 9789        }
 9790
 9791        false
 9792    }
 9793
 9794    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9795        self.transact(window, cx, |this, window, cx| {
 9796            this.select_all(&SelectAll, window, cx);
 9797            this.insert("", window, cx);
 9798        });
 9799    }
 9800
 9801    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9802        if self.read_only(cx) {
 9803            return;
 9804        }
 9805        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9806        self.transact(window, cx, |this, window, cx| {
 9807            this.select_autoclose_pair(window, cx);
 9808            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9809            if !this.linked_edit_ranges.is_empty() {
 9810                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9811                let snapshot = this.buffer.read(cx).snapshot(cx);
 9812
 9813                for selection in selections.iter() {
 9814                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9815                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9816                    if selection_start.buffer_id != selection_end.buffer_id {
 9817                        continue;
 9818                    }
 9819                    if let Some(ranges) =
 9820                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9821                    {
 9822                        for (buffer, entries) in ranges {
 9823                            linked_ranges.entry(buffer).or_default().extend(entries);
 9824                        }
 9825                    }
 9826                }
 9827            }
 9828
 9829            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9830            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9831            for selection in &mut selections {
 9832                if selection.is_empty() {
 9833                    let old_head = selection.head();
 9834                    let mut new_head =
 9835                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9836                            .to_point(&display_map);
 9837                    if let Some((buffer, line_buffer_range)) = display_map
 9838                        .buffer_snapshot
 9839                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9840                    {
 9841                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9842                        let indent_len = match indent_size.kind {
 9843                            IndentKind::Space => {
 9844                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9845                            }
 9846                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9847                        };
 9848                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9849                            let indent_len = indent_len.get();
 9850                            new_head = cmp::min(
 9851                                new_head,
 9852                                MultiBufferPoint::new(
 9853                                    old_head.row,
 9854                                    ((old_head.column - 1) / indent_len) * indent_len,
 9855                                ),
 9856                            );
 9857                        }
 9858                    }
 9859
 9860                    selection.set_head(new_head, SelectionGoal::None);
 9861                }
 9862            }
 9863
 9864            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9865            this.insert("", window, cx);
 9866            let empty_str: Arc<str> = Arc::from("");
 9867            for (buffer, edits) in linked_ranges {
 9868                let snapshot = buffer.read(cx).snapshot();
 9869                use text::ToPoint as TP;
 9870
 9871                let edits = edits
 9872                    .into_iter()
 9873                    .map(|range| {
 9874                        let end_point = TP::to_point(&range.end, &snapshot);
 9875                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9876
 9877                        if end_point == start_point {
 9878                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9879                                .saturating_sub(1);
 9880                            start_point =
 9881                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9882                        };
 9883
 9884                        (start_point..end_point, empty_str.clone())
 9885                    })
 9886                    .sorted_by_key(|(range, _)| range.start)
 9887                    .collect::<Vec<_>>();
 9888                buffer.update(cx, |this, cx| {
 9889                    this.edit(edits, None, cx);
 9890                })
 9891            }
 9892            this.refresh_edit_prediction(true, false, window, cx);
 9893            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9894        });
 9895    }
 9896
 9897    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9898        if self.read_only(cx) {
 9899            return;
 9900        }
 9901        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9902        self.transact(window, cx, |this, window, cx| {
 9903            this.change_selections(Default::default(), window, cx, |s| {
 9904                s.move_with(|map, selection| {
 9905                    if selection.is_empty() {
 9906                        let cursor = movement::right(map, selection.head());
 9907                        selection.end = cursor;
 9908                        selection.reversed = true;
 9909                        selection.goal = SelectionGoal::None;
 9910                    }
 9911                })
 9912            });
 9913            this.insert("", window, cx);
 9914            this.refresh_edit_prediction(true, false, window, cx);
 9915        });
 9916    }
 9917
 9918    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9919        if self.mode.is_single_line() {
 9920            cx.propagate();
 9921            return;
 9922        }
 9923
 9924        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9925        if self.move_to_prev_snippet_tabstop(window, cx) {
 9926            return;
 9927        }
 9928        self.outdent(&Outdent, window, cx);
 9929    }
 9930
 9931    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9932        if self.mode.is_single_line() {
 9933            cx.propagate();
 9934            return;
 9935        }
 9936
 9937        if self.move_to_next_snippet_tabstop(window, cx) {
 9938            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9939            return;
 9940        }
 9941        if self.read_only(cx) {
 9942            return;
 9943        }
 9944        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9945        let mut selections = self.selections.all_adjusted(cx);
 9946        let buffer = self.buffer.read(cx);
 9947        let snapshot = buffer.snapshot(cx);
 9948        let rows_iter = selections.iter().map(|s| s.head().row);
 9949        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9950
 9951        let has_some_cursor_in_whitespace = selections
 9952            .iter()
 9953            .filter(|selection| selection.is_empty())
 9954            .any(|selection| {
 9955                let cursor = selection.head();
 9956                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9957                cursor.column < current_indent.len
 9958            });
 9959
 9960        let mut edits = Vec::new();
 9961        let mut prev_edited_row = 0;
 9962        let mut row_delta = 0;
 9963        for selection in &mut selections {
 9964            if selection.start.row != prev_edited_row {
 9965                row_delta = 0;
 9966            }
 9967            prev_edited_row = selection.end.row;
 9968
 9969            // If the selection is non-empty, then increase the indentation of the selected lines.
 9970            if !selection.is_empty() {
 9971                row_delta =
 9972                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9973                continue;
 9974            }
 9975
 9976            let cursor = selection.head();
 9977            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9978            if let Some(suggested_indent) =
 9979                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9980            {
 9981                // Don't do anything if already at suggested indent
 9982                // and there is any other cursor which is not
 9983                if has_some_cursor_in_whitespace
 9984                    && cursor.column == current_indent.len
 9985                    && current_indent.len == suggested_indent.len
 9986                {
 9987                    continue;
 9988                }
 9989
 9990                // Adjust line and move cursor to suggested indent
 9991                // if cursor is not at suggested indent
 9992                if cursor.column < suggested_indent.len
 9993                    && cursor.column <= current_indent.len
 9994                    && current_indent.len <= suggested_indent.len
 9995                {
 9996                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9997                    selection.end = selection.start;
 9998                    if row_delta == 0 {
 9999                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10000                            cursor.row,
10001                            current_indent,
10002                            suggested_indent,
10003                        ));
10004                        row_delta = suggested_indent.len - current_indent.len;
10005                    }
10006                    continue;
10007                }
10008
10009                // If current indent is more than suggested indent
10010                // only move cursor to current indent and skip indent
10011                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10012                    selection.start = Point::new(cursor.row, current_indent.len);
10013                    selection.end = selection.start;
10014                    continue;
10015                }
10016            }
10017
10018            // Otherwise, insert a hard or soft tab.
10019            let settings = buffer.language_settings_at(cursor, cx);
10020            let tab_size = if settings.hard_tabs {
10021                IndentSize::tab()
10022            } else {
10023                let tab_size = settings.tab_size.get();
10024                let indent_remainder = snapshot
10025                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10026                    .flat_map(str::chars)
10027                    .fold(row_delta % tab_size, |counter: u32, c| {
10028                        if c == '\t' {
10029                            0
10030                        } else {
10031                            (counter + 1) % tab_size
10032                        }
10033                    });
10034
10035                let chars_to_next_tab_stop = tab_size - indent_remainder;
10036                IndentSize::spaces(chars_to_next_tab_stop)
10037            };
10038            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10039            selection.end = selection.start;
10040            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10041            row_delta += tab_size.len;
10042        }
10043
10044        self.transact(window, cx, |this, window, cx| {
10045            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10046            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10047            this.refresh_edit_prediction(true, false, window, cx);
10048        });
10049    }
10050
10051    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10052        if self.read_only(cx) {
10053            return;
10054        }
10055        if self.mode.is_single_line() {
10056            cx.propagate();
10057            return;
10058        }
10059
10060        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10061        let mut selections = self.selections.all::<Point>(cx);
10062        let mut prev_edited_row = 0;
10063        let mut row_delta = 0;
10064        let mut edits = Vec::new();
10065        let buffer = self.buffer.read(cx);
10066        let snapshot = buffer.snapshot(cx);
10067        for selection in &mut selections {
10068            if selection.start.row != prev_edited_row {
10069                row_delta = 0;
10070            }
10071            prev_edited_row = selection.end.row;
10072
10073            row_delta =
10074                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10075        }
10076
10077        self.transact(window, cx, |this, window, cx| {
10078            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10079            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10080        });
10081    }
10082
10083    fn indent_selection(
10084        buffer: &MultiBuffer,
10085        snapshot: &MultiBufferSnapshot,
10086        selection: &mut Selection<Point>,
10087        edits: &mut Vec<(Range<Point>, String)>,
10088        delta_for_start_row: u32,
10089        cx: &App,
10090    ) -> u32 {
10091        let settings = buffer.language_settings_at(selection.start, cx);
10092        let tab_size = settings.tab_size.get();
10093        let indent_kind = if settings.hard_tabs {
10094            IndentKind::Tab
10095        } else {
10096            IndentKind::Space
10097        };
10098        let mut start_row = selection.start.row;
10099        let mut end_row = selection.end.row + 1;
10100
10101        // If a selection ends at the beginning of a line, don't indent
10102        // that last line.
10103        if selection.end.column == 0 && selection.end.row > selection.start.row {
10104            end_row -= 1;
10105        }
10106
10107        // Avoid re-indenting a row that has already been indented by a
10108        // previous selection, but still update this selection's column
10109        // to reflect that indentation.
10110        if delta_for_start_row > 0 {
10111            start_row += 1;
10112            selection.start.column += delta_for_start_row;
10113            if selection.end.row == selection.start.row {
10114                selection.end.column += delta_for_start_row;
10115            }
10116        }
10117
10118        let mut delta_for_end_row = 0;
10119        let has_multiple_rows = start_row + 1 != end_row;
10120        for row in start_row..end_row {
10121            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10122            let indent_delta = match (current_indent.kind, indent_kind) {
10123                (IndentKind::Space, IndentKind::Space) => {
10124                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10125                    IndentSize::spaces(columns_to_next_tab_stop)
10126                }
10127                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10128                (_, IndentKind::Tab) => IndentSize::tab(),
10129            };
10130
10131            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10132                0
10133            } else {
10134                selection.start.column
10135            };
10136            let row_start = Point::new(row, start);
10137            edits.push((
10138                row_start..row_start,
10139                indent_delta.chars().collect::<String>(),
10140            ));
10141
10142            // Update this selection's endpoints to reflect the indentation.
10143            if row == selection.start.row {
10144                selection.start.column += indent_delta.len;
10145            }
10146            if row == selection.end.row {
10147                selection.end.column += indent_delta.len;
10148                delta_for_end_row = indent_delta.len;
10149            }
10150        }
10151
10152        if selection.start.row == selection.end.row {
10153            delta_for_start_row + delta_for_end_row
10154        } else {
10155            delta_for_end_row
10156        }
10157    }
10158
10159    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10160        if self.read_only(cx) {
10161            return;
10162        }
10163        if self.mode.is_single_line() {
10164            cx.propagate();
10165            return;
10166        }
10167
10168        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10169        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10170        let selections = self.selections.all::<Point>(cx);
10171        let mut deletion_ranges = Vec::new();
10172        let mut last_outdent = None;
10173        {
10174            let buffer = self.buffer.read(cx);
10175            let snapshot = buffer.snapshot(cx);
10176            for selection in &selections {
10177                let settings = buffer.language_settings_at(selection.start, cx);
10178                let tab_size = settings.tab_size.get();
10179                let mut rows = selection.spanned_rows(false, &display_map);
10180
10181                // Avoid re-outdenting a row that has already been outdented by a
10182                // previous selection.
10183                if let Some(last_row) = last_outdent
10184                    && last_row == rows.start
10185                {
10186                    rows.start = rows.start.next_row();
10187                }
10188                let has_multiple_rows = rows.len() > 1;
10189                for row in rows.iter_rows() {
10190                    let indent_size = snapshot.indent_size_for_line(row);
10191                    if indent_size.len > 0 {
10192                        let deletion_len = match indent_size.kind {
10193                            IndentKind::Space => {
10194                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10195                                if columns_to_prev_tab_stop == 0 {
10196                                    tab_size
10197                                } else {
10198                                    columns_to_prev_tab_stop
10199                                }
10200                            }
10201                            IndentKind::Tab => 1,
10202                        };
10203                        let start = if has_multiple_rows
10204                            || deletion_len > selection.start.column
10205                            || indent_size.len < selection.start.column
10206                        {
10207                            0
10208                        } else {
10209                            selection.start.column - deletion_len
10210                        };
10211                        deletion_ranges.push(
10212                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10213                        );
10214                        last_outdent = Some(row);
10215                    }
10216                }
10217            }
10218        }
10219
10220        self.transact(window, cx, |this, window, cx| {
10221            this.buffer.update(cx, |buffer, cx| {
10222                let empty_str: Arc<str> = Arc::default();
10223                buffer.edit(
10224                    deletion_ranges
10225                        .into_iter()
10226                        .map(|range| (range, empty_str.clone())),
10227                    None,
10228                    cx,
10229                );
10230            });
10231            let selections = this.selections.all::<usize>(cx);
10232            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10233        });
10234    }
10235
10236    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10237        if self.read_only(cx) {
10238            return;
10239        }
10240        if self.mode.is_single_line() {
10241            cx.propagate();
10242            return;
10243        }
10244
10245        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10246        let selections = self
10247            .selections
10248            .all::<usize>(cx)
10249            .into_iter()
10250            .map(|s| s.range());
10251
10252        self.transact(window, cx, |this, window, cx| {
10253            this.buffer.update(cx, |buffer, cx| {
10254                buffer.autoindent_ranges(selections, cx);
10255            });
10256            let selections = this.selections.all::<usize>(cx);
10257            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10258        });
10259    }
10260
10261    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10262        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10263        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10264        let selections = self.selections.all::<Point>(cx);
10265
10266        let mut new_cursors = Vec::new();
10267        let mut edit_ranges = Vec::new();
10268        let mut selections = selections.iter().peekable();
10269        while let Some(selection) = selections.next() {
10270            let mut rows = selection.spanned_rows(false, &display_map);
10271            let goal_display_column = selection.head().to_display_point(&display_map).column();
10272
10273            // Accumulate contiguous regions of rows that we want to delete.
10274            while let Some(next_selection) = selections.peek() {
10275                let next_rows = next_selection.spanned_rows(false, &display_map);
10276                if next_rows.start <= rows.end {
10277                    rows.end = next_rows.end;
10278                    selections.next().unwrap();
10279                } else {
10280                    break;
10281                }
10282            }
10283
10284            let buffer = &display_map.buffer_snapshot;
10285            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10286            let edit_end;
10287            let cursor_buffer_row;
10288            if buffer.max_point().row >= rows.end.0 {
10289                // If there's a line after the range, delete the \n from the end of the row range
10290                // and position the cursor on the next line.
10291                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10292                cursor_buffer_row = rows.end;
10293            } else {
10294                // If there isn't a line after the range, delete the \n from the line before the
10295                // start of the row range and position the cursor there.
10296                edit_start = edit_start.saturating_sub(1);
10297                edit_end = buffer.len();
10298                cursor_buffer_row = rows.start.previous_row();
10299            }
10300
10301            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10302            *cursor.column_mut() =
10303                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10304
10305            new_cursors.push((
10306                selection.id,
10307                buffer.anchor_after(cursor.to_point(&display_map)),
10308            ));
10309            edit_ranges.push(edit_start..edit_end);
10310        }
10311
10312        self.transact(window, cx, |this, window, cx| {
10313            let buffer = this.buffer.update(cx, |buffer, cx| {
10314                let empty_str: Arc<str> = Arc::default();
10315                buffer.edit(
10316                    edit_ranges
10317                        .into_iter()
10318                        .map(|range| (range, empty_str.clone())),
10319                    None,
10320                    cx,
10321                );
10322                buffer.snapshot(cx)
10323            });
10324            let new_selections = new_cursors
10325                .into_iter()
10326                .map(|(id, cursor)| {
10327                    let cursor = cursor.to_point(&buffer);
10328                    Selection {
10329                        id,
10330                        start: cursor,
10331                        end: cursor,
10332                        reversed: false,
10333                        goal: SelectionGoal::None,
10334                    }
10335                })
10336                .collect();
10337
10338            this.change_selections(Default::default(), window, cx, |s| {
10339                s.select(new_selections);
10340            });
10341        });
10342    }
10343
10344    pub fn join_lines_impl(
10345        &mut self,
10346        insert_whitespace: bool,
10347        window: &mut Window,
10348        cx: &mut Context<Self>,
10349    ) {
10350        if self.read_only(cx) {
10351            return;
10352        }
10353        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10354        for selection in self.selections.all::<Point>(cx) {
10355            let start = MultiBufferRow(selection.start.row);
10356            // Treat single line selections as if they include the next line. Otherwise this action
10357            // would do nothing for single line selections individual cursors.
10358            let end = if selection.start.row == selection.end.row {
10359                MultiBufferRow(selection.start.row + 1)
10360            } else {
10361                MultiBufferRow(selection.end.row)
10362            };
10363
10364            if let Some(last_row_range) = row_ranges.last_mut()
10365                && start <= last_row_range.end
10366            {
10367                last_row_range.end = end;
10368                continue;
10369            }
10370            row_ranges.push(start..end);
10371        }
10372
10373        let snapshot = self.buffer.read(cx).snapshot(cx);
10374        let mut cursor_positions = Vec::new();
10375        for row_range in &row_ranges {
10376            let anchor = snapshot.anchor_before(Point::new(
10377                row_range.end.previous_row().0,
10378                snapshot.line_len(row_range.end.previous_row()),
10379            ));
10380            cursor_positions.push(anchor..anchor);
10381        }
10382
10383        self.transact(window, cx, |this, window, cx| {
10384            for row_range in row_ranges.into_iter().rev() {
10385                for row in row_range.iter_rows().rev() {
10386                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10387                    let next_line_row = row.next_row();
10388                    let indent = snapshot.indent_size_for_line(next_line_row);
10389                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10390
10391                    let replace =
10392                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10393                            " "
10394                        } else {
10395                            ""
10396                        };
10397
10398                    this.buffer.update(cx, |buffer, cx| {
10399                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10400                    });
10401                }
10402            }
10403
10404            this.change_selections(Default::default(), window, cx, |s| {
10405                s.select_anchor_ranges(cursor_positions)
10406            });
10407        });
10408    }
10409
10410    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10411        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10412        self.join_lines_impl(true, window, cx);
10413    }
10414
10415    pub fn sort_lines_case_sensitive(
10416        &mut self,
10417        _: &SortLinesCaseSensitive,
10418        window: &mut Window,
10419        cx: &mut Context<Self>,
10420    ) {
10421        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10422    }
10423
10424    pub fn sort_lines_by_length(
10425        &mut self,
10426        _: &SortLinesByLength,
10427        window: &mut Window,
10428        cx: &mut Context<Self>,
10429    ) {
10430        self.manipulate_immutable_lines(window, cx, |lines| {
10431            lines.sort_by_key(|&line| line.chars().count())
10432        })
10433    }
10434
10435    pub fn sort_lines_case_insensitive(
10436        &mut self,
10437        _: &SortLinesCaseInsensitive,
10438        window: &mut Window,
10439        cx: &mut Context<Self>,
10440    ) {
10441        self.manipulate_immutable_lines(window, cx, |lines| {
10442            lines.sort_by_key(|line| line.to_lowercase())
10443        })
10444    }
10445
10446    pub fn unique_lines_case_insensitive(
10447        &mut self,
10448        _: &UniqueLinesCaseInsensitive,
10449        window: &mut Window,
10450        cx: &mut Context<Self>,
10451    ) {
10452        self.manipulate_immutable_lines(window, cx, |lines| {
10453            let mut seen = HashSet::default();
10454            lines.retain(|line| seen.insert(line.to_lowercase()));
10455        })
10456    }
10457
10458    pub fn unique_lines_case_sensitive(
10459        &mut self,
10460        _: &UniqueLinesCaseSensitive,
10461        window: &mut Window,
10462        cx: &mut Context<Self>,
10463    ) {
10464        self.manipulate_immutable_lines(window, cx, |lines| {
10465            let mut seen = HashSet::default();
10466            lines.retain(|line| seen.insert(*line));
10467        })
10468    }
10469
10470    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10471        let snapshot = self.buffer.read(cx).snapshot(cx);
10472        for selection in self.selections.disjoint_anchors().iter() {
10473            if snapshot
10474                .language_at(selection.start)
10475                .and_then(|lang| lang.config().wrap_characters.as_ref())
10476                .is_some()
10477            {
10478                return true;
10479            }
10480        }
10481        false
10482    }
10483
10484    fn wrap_selections_in_tag(
10485        &mut self,
10486        _: &WrapSelectionsInTag,
10487        window: &mut Window,
10488        cx: &mut Context<Self>,
10489    ) {
10490        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10491
10492        let snapshot = self.buffer.read(cx).snapshot(cx);
10493
10494        let mut edits = Vec::new();
10495        let mut boundaries = Vec::new();
10496
10497        for selection in self.selections.all::<Point>(cx).iter() {
10498            let Some(wrap_config) = snapshot
10499                .language_at(selection.start)
10500                .and_then(|lang| lang.config().wrap_characters.clone())
10501            else {
10502                continue;
10503            };
10504
10505            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10506            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10507
10508            let start_before = snapshot.anchor_before(selection.start);
10509            let end_after = snapshot.anchor_after(selection.end);
10510
10511            edits.push((start_before..start_before, open_tag));
10512            edits.push((end_after..end_after, close_tag));
10513
10514            boundaries.push((
10515                start_before,
10516                end_after,
10517                wrap_config.start_prefix.len(),
10518                wrap_config.end_suffix.len(),
10519            ));
10520        }
10521
10522        if edits.is_empty() {
10523            return;
10524        }
10525
10526        self.transact(window, cx, |this, window, cx| {
10527            let buffer = this.buffer.update(cx, |buffer, cx| {
10528                buffer.edit(edits, None, cx);
10529                buffer.snapshot(cx)
10530            });
10531
10532            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10533            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10534                boundaries.into_iter()
10535            {
10536                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10537                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10538                new_selections.push(open_offset..open_offset);
10539                new_selections.push(close_offset..close_offset);
10540            }
10541
10542            this.change_selections(Default::default(), window, cx, |s| {
10543                s.select_ranges(new_selections);
10544            });
10545
10546            this.request_autoscroll(Autoscroll::fit(), cx);
10547        });
10548    }
10549
10550    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10551        let Some(project) = self.project.clone() else {
10552            return;
10553        };
10554        self.reload(project, window, cx)
10555            .detach_and_notify_err(window, cx);
10556    }
10557
10558    pub fn restore_file(
10559        &mut self,
10560        _: &::git::RestoreFile,
10561        window: &mut Window,
10562        cx: &mut Context<Self>,
10563    ) {
10564        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10565        let mut buffer_ids = HashSet::default();
10566        let snapshot = self.buffer().read(cx).snapshot(cx);
10567        for selection in self.selections.all::<usize>(cx) {
10568            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10569        }
10570
10571        let buffer = self.buffer().read(cx);
10572        let ranges = buffer_ids
10573            .into_iter()
10574            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10575            .collect::<Vec<_>>();
10576
10577        self.restore_hunks_in_ranges(ranges, window, cx);
10578    }
10579
10580    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10581        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10582        let selections = self
10583            .selections
10584            .all(cx)
10585            .into_iter()
10586            .map(|s| s.range())
10587            .collect();
10588        self.restore_hunks_in_ranges(selections, window, cx);
10589    }
10590
10591    pub fn restore_hunks_in_ranges(
10592        &mut self,
10593        ranges: Vec<Range<Point>>,
10594        window: &mut Window,
10595        cx: &mut Context<Editor>,
10596    ) {
10597        let mut revert_changes = HashMap::default();
10598        let chunk_by = self
10599            .snapshot(window, cx)
10600            .hunks_for_ranges(ranges)
10601            .into_iter()
10602            .chunk_by(|hunk| hunk.buffer_id);
10603        for (buffer_id, hunks) in &chunk_by {
10604            let hunks = hunks.collect::<Vec<_>>();
10605            for hunk in &hunks {
10606                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10607            }
10608            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10609        }
10610        drop(chunk_by);
10611        if !revert_changes.is_empty() {
10612            self.transact(window, cx, |editor, window, cx| {
10613                editor.restore(revert_changes, window, cx);
10614            });
10615        }
10616    }
10617
10618    pub fn open_active_item_in_terminal(
10619        &mut self,
10620        _: &OpenInTerminal,
10621        window: &mut Window,
10622        cx: &mut Context<Self>,
10623    ) {
10624        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10625            let project_path = buffer.read(cx).project_path(cx)?;
10626            let project = self.project()?.read(cx);
10627            let entry = project.entry_for_path(&project_path, cx)?;
10628            let parent = match &entry.canonical_path {
10629                Some(canonical_path) => canonical_path.to_path_buf(),
10630                None => project.absolute_path(&project_path, cx)?,
10631            }
10632            .parent()?
10633            .to_path_buf();
10634            Some(parent)
10635        }) {
10636            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10637        }
10638    }
10639
10640    fn set_breakpoint_context_menu(
10641        &mut self,
10642        display_row: DisplayRow,
10643        position: Option<Anchor>,
10644        clicked_point: gpui::Point<Pixels>,
10645        window: &mut Window,
10646        cx: &mut Context<Self>,
10647    ) {
10648        let source = self
10649            .buffer
10650            .read(cx)
10651            .snapshot(cx)
10652            .anchor_before(Point::new(display_row.0, 0u32));
10653
10654        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10655
10656        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10657            self,
10658            source,
10659            clicked_point,
10660            context_menu,
10661            window,
10662            cx,
10663        );
10664    }
10665
10666    fn add_edit_breakpoint_block(
10667        &mut self,
10668        anchor: Anchor,
10669        breakpoint: &Breakpoint,
10670        edit_action: BreakpointPromptEditAction,
10671        window: &mut Window,
10672        cx: &mut Context<Self>,
10673    ) {
10674        let weak_editor = cx.weak_entity();
10675        let bp_prompt = cx.new(|cx| {
10676            BreakpointPromptEditor::new(
10677                weak_editor,
10678                anchor,
10679                breakpoint.clone(),
10680                edit_action,
10681                window,
10682                cx,
10683            )
10684        });
10685
10686        let height = bp_prompt.update(cx, |this, cx| {
10687            this.prompt
10688                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10689        });
10690        let cloned_prompt = bp_prompt.clone();
10691        let blocks = vec![BlockProperties {
10692            style: BlockStyle::Sticky,
10693            placement: BlockPlacement::Above(anchor),
10694            height: Some(height),
10695            render: Arc::new(move |cx| {
10696                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10697                cloned_prompt.clone().into_any_element()
10698            }),
10699            priority: 0,
10700        }];
10701
10702        let focus_handle = bp_prompt.focus_handle(cx);
10703        window.focus(&focus_handle);
10704
10705        let block_ids = self.insert_blocks(blocks, None, cx);
10706        bp_prompt.update(cx, |prompt, _| {
10707            prompt.add_block_ids(block_ids);
10708        });
10709    }
10710
10711    pub(crate) fn breakpoint_at_row(
10712        &self,
10713        row: u32,
10714        window: &mut Window,
10715        cx: &mut Context<Self>,
10716    ) -> Option<(Anchor, Breakpoint)> {
10717        let snapshot = self.snapshot(window, cx);
10718        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10719
10720        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10721    }
10722
10723    pub(crate) fn breakpoint_at_anchor(
10724        &self,
10725        breakpoint_position: Anchor,
10726        snapshot: &EditorSnapshot,
10727        cx: &mut Context<Self>,
10728    ) -> Option<(Anchor, Breakpoint)> {
10729        let buffer = self
10730            .buffer
10731            .read(cx)
10732            .buffer_for_anchor(breakpoint_position, cx)?;
10733
10734        let enclosing_excerpt = breakpoint_position.excerpt_id;
10735        let buffer_snapshot = buffer.read(cx).snapshot();
10736
10737        let row = buffer_snapshot
10738            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10739            .row;
10740
10741        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10742        let anchor_end = snapshot
10743            .buffer_snapshot
10744            .anchor_after(Point::new(row, line_len));
10745
10746        self.breakpoint_store
10747            .as_ref()?
10748            .read_with(cx, |breakpoint_store, cx| {
10749                breakpoint_store
10750                    .breakpoints(
10751                        &buffer,
10752                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10753                        &buffer_snapshot,
10754                        cx,
10755                    )
10756                    .next()
10757                    .and_then(|(bp, _)| {
10758                        let breakpoint_row = buffer_snapshot
10759                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10760                            .row;
10761
10762                        if breakpoint_row == row {
10763                            snapshot
10764                                .buffer_snapshot
10765                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10766                                .map(|position| (position, bp.bp.clone()))
10767                        } else {
10768                            None
10769                        }
10770                    })
10771            })
10772    }
10773
10774    pub fn edit_log_breakpoint(
10775        &mut self,
10776        _: &EditLogBreakpoint,
10777        window: &mut Window,
10778        cx: &mut Context<Self>,
10779    ) {
10780        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10781            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10782                message: None,
10783                state: BreakpointState::Enabled,
10784                condition: None,
10785                hit_condition: None,
10786            });
10787
10788            self.add_edit_breakpoint_block(
10789                anchor,
10790                &breakpoint,
10791                BreakpointPromptEditAction::Log,
10792                window,
10793                cx,
10794            );
10795        }
10796    }
10797
10798    fn breakpoints_at_cursors(
10799        &self,
10800        window: &mut Window,
10801        cx: &mut Context<Self>,
10802    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10803        let snapshot = self.snapshot(window, cx);
10804        let cursors = self
10805            .selections
10806            .disjoint_anchors()
10807            .iter()
10808            .map(|selection| {
10809                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10810
10811                let breakpoint_position = self
10812                    .breakpoint_at_row(cursor_position.row, window, cx)
10813                    .map(|bp| bp.0)
10814                    .unwrap_or_else(|| {
10815                        snapshot
10816                            .display_snapshot
10817                            .buffer_snapshot
10818                            .anchor_after(Point::new(cursor_position.row, 0))
10819                    });
10820
10821                let breakpoint = self
10822                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10823                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10824
10825                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10826            })
10827            // 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.
10828            .collect::<HashMap<Anchor, _>>();
10829
10830        cursors.into_iter().collect()
10831    }
10832
10833    pub fn enable_breakpoint(
10834        &mut self,
10835        _: &crate::actions::EnableBreakpoint,
10836        window: &mut Window,
10837        cx: &mut Context<Self>,
10838    ) {
10839        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10840            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10841                continue;
10842            };
10843            self.edit_breakpoint_at_anchor(
10844                anchor,
10845                breakpoint,
10846                BreakpointEditAction::InvertState,
10847                cx,
10848            );
10849        }
10850    }
10851
10852    pub fn disable_breakpoint(
10853        &mut self,
10854        _: &crate::actions::DisableBreakpoint,
10855        window: &mut Window,
10856        cx: &mut Context<Self>,
10857    ) {
10858        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10859            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10860                continue;
10861            };
10862            self.edit_breakpoint_at_anchor(
10863                anchor,
10864                breakpoint,
10865                BreakpointEditAction::InvertState,
10866                cx,
10867            );
10868        }
10869    }
10870
10871    pub fn toggle_breakpoint(
10872        &mut self,
10873        _: &crate::actions::ToggleBreakpoint,
10874        window: &mut Window,
10875        cx: &mut Context<Self>,
10876    ) {
10877        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10878            if let Some(breakpoint) = breakpoint {
10879                self.edit_breakpoint_at_anchor(
10880                    anchor,
10881                    breakpoint,
10882                    BreakpointEditAction::Toggle,
10883                    cx,
10884                );
10885            } else {
10886                self.edit_breakpoint_at_anchor(
10887                    anchor,
10888                    Breakpoint::new_standard(),
10889                    BreakpointEditAction::Toggle,
10890                    cx,
10891                );
10892            }
10893        }
10894    }
10895
10896    pub fn edit_breakpoint_at_anchor(
10897        &mut self,
10898        breakpoint_position: Anchor,
10899        breakpoint: Breakpoint,
10900        edit_action: BreakpointEditAction,
10901        cx: &mut Context<Self>,
10902    ) {
10903        let Some(breakpoint_store) = &self.breakpoint_store else {
10904            return;
10905        };
10906
10907        let Some(buffer) = self
10908            .buffer
10909            .read(cx)
10910            .buffer_for_anchor(breakpoint_position, cx)
10911        else {
10912            return;
10913        };
10914
10915        breakpoint_store.update(cx, |breakpoint_store, cx| {
10916            breakpoint_store.toggle_breakpoint(
10917                buffer,
10918                BreakpointWithPosition {
10919                    position: breakpoint_position.text_anchor,
10920                    bp: breakpoint,
10921                },
10922                edit_action,
10923                cx,
10924            );
10925        });
10926
10927        cx.notify();
10928    }
10929
10930    #[cfg(any(test, feature = "test-support"))]
10931    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10932        self.breakpoint_store.clone()
10933    }
10934
10935    pub fn prepare_restore_change(
10936        &self,
10937        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10938        hunk: &MultiBufferDiffHunk,
10939        cx: &mut App,
10940    ) -> Option<()> {
10941        if hunk.is_created_file() {
10942            return None;
10943        }
10944        let buffer = self.buffer.read(cx);
10945        let diff = buffer.diff_for(hunk.buffer_id)?;
10946        let buffer = buffer.buffer(hunk.buffer_id)?;
10947        let buffer = buffer.read(cx);
10948        let original_text = diff
10949            .read(cx)
10950            .base_text()
10951            .as_rope()
10952            .slice(hunk.diff_base_byte_range.clone());
10953        let buffer_snapshot = buffer.snapshot();
10954        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10955        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10956            probe
10957                .0
10958                .start
10959                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10960                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10961        }) {
10962            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10963            Some(())
10964        } else {
10965            None
10966        }
10967    }
10968
10969    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10970        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10971    }
10972
10973    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10974        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10975    }
10976
10977    fn manipulate_lines<M>(
10978        &mut self,
10979        window: &mut Window,
10980        cx: &mut Context<Self>,
10981        mut manipulate: M,
10982    ) where
10983        M: FnMut(&str) -> LineManipulationResult,
10984    {
10985        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10986
10987        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10988        let buffer = self.buffer.read(cx).snapshot(cx);
10989
10990        let mut edits = Vec::new();
10991
10992        let selections = self.selections.all::<Point>(cx);
10993        let mut selections = selections.iter().peekable();
10994        let mut contiguous_row_selections = Vec::new();
10995        let mut new_selections = Vec::new();
10996        let mut added_lines = 0;
10997        let mut removed_lines = 0;
10998
10999        while let Some(selection) = selections.next() {
11000            let (start_row, end_row) = consume_contiguous_rows(
11001                &mut contiguous_row_selections,
11002                selection,
11003                &display_map,
11004                &mut selections,
11005            );
11006
11007            let start_point = Point::new(start_row.0, 0);
11008            let end_point = Point::new(
11009                end_row.previous_row().0,
11010                buffer.line_len(end_row.previous_row()),
11011            );
11012            let text = buffer
11013                .text_for_range(start_point..end_point)
11014                .collect::<String>();
11015
11016            let LineManipulationResult {
11017                new_text,
11018                line_count_before,
11019                line_count_after,
11020            } = manipulate(&text);
11021
11022            edits.push((start_point..end_point, new_text));
11023
11024            // Selections must change based on added and removed line count
11025            let start_row =
11026                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11027            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11028            new_selections.push(Selection {
11029                id: selection.id,
11030                start: start_row,
11031                end: end_row,
11032                goal: SelectionGoal::None,
11033                reversed: selection.reversed,
11034            });
11035
11036            if line_count_after > line_count_before {
11037                added_lines += line_count_after - line_count_before;
11038            } else if line_count_before > line_count_after {
11039                removed_lines += line_count_before - line_count_after;
11040            }
11041        }
11042
11043        self.transact(window, cx, |this, window, cx| {
11044            let buffer = this.buffer.update(cx, |buffer, cx| {
11045                buffer.edit(edits, None, cx);
11046                buffer.snapshot(cx)
11047            });
11048
11049            // Recalculate offsets on newly edited buffer
11050            let new_selections = new_selections
11051                .iter()
11052                .map(|s| {
11053                    let start_point = Point::new(s.start.0, 0);
11054                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11055                    Selection {
11056                        id: s.id,
11057                        start: buffer.point_to_offset(start_point),
11058                        end: buffer.point_to_offset(end_point),
11059                        goal: s.goal,
11060                        reversed: s.reversed,
11061                    }
11062                })
11063                .collect();
11064
11065            this.change_selections(Default::default(), window, cx, |s| {
11066                s.select(new_selections);
11067            });
11068
11069            this.request_autoscroll(Autoscroll::fit(), cx);
11070        });
11071    }
11072
11073    fn manipulate_immutable_lines<Fn>(
11074        &mut self,
11075        window: &mut Window,
11076        cx: &mut Context<Self>,
11077        mut callback: Fn,
11078    ) where
11079        Fn: FnMut(&mut Vec<&str>),
11080    {
11081        self.manipulate_lines(window, cx, |text| {
11082            let mut lines: Vec<&str> = text.split('\n').collect();
11083            let line_count_before = lines.len();
11084
11085            callback(&mut lines);
11086
11087            LineManipulationResult {
11088                new_text: lines.join("\n"),
11089                line_count_before,
11090                line_count_after: lines.len(),
11091            }
11092        });
11093    }
11094
11095    fn manipulate_mutable_lines<Fn>(
11096        &mut self,
11097        window: &mut Window,
11098        cx: &mut Context<Self>,
11099        mut callback: Fn,
11100    ) where
11101        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11102    {
11103        self.manipulate_lines(window, cx, |text| {
11104            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11105            let line_count_before = lines.len();
11106
11107            callback(&mut lines);
11108
11109            LineManipulationResult {
11110                new_text: lines.join("\n"),
11111                line_count_before,
11112                line_count_after: lines.len(),
11113            }
11114        });
11115    }
11116
11117    pub fn convert_indentation_to_spaces(
11118        &mut self,
11119        _: &ConvertIndentationToSpaces,
11120        window: &mut Window,
11121        cx: &mut Context<Self>,
11122    ) {
11123        let settings = self.buffer.read(cx).language_settings(cx);
11124        let tab_size = settings.tab_size.get() as usize;
11125
11126        self.manipulate_mutable_lines(window, cx, |lines| {
11127            // Allocates a reasonably sized scratch buffer once for the whole loop
11128            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11129            // Avoids recomputing spaces that could be inserted many times
11130            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11131                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11132                .collect();
11133
11134            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11135                let mut chars = line.as_ref().chars();
11136                let mut col = 0;
11137                let mut changed = false;
11138
11139                for ch in chars.by_ref() {
11140                    match ch {
11141                        ' ' => {
11142                            reindented_line.push(' ');
11143                            col += 1;
11144                        }
11145                        '\t' => {
11146                            // \t are converted to spaces depending on the current column
11147                            let spaces_len = tab_size - (col % tab_size);
11148                            reindented_line.extend(&space_cache[spaces_len - 1]);
11149                            col += spaces_len;
11150                            changed = true;
11151                        }
11152                        _ => {
11153                            // If we dont append before break, the character is consumed
11154                            reindented_line.push(ch);
11155                            break;
11156                        }
11157                    }
11158                }
11159
11160                if !changed {
11161                    reindented_line.clear();
11162                    continue;
11163                }
11164                // Append the rest of the line and replace old reference with new one
11165                reindented_line.extend(chars);
11166                *line = Cow::Owned(reindented_line.clone());
11167                reindented_line.clear();
11168            }
11169        });
11170    }
11171
11172    pub fn convert_indentation_to_tabs(
11173        &mut self,
11174        _: &ConvertIndentationToTabs,
11175        window: &mut Window,
11176        cx: &mut Context<Self>,
11177    ) {
11178        let settings = self.buffer.read(cx).language_settings(cx);
11179        let tab_size = settings.tab_size.get() as usize;
11180
11181        self.manipulate_mutable_lines(window, cx, |lines| {
11182            // Allocates a reasonably sized buffer once for the whole loop
11183            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11184            // Avoids recomputing spaces that could be inserted many times
11185            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11186                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11187                .collect();
11188
11189            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11190                let mut chars = line.chars();
11191                let mut spaces_count = 0;
11192                let mut first_non_indent_char = None;
11193                let mut changed = false;
11194
11195                for ch in chars.by_ref() {
11196                    match ch {
11197                        ' ' => {
11198                            // Keep track of spaces. Append \t when we reach tab_size
11199                            spaces_count += 1;
11200                            changed = true;
11201                            if spaces_count == tab_size {
11202                                reindented_line.push('\t');
11203                                spaces_count = 0;
11204                            }
11205                        }
11206                        '\t' => {
11207                            reindented_line.push('\t');
11208                            spaces_count = 0;
11209                        }
11210                        _ => {
11211                            // Dont append it yet, we might have remaining spaces
11212                            first_non_indent_char = Some(ch);
11213                            break;
11214                        }
11215                    }
11216                }
11217
11218                if !changed {
11219                    reindented_line.clear();
11220                    continue;
11221                }
11222                // Remaining spaces that didn't make a full tab stop
11223                if spaces_count > 0 {
11224                    reindented_line.extend(&space_cache[spaces_count - 1]);
11225                }
11226                // If we consume an extra character that was not indentation, add it back
11227                if let Some(extra_char) = first_non_indent_char {
11228                    reindented_line.push(extra_char);
11229                }
11230                // Append the rest of the line and replace old reference with new one
11231                reindented_line.extend(chars);
11232                *line = Cow::Owned(reindented_line.clone());
11233                reindented_line.clear();
11234            }
11235        });
11236    }
11237
11238    pub fn convert_to_upper_case(
11239        &mut self,
11240        _: &ConvertToUpperCase,
11241        window: &mut Window,
11242        cx: &mut Context<Self>,
11243    ) {
11244        self.manipulate_text(window, cx, |text| text.to_uppercase())
11245    }
11246
11247    pub fn convert_to_lower_case(
11248        &mut self,
11249        _: &ConvertToLowerCase,
11250        window: &mut Window,
11251        cx: &mut Context<Self>,
11252    ) {
11253        self.manipulate_text(window, cx, |text| text.to_lowercase())
11254    }
11255
11256    pub fn convert_to_title_case(
11257        &mut self,
11258        _: &ConvertToTitleCase,
11259        window: &mut Window,
11260        cx: &mut Context<Self>,
11261    ) {
11262        self.manipulate_text(window, cx, |text| {
11263            text.split('\n')
11264                .map(|line| line.to_case(Case::Title))
11265                .join("\n")
11266        })
11267    }
11268
11269    pub fn convert_to_snake_case(
11270        &mut self,
11271        _: &ConvertToSnakeCase,
11272        window: &mut Window,
11273        cx: &mut Context<Self>,
11274    ) {
11275        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11276    }
11277
11278    pub fn convert_to_kebab_case(
11279        &mut self,
11280        _: &ConvertToKebabCase,
11281        window: &mut Window,
11282        cx: &mut Context<Self>,
11283    ) {
11284        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11285    }
11286
11287    pub fn convert_to_upper_camel_case(
11288        &mut self,
11289        _: &ConvertToUpperCamelCase,
11290        window: &mut Window,
11291        cx: &mut Context<Self>,
11292    ) {
11293        self.manipulate_text(window, cx, |text| {
11294            text.split('\n')
11295                .map(|line| line.to_case(Case::UpperCamel))
11296                .join("\n")
11297        })
11298    }
11299
11300    pub fn convert_to_lower_camel_case(
11301        &mut self,
11302        _: &ConvertToLowerCamelCase,
11303        window: &mut Window,
11304        cx: &mut Context<Self>,
11305    ) {
11306        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11307    }
11308
11309    pub fn convert_to_opposite_case(
11310        &mut self,
11311        _: &ConvertToOppositeCase,
11312        window: &mut Window,
11313        cx: &mut Context<Self>,
11314    ) {
11315        self.manipulate_text(window, cx, |text| {
11316            text.chars()
11317                .fold(String::with_capacity(text.len()), |mut t, c| {
11318                    if c.is_uppercase() {
11319                        t.extend(c.to_lowercase());
11320                    } else {
11321                        t.extend(c.to_uppercase());
11322                    }
11323                    t
11324                })
11325        })
11326    }
11327
11328    pub fn convert_to_sentence_case(
11329        &mut self,
11330        _: &ConvertToSentenceCase,
11331        window: &mut Window,
11332        cx: &mut Context<Self>,
11333    ) {
11334        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11335    }
11336
11337    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11338        self.manipulate_text(window, cx, |text| {
11339            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11340            if has_upper_case_characters {
11341                text.to_lowercase()
11342            } else {
11343                text.to_uppercase()
11344            }
11345        })
11346    }
11347
11348    pub fn convert_to_rot13(
11349        &mut self,
11350        _: &ConvertToRot13,
11351        window: &mut Window,
11352        cx: &mut Context<Self>,
11353    ) {
11354        self.manipulate_text(window, cx, |text| {
11355            text.chars()
11356                .map(|c| match c {
11357                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11358                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11359                    _ => c,
11360                })
11361                .collect()
11362        })
11363    }
11364
11365    pub fn convert_to_rot47(
11366        &mut self,
11367        _: &ConvertToRot47,
11368        window: &mut Window,
11369        cx: &mut Context<Self>,
11370    ) {
11371        self.manipulate_text(window, cx, |text| {
11372            text.chars()
11373                .map(|c| {
11374                    let code_point = c as u32;
11375                    if code_point >= 33 && code_point <= 126 {
11376                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11377                    }
11378                    c
11379                })
11380                .collect()
11381        })
11382    }
11383
11384    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11385    where
11386        Fn: FnMut(&str) -> String,
11387    {
11388        let buffer = self.buffer.read(cx).snapshot(cx);
11389
11390        let mut new_selections = Vec::new();
11391        let mut edits = Vec::new();
11392        let mut selection_adjustment = 0i32;
11393
11394        for selection in self.selections.all::<usize>(cx) {
11395            let selection_is_empty = selection.is_empty();
11396
11397            let (start, end) = if selection_is_empty {
11398                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11399                (word_range.start, word_range.end)
11400            } else {
11401                (selection.start, selection.end)
11402            };
11403
11404            let text = buffer.text_for_range(start..end).collect::<String>();
11405            let old_length = text.len() as i32;
11406            let text = callback(&text);
11407
11408            new_selections.push(Selection {
11409                start: (start as i32 - selection_adjustment) as usize,
11410                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11411                goal: SelectionGoal::None,
11412                ..selection
11413            });
11414
11415            selection_adjustment += old_length - text.len() as i32;
11416
11417            edits.push((start..end, text));
11418        }
11419
11420        self.transact(window, cx, |this, window, cx| {
11421            this.buffer.update(cx, |buffer, cx| {
11422                buffer.edit(edits, None, cx);
11423            });
11424
11425            this.change_selections(Default::default(), window, cx, |s| {
11426                s.select(new_selections);
11427            });
11428
11429            this.request_autoscroll(Autoscroll::fit(), cx);
11430        });
11431    }
11432
11433    pub fn move_selection_on_drop(
11434        &mut self,
11435        selection: &Selection<Anchor>,
11436        target: DisplayPoint,
11437        is_cut: bool,
11438        window: &mut Window,
11439        cx: &mut Context<Self>,
11440    ) {
11441        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11442        let buffer = &display_map.buffer_snapshot;
11443        let mut edits = Vec::new();
11444        let insert_point = display_map
11445            .clip_point(target, Bias::Left)
11446            .to_point(&display_map);
11447        let text = buffer
11448            .text_for_range(selection.start..selection.end)
11449            .collect::<String>();
11450        if is_cut {
11451            edits.push(((selection.start..selection.end), String::new()));
11452        }
11453        let insert_anchor = buffer.anchor_before(insert_point);
11454        edits.push(((insert_anchor..insert_anchor), text));
11455        let last_edit_start = insert_anchor.bias_left(buffer);
11456        let last_edit_end = insert_anchor.bias_right(buffer);
11457        self.transact(window, cx, |this, window, cx| {
11458            this.buffer.update(cx, |buffer, cx| {
11459                buffer.edit(edits, None, cx);
11460            });
11461            this.change_selections(Default::default(), window, cx, |s| {
11462                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11463            });
11464        });
11465    }
11466
11467    pub fn clear_selection_drag_state(&mut self) {
11468        self.selection_drag_state = SelectionDragState::None;
11469    }
11470
11471    pub fn duplicate(
11472        &mut self,
11473        upwards: bool,
11474        whole_lines: bool,
11475        window: &mut Window,
11476        cx: &mut Context<Self>,
11477    ) {
11478        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11479
11480        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11481        let buffer = &display_map.buffer_snapshot;
11482        let selections = self.selections.all::<Point>(cx);
11483
11484        let mut edits = Vec::new();
11485        let mut selections_iter = selections.iter().peekable();
11486        while let Some(selection) = selections_iter.next() {
11487            let mut rows = selection.spanned_rows(false, &display_map);
11488            // duplicate line-wise
11489            if whole_lines || selection.start == selection.end {
11490                // Avoid duplicating the same lines twice.
11491                while let Some(next_selection) = selections_iter.peek() {
11492                    let next_rows = next_selection.spanned_rows(false, &display_map);
11493                    if next_rows.start < rows.end {
11494                        rows.end = next_rows.end;
11495                        selections_iter.next().unwrap();
11496                    } else {
11497                        break;
11498                    }
11499                }
11500
11501                // Copy the text from the selected row region and splice it either at the start
11502                // or end of the region.
11503                let start = Point::new(rows.start.0, 0);
11504                let end = Point::new(
11505                    rows.end.previous_row().0,
11506                    buffer.line_len(rows.end.previous_row()),
11507                );
11508                let text = buffer
11509                    .text_for_range(start..end)
11510                    .chain(Some("\n"))
11511                    .collect::<String>();
11512                let insert_location = if upwards {
11513                    Point::new(rows.end.0, 0)
11514                } else {
11515                    start
11516                };
11517                edits.push((insert_location..insert_location, text));
11518            } else {
11519                // duplicate character-wise
11520                let start = selection.start;
11521                let end = selection.end;
11522                let text = buffer.text_for_range(start..end).collect::<String>();
11523                edits.push((selection.end..selection.end, text));
11524            }
11525        }
11526
11527        self.transact(window, cx, |this, _, cx| {
11528            this.buffer.update(cx, |buffer, cx| {
11529                buffer.edit(edits, None, cx);
11530            });
11531
11532            this.request_autoscroll(Autoscroll::fit(), cx);
11533        });
11534    }
11535
11536    pub fn duplicate_line_up(
11537        &mut self,
11538        _: &DuplicateLineUp,
11539        window: &mut Window,
11540        cx: &mut Context<Self>,
11541    ) {
11542        self.duplicate(true, true, window, cx);
11543    }
11544
11545    pub fn duplicate_line_down(
11546        &mut self,
11547        _: &DuplicateLineDown,
11548        window: &mut Window,
11549        cx: &mut Context<Self>,
11550    ) {
11551        self.duplicate(false, true, window, cx);
11552    }
11553
11554    pub fn duplicate_selection(
11555        &mut self,
11556        _: &DuplicateSelection,
11557        window: &mut Window,
11558        cx: &mut Context<Self>,
11559    ) {
11560        self.duplicate(false, false, window, cx);
11561    }
11562
11563    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11564        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11565        if self.mode.is_single_line() {
11566            cx.propagate();
11567            return;
11568        }
11569
11570        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11571        let buffer = self.buffer.read(cx).snapshot(cx);
11572
11573        let mut edits = Vec::new();
11574        let mut unfold_ranges = Vec::new();
11575        let mut refold_creases = Vec::new();
11576
11577        let selections = self.selections.all::<Point>(cx);
11578        let mut selections = selections.iter().peekable();
11579        let mut contiguous_row_selections = Vec::new();
11580        let mut new_selections = Vec::new();
11581
11582        while let Some(selection) = selections.next() {
11583            // Find all the selections that span a contiguous row range
11584            let (start_row, end_row) = consume_contiguous_rows(
11585                &mut contiguous_row_selections,
11586                selection,
11587                &display_map,
11588                &mut selections,
11589            );
11590
11591            // Move the text spanned by the row range to be before the line preceding the row range
11592            if start_row.0 > 0 {
11593                let range_to_move = Point::new(
11594                    start_row.previous_row().0,
11595                    buffer.line_len(start_row.previous_row()),
11596                )
11597                    ..Point::new(
11598                        end_row.previous_row().0,
11599                        buffer.line_len(end_row.previous_row()),
11600                    );
11601                let insertion_point = display_map
11602                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11603                    .0;
11604
11605                // Don't move lines across excerpts
11606                if buffer
11607                    .excerpt_containing(insertion_point..range_to_move.end)
11608                    .is_some()
11609                {
11610                    let text = buffer
11611                        .text_for_range(range_to_move.clone())
11612                        .flat_map(|s| s.chars())
11613                        .skip(1)
11614                        .chain(['\n'])
11615                        .collect::<String>();
11616
11617                    edits.push((
11618                        buffer.anchor_after(range_to_move.start)
11619                            ..buffer.anchor_before(range_to_move.end),
11620                        String::new(),
11621                    ));
11622                    let insertion_anchor = buffer.anchor_after(insertion_point);
11623                    edits.push((insertion_anchor..insertion_anchor, text));
11624
11625                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11626
11627                    // Move selections up
11628                    new_selections.extend(contiguous_row_selections.drain(..).map(
11629                        |mut selection| {
11630                            selection.start.row -= row_delta;
11631                            selection.end.row -= row_delta;
11632                            selection
11633                        },
11634                    ));
11635
11636                    // Move folds up
11637                    unfold_ranges.push(range_to_move.clone());
11638                    for fold in display_map.folds_in_range(
11639                        buffer.anchor_before(range_to_move.start)
11640                            ..buffer.anchor_after(range_to_move.end),
11641                    ) {
11642                        let mut start = fold.range.start.to_point(&buffer);
11643                        let mut end = fold.range.end.to_point(&buffer);
11644                        start.row -= row_delta;
11645                        end.row -= row_delta;
11646                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11647                    }
11648                }
11649            }
11650
11651            // If we didn't move line(s), preserve the existing selections
11652            new_selections.append(&mut contiguous_row_selections);
11653        }
11654
11655        self.transact(window, cx, |this, window, cx| {
11656            this.unfold_ranges(&unfold_ranges, true, true, cx);
11657            this.buffer.update(cx, |buffer, cx| {
11658                for (range, text) in edits {
11659                    buffer.edit([(range, text)], None, cx);
11660                }
11661            });
11662            this.fold_creases(refold_creases, true, window, cx);
11663            this.change_selections(Default::default(), window, cx, |s| {
11664                s.select(new_selections);
11665            })
11666        });
11667    }
11668
11669    pub fn move_line_down(
11670        &mut self,
11671        _: &MoveLineDown,
11672        window: &mut Window,
11673        cx: &mut Context<Self>,
11674    ) {
11675        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11676        if self.mode.is_single_line() {
11677            cx.propagate();
11678            return;
11679        }
11680
11681        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11682        let buffer = self.buffer.read(cx).snapshot(cx);
11683
11684        let mut edits = Vec::new();
11685        let mut unfold_ranges = Vec::new();
11686        let mut refold_creases = Vec::new();
11687
11688        let selections = self.selections.all::<Point>(cx);
11689        let mut selections = selections.iter().peekable();
11690        let mut contiguous_row_selections = Vec::new();
11691        let mut new_selections = Vec::new();
11692
11693        while let Some(selection) = selections.next() {
11694            // Find all the selections that span a contiguous row range
11695            let (start_row, end_row) = consume_contiguous_rows(
11696                &mut contiguous_row_selections,
11697                selection,
11698                &display_map,
11699                &mut selections,
11700            );
11701
11702            // Move the text spanned by the row range to be after the last line of the row range
11703            if end_row.0 <= buffer.max_point().row {
11704                let range_to_move =
11705                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11706                let insertion_point = display_map
11707                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11708                    .0;
11709
11710                // Don't move lines across excerpt boundaries
11711                if buffer
11712                    .excerpt_containing(range_to_move.start..insertion_point)
11713                    .is_some()
11714                {
11715                    let mut text = String::from("\n");
11716                    text.extend(buffer.text_for_range(range_to_move.clone()));
11717                    text.pop(); // Drop trailing newline
11718                    edits.push((
11719                        buffer.anchor_after(range_to_move.start)
11720                            ..buffer.anchor_before(range_to_move.end),
11721                        String::new(),
11722                    ));
11723                    let insertion_anchor = buffer.anchor_after(insertion_point);
11724                    edits.push((insertion_anchor..insertion_anchor, text));
11725
11726                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11727
11728                    // Move selections down
11729                    new_selections.extend(contiguous_row_selections.drain(..).map(
11730                        |mut selection| {
11731                            selection.start.row += row_delta;
11732                            selection.end.row += row_delta;
11733                            selection
11734                        },
11735                    ));
11736
11737                    // Move folds down
11738                    unfold_ranges.push(range_to_move.clone());
11739                    for fold in display_map.folds_in_range(
11740                        buffer.anchor_before(range_to_move.start)
11741                            ..buffer.anchor_after(range_to_move.end),
11742                    ) {
11743                        let mut start = fold.range.start.to_point(&buffer);
11744                        let mut end = fold.range.end.to_point(&buffer);
11745                        start.row += row_delta;
11746                        end.row += row_delta;
11747                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11748                    }
11749                }
11750            }
11751
11752            // If we didn't move line(s), preserve the existing selections
11753            new_selections.append(&mut contiguous_row_selections);
11754        }
11755
11756        self.transact(window, cx, |this, window, cx| {
11757            this.unfold_ranges(&unfold_ranges, true, true, cx);
11758            this.buffer.update(cx, |buffer, cx| {
11759                for (range, text) in edits {
11760                    buffer.edit([(range, text)], None, cx);
11761                }
11762            });
11763            this.fold_creases(refold_creases, true, window, cx);
11764            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11765        });
11766    }
11767
11768    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11769        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11770        let text_layout_details = &self.text_layout_details(window);
11771        self.transact(window, cx, |this, window, cx| {
11772            let edits = this.change_selections(Default::default(), window, cx, |s| {
11773                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11774                s.move_with(|display_map, selection| {
11775                    if !selection.is_empty() {
11776                        return;
11777                    }
11778
11779                    let mut head = selection.head();
11780                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11781                    if head.column() == display_map.line_len(head.row()) {
11782                        transpose_offset = display_map
11783                            .buffer_snapshot
11784                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11785                    }
11786
11787                    if transpose_offset == 0 {
11788                        return;
11789                    }
11790
11791                    *head.column_mut() += 1;
11792                    head = display_map.clip_point(head, Bias::Right);
11793                    let goal = SelectionGoal::HorizontalPosition(
11794                        display_map
11795                            .x_for_display_point(head, text_layout_details)
11796                            .into(),
11797                    );
11798                    selection.collapse_to(head, goal);
11799
11800                    let transpose_start = display_map
11801                        .buffer_snapshot
11802                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11803                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11804                        let transpose_end = display_map
11805                            .buffer_snapshot
11806                            .clip_offset(transpose_offset + 1, Bias::Right);
11807                        if let Some(ch) =
11808                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11809                        {
11810                            edits.push((transpose_start..transpose_offset, String::new()));
11811                            edits.push((transpose_end..transpose_end, ch.to_string()));
11812                        }
11813                    }
11814                });
11815                edits
11816            });
11817            this.buffer
11818                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11819            let selections = this.selections.all::<usize>(cx);
11820            this.change_selections(Default::default(), window, cx, |s| {
11821                s.select(selections);
11822            });
11823        });
11824    }
11825
11826    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11827        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11828        if self.mode.is_single_line() {
11829            cx.propagate();
11830            return;
11831        }
11832
11833        self.rewrap_impl(RewrapOptions::default(), cx)
11834    }
11835
11836    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11837        let buffer = self.buffer.read(cx).snapshot(cx);
11838        let selections = self.selections.all::<Point>(cx);
11839
11840        #[derive(Clone, Debug, PartialEq)]
11841        enum CommentFormat {
11842            /// single line comment, with prefix for line
11843            Line(String),
11844            /// single line within a block comment, with prefix for line
11845            BlockLine(String),
11846            /// a single line of a block comment that includes the initial delimiter
11847            BlockCommentWithStart(BlockCommentConfig),
11848            /// a single line of a block comment that includes the ending delimiter
11849            BlockCommentWithEnd(BlockCommentConfig),
11850        }
11851
11852        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11853        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11854            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11855                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11856                .peekable();
11857
11858            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11859                row
11860            } else {
11861                return Vec::new();
11862            };
11863
11864            let language_settings = buffer.language_settings_at(selection.head(), cx);
11865            let language_scope = buffer.language_scope_at(selection.head());
11866
11867            let indent_and_prefix_for_row =
11868                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11869                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11870                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11871                        &language_scope
11872                    {
11873                        let indent_end = Point::new(row, indent.len);
11874                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11875                        let line_text_after_indent = buffer
11876                            .text_for_range(indent_end..line_end)
11877                            .collect::<String>();
11878
11879                        let is_within_comment_override = buffer
11880                            .language_scope_at(indent_end)
11881                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11882                        let comment_delimiters = if is_within_comment_override {
11883                            // we are within a comment syntax node, but we don't
11884                            // yet know what kind of comment: block, doc or line
11885                            match (
11886                                language_scope.documentation_comment(),
11887                                language_scope.block_comment(),
11888                            ) {
11889                                (Some(config), _) | (_, Some(config))
11890                                    if buffer.contains_str_at(indent_end, &config.start) =>
11891                                {
11892                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11893                                }
11894                                (Some(config), _) | (_, Some(config))
11895                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11896                                {
11897                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11898                                }
11899                                (Some(config), _) | (_, Some(config))
11900                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11901                                {
11902                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11903                                }
11904                                (_, _) => language_scope
11905                                    .line_comment_prefixes()
11906                                    .iter()
11907                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11908                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11909                            }
11910                        } else {
11911                            // we not in an overridden comment node, but we may
11912                            // be within a non-overridden line comment node
11913                            language_scope
11914                                .line_comment_prefixes()
11915                                .iter()
11916                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11917                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11918                        };
11919
11920                        let rewrap_prefix = language_scope
11921                            .rewrap_prefixes()
11922                            .iter()
11923                            .find_map(|prefix_regex| {
11924                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11925                                    if mat.start() == 0 {
11926                                        Some(mat.as_str().to_string())
11927                                    } else {
11928                                        None
11929                                    }
11930                                })
11931                            })
11932                            .flatten();
11933                        (comment_delimiters, rewrap_prefix)
11934                    } else {
11935                        (None, None)
11936                    };
11937                    (indent, comment_prefix, rewrap_prefix)
11938                };
11939
11940            let mut ranges = Vec::new();
11941            let from_empty_selection = selection.is_empty();
11942
11943            let mut current_range_start = first_row;
11944            let mut prev_row = first_row;
11945            let (
11946                mut current_range_indent,
11947                mut current_range_comment_delimiters,
11948                mut current_range_rewrap_prefix,
11949            ) = indent_and_prefix_for_row(first_row);
11950
11951            for row in non_blank_rows_iter.skip(1) {
11952                let has_paragraph_break = row > prev_row + 1;
11953
11954                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
11955                    indent_and_prefix_for_row(row);
11956
11957                let has_indent_change = row_indent != current_range_indent;
11958                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
11959
11960                let has_boundary_change = has_comment_change
11961                    || row_rewrap_prefix.is_some()
11962                    || (has_indent_change && current_range_comment_delimiters.is_some());
11963
11964                if has_paragraph_break || has_boundary_change {
11965                    ranges.push((
11966                        language_settings.clone(),
11967                        Point::new(current_range_start, 0)
11968                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11969                        current_range_indent,
11970                        current_range_comment_delimiters.clone(),
11971                        current_range_rewrap_prefix.clone(),
11972                        from_empty_selection,
11973                    ));
11974                    current_range_start = row;
11975                    current_range_indent = row_indent;
11976                    current_range_comment_delimiters = row_comment_delimiters;
11977                    current_range_rewrap_prefix = row_rewrap_prefix;
11978                }
11979                prev_row = row;
11980            }
11981
11982            ranges.push((
11983                language_settings.clone(),
11984                Point::new(current_range_start, 0)
11985                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11986                current_range_indent,
11987                current_range_comment_delimiters,
11988                current_range_rewrap_prefix,
11989                from_empty_selection,
11990            ));
11991
11992            ranges
11993        });
11994
11995        let mut edits = Vec::new();
11996        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11997
11998        for (
11999            language_settings,
12000            wrap_range,
12001            mut indent_size,
12002            comment_prefix,
12003            rewrap_prefix,
12004            from_empty_selection,
12005        ) in wrap_ranges
12006        {
12007            let mut start_row = wrap_range.start.row;
12008            let mut end_row = wrap_range.end.row;
12009
12010            // Skip selections that overlap with a range that has already been rewrapped.
12011            let selection_range = start_row..end_row;
12012            if rewrapped_row_ranges
12013                .iter()
12014                .any(|range| range.overlaps(&selection_range))
12015            {
12016                continue;
12017            }
12018
12019            let tab_size = language_settings.tab_size;
12020
12021            let (line_prefix, inside_comment) = match &comment_prefix {
12022                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12023                    (Some(prefix.as_str()), true)
12024                }
12025                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12026                    (Some(prefix.as_ref()), true)
12027                }
12028                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12029                    start: _,
12030                    end: _,
12031                    prefix,
12032                    tab_size,
12033                })) => {
12034                    indent_size.len += tab_size;
12035                    (Some(prefix.as_ref()), true)
12036                }
12037                None => (None, false),
12038            };
12039            let indent_prefix = indent_size.chars().collect::<String>();
12040            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12041
12042            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12043                RewrapBehavior::InComments => inside_comment,
12044                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12045                RewrapBehavior::Anywhere => true,
12046            };
12047
12048            let should_rewrap = options.override_language_settings
12049                || allow_rewrap_based_on_language
12050                || self.hard_wrap.is_some();
12051            if !should_rewrap {
12052                continue;
12053            }
12054
12055            if from_empty_selection {
12056                'expand_upwards: while start_row > 0 {
12057                    let prev_row = start_row - 1;
12058                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12059                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12060                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12061                    {
12062                        start_row = prev_row;
12063                    } else {
12064                        break 'expand_upwards;
12065                    }
12066                }
12067
12068                'expand_downwards: while end_row < buffer.max_point().row {
12069                    let next_row = end_row + 1;
12070                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12071                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12072                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12073                    {
12074                        end_row = next_row;
12075                    } else {
12076                        break 'expand_downwards;
12077                    }
12078                }
12079            }
12080
12081            let start = Point::new(start_row, 0);
12082            let start_offset = start.to_offset(&buffer);
12083            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12084            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12085            let mut first_line_delimiter = None;
12086            let mut last_line_delimiter = None;
12087            let Some(lines_without_prefixes) = selection_text
12088                .lines()
12089                .enumerate()
12090                .map(|(ix, line)| {
12091                    let line_trimmed = line.trim_start();
12092                    if rewrap_prefix.is_some() && ix > 0 {
12093                        Ok(line_trimmed)
12094                    } else if let Some(
12095                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12096                            start,
12097                            prefix,
12098                            end,
12099                            tab_size,
12100                        })
12101                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12102                            start,
12103                            prefix,
12104                            end,
12105                            tab_size,
12106                        }),
12107                    ) = &comment_prefix
12108                    {
12109                        let line_trimmed = line_trimmed
12110                            .strip_prefix(start.as_ref())
12111                            .map(|s| {
12112                                let mut indent_size = indent_size;
12113                                indent_size.len -= tab_size;
12114                                let indent_prefix: String = indent_size.chars().collect();
12115                                first_line_delimiter = Some((indent_prefix, start));
12116                                s.trim_start()
12117                            })
12118                            .unwrap_or(line_trimmed);
12119                        let line_trimmed = line_trimmed
12120                            .strip_suffix(end.as_ref())
12121                            .map(|s| {
12122                                last_line_delimiter = Some(end);
12123                                s.trim_end()
12124                            })
12125                            .unwrap_or(line_trimmed);
12126                        let line_trimmed = line_trimmed
12127                            .strip_prefix(prefix.as_ref())
12128                            .unwrap_or(line_trimmed);
12129                        Ok(line_trimmed)
12130                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12131                        line_trimmed.strip_prefix(prefix).with_context(|| {
12132                            format!("line did not start with prefix {prefix:?}: {line:?}")
12133                        })
12134                    } else {
12135                        line_trimmed
12136                            .strip_prefix(&line_prefix.trim_start())
12137                            .with_context(|| {
12138                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12139                            })
12140                    }
12141                })
12142                .collect::<Result<Vec<_>, _>>()
12143                .log_err()
12144            else {
12145                continue;
12146            };
12147
12148            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12149                buffer
12150                    .language_settings_at(Point::new(start_row, 0), cx)
12151                    .preferred_line_length as usize
12152            });
12153
12154            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12155                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12156            } else {
12157                line_prefix.clone()
12158            };
12159
12160            let wrapped_text = {
12161                let mut wrapped_text = wrap_with_prefix(
12162                    line_prefix,
12163                    subsequent_lines_prefix,
12164                    lines_without_prefixes.join("\n"),
12165                    wrap_column,
12166                    tab_size,
12167                    options.preserve_existing_whitespace,
12168                );
12169
12170                if let Some((indent, delimiter)) = first_line_delimiter {
12171                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12172                }
12173                if let Some(last_line) = last_line_delimiter {
12174                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12175                }
12176
12177                wrapped_text
12178            };
12179
12180            // TODO: should always use char-based diff while still supporting cursor behavior that
12181            // matches vim.
12182            let mut diff_options = DiffOptions::default();
12183            if options.override_language_settings {
12184                diff_options.max_word_diff_len = 0;
12185                diff_options.max_word_diff_line_count = 0;
12186            } else {
12187                diff_options.max_word_diff_len = usize::MAX;
12188                diff_options.max_word_diff_line_count = usize::MAX;
12189            }
12190
12191            for (old_range, new_text) in
12192                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12193            {
12194                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12195                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12196                edits.push((edit_start..edit_end, new_text));
12197            }
12198
12199            rewrapped_row_ranges.push(start_row..=end_row);
12200        }
12201
12202        self.buffer
12203            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12204    }
12205
12206    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12207        let mut text = String::new();
12208        let buffer = self.buffer.read(cx).snapshot(cx);
12209        let mut selections = self.selections.all::<Point>(cx);
12210        let mut clipboard_selections = Vec::with_capacity(selections.len());
12211        {
12212            let max_point = buffer.max_point();
12213            let mut is_first = true;
12214            for selection in &mut selections {
12215                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12216                if is_entire_line {
12217                    selection.start = Point::new(selection.start.row, 0);
12218                    if !selection.is_empty() && selection.end.column == 0 {
12219                        selection.end = cmp::min(max_point, selection.end);
12220                    } else {
12221                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12222                    }
12223                    selection.goal = SelectionGoal::None;
12224                }
12225                if is_first {
12226                    is_first = false;
12227                } else {
12228                    text += "\n";
12229                }
12230                let mut len = 0;
12231                for chunk in buffer.text_for_range(selection.start..selection.end) {
12232                    text.push_str(chunk);
12233                    len += chunk.len();
12234                }
12235                clipboard_selections.push(ClipboardSelection {
12236                    len,
12237                    is_entire_line,
12238                    first_line_indent: buffer
12239                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12240                        .len,
12241                });
12242            }
12243        }
12244
12245        self.transact(window, cx, |this, window, cx| {
12246            this.change_selections(Default::default(), window, cx, |s| {
12247                s.select(selections);
12248            });
12249            this.insert("", window, cx);
12250        });
12251        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12252    }
12253
12254    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12255        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12256        let item = self.cut_common(window, cx);
12257        cx.write_to_clipboard(item);
12258    }
12259
12260    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12261        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12262        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12263            s.move_with(|snapshot, sel| {
12264                if sel.is_empty() {
12265                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12266                }
12267            });
12268        });
12269        let item = self.cut_common(window, cx);
12270        cx.set_global(KillRing(item))
12271    }
12272
12273    pub fn kill_ring_yank(
12274        &mut self,
12275        _: &KillRingYank,
12276        window: &mut Window,
12277        cx: &mut Context<Self>,
12278    ) {
12279        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12280        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12281            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12282                (kill_ring.text().to_string(), kill_ring.metadata_json())
12283            } else {
12284                return;
12285            }
12286        } else {
12287            return;
12288        };
12289        self.do_paste(&text, metadata, false, window, cx);
12290    }
12291
12292    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12293        self.do_copy(true, cx);
12294    }
12295
12296    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12297        self.do_copy(false, cx);
12298    }
12299
12300    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12301        let selections = self.selections.all::<Point>(cx);
12302        let buffer = self.buffer.read(cx).read(cx);
12303        let mut text = String::new();
12304
12305        let mut clipboard_selections = Vec::with_capacity(selections.len());
12306        {
12307            let max_point = buffer.max_point();
12308            let mut is_first = true;
12309            for selection in &selections {
12310                let mut start = selection.start;
12311                let mut end = selection.end;
12312                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12313                if is_entire_line {
12314                    start = Point::new(start.row, 0);
12315                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12316                }
12317
12318                let mut trimmed_selections = Vec::new();
12319                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12320                    let row = MultiBufferRow(start.row);
12321                    let first_indent = buffer.indent_size_for_line(row);
12322                    if first_indent.len == 0 || start.column > first_indent.len {
12323                        trimmed_selections.push(start..end);
12324                    } else {
12325                        trimmed_selections.push(
12326                            Point::new(row.0, first_indent.len)
12327                                ..Point::new(row.0, buffer.line_len(row)),
12328                        );
12329                        for row in start.row + 1..=end.row {
12330                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12331                            if row == end.row {
12332                                line_len = end.column;
12333                            }
12334                            if line_len == 0 {
12335                                trimmed_selections
12336                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12337                                continue;
12338                            }
12339                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12340                            if row_indent_size.len >= first_indent.len {
12341                                trimmed_selections.push(
12342                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12343                                );
12344                            } else {
12345                                trimmed_selections.clear();
12346                                trimmed_selections.push(start..end);
12347                                break;
12348                            }
12349                        }
12350                    }
12351                } else {
12352                    trimmed_selections.push(start..end);
12353                }
12354
12355                for trimmed_range in trimmed_selections {
12356                    if is_first {
12357                        is_first = false;
12358                    } else {
12359                        text += "\n";
12360                    }
12361                    let mut len = 0;
12362                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12363                        text.push_str(chunk);
12364                        len += chunk.len();
12365                    }
12366                    clipboard_selections.push(ClipboardSelection {
12367                        len,
12368                        is_entire_line,
12369                        first_line_indent: buffer
12370                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12371                            .len,
12372                    });
12373                }
12374            }
12375        }
12376
12377        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12378            text,
12379            clipboard_selections,
12380        ));
12381    }
12382
12383    pub fn do_paste(
12384        &mut self,
12385        text: &String,
12386        clipboard_selections: Option<Vec<ClipboardSelection>>,
12387        handle_entire_lines: bool,
12388        window: &mut Window,
12389        cx: &mut Context<Self>,
12390    ) {
12391        if self.read_only(cx) {
12392            return;
12393        }
12394
12395        let clipboard_text = Cow::Borrowed(text);
12396
12397        self.transact(window, cx, |this, window, cx| {
12398            let had_active_edit_prediction = this.has_active_edit_prediction();
12399
12400            if let Some(mut clipboard_selections) = clipboard_selections {
12401                let old_selections = this.selections.all::<usize>(cx);
12402                let all_selections_were_entire_line =
12403                    clipboard_selections.iter().all(|s| s.is_entire_line);
12404                let first_selection_indent_column =
12405                    clipboard_selections.first().map(|s| s.first_line_indent);
12406                if clipboard_selections.len() != old_selections.len() {
12407                    clipboard_selections.drain(..);
12408                }
12409                let cursor_offset = this.selections.last::<usize>(cx).head();
12410                let mut auto_indent_on_paste = true;
12411
12412                this.buffer.update(cx, |buffer, cx| {
12413                    let snapshot = buffer.read(cx);
12414                    auto_indent_on_paste = snapshot
12415                        .language_settings_at(cursor_offset, cx)
12416                        .auto_indent_on_paste;
12417
12418                    let mut start_offset = 0;
12419                    let mut edits = Vec::new();
12420                    let mut original_indent_columns = Vec::new();
12421                    for (ix, selection) in old_selections.iter().enumerate() {
12422                        let to_insert;
12423                        let entire_line;
12424                        let original_indent_column;
12425                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12426                            let end_offset = start_offset + clipboard_selection.len;
12427                            to_insert = &clipboard_text[start_offset..end_offset];
12428                            entire_line = clipboard_selection.is_entire_line;
12429                            start_offset = end_offset + 1;
12430                            original_indent_column = Some(clipboard_selection.first_line_indent);
12431                        } else {
12432                            to_insert = clipboard_text.as_str();
12433                            entire_line = all_selections_were_entire_line;
12434                            original_indent_column = first_selection_indent_column
12435                        }
12436
12437                        // If the corresponding selection was empty when this slice of the
12438                        // clipboard text was written, then the entire line containing the
12439                        // selection was copied. If this selection is also currently empty,
12440                        // then paste the line before the current line of the buffer.
12441                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12442                            let column = selection.start.to_point(&snapshot).column as usize;
12443                            let line_start = selection.start - column;
12444                            line_start..line_start
12445                        } else {
12446                            selection.range()
12447                        };
12448
12449                        edits.push((range, to_insert));
12450                        original_indent_columns.push(original_indent_column);
12451                    }
12452                    drop(snapshot);
12453
12454                    buffer.edit(
12455                        edits,
12456                        if auto_indent_on_paste {
12457                            Some(AutoindentMode::Block {
12458                                original_indent_columns,
12459                            })
12460                        } else {
12461                            None
12462                        },
12463                        cx,
12464                    );
12465                });
12466
12467                let selections = this.selections.all::<usize>(cx);
12468                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12469            } else {
12470                this.insert(&clipboard_text, window, cx);
12471            }
12472
12473            let trigger_in_words =
12474                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12475
12476            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12477        });
12478    }
12479
12480    pub fn diff_clipboard_with_selection(
12481        &mut self,
12482        _: &DiffClipboardWithSelection,
12483        window: &mut Window,
12484        cx: &mut Context<Self>,
12485    ) {
12486        let selections = self.selections.all::<usize>(cx);
12487
12488        if selections.is_empty() {
12489            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12490            return;
12491        };
12492
12493        let clipboard_text = match cx.read_from_clipboard() {
12494            Some(item) => match item.entries().first() {
12495                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12496                _ => None,
12497            },
12498            None => None,
12499        };
12500
12501        let Some(clipboard_text) = clipboard_text else {
12502            log::warn!("Clipboard doesn't contain text.");
12503            return;
12504        };
12505
12506        window.dispatch_action(
12507            Box::new(DiffClipboardWithSelectionData {
12508                clipboard_text,
12509                editor: cx.entity(),
12510            }),
12511            cx,
12512        );
12513    }
12514
12515    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12516        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12517        if let Some(item) = cx.read_from_clipboard() {
12518            let entries = item.entries();
12519
12520            match entries.first() {
12521                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12522                // of all the pasted entries.
12523                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12524                    .do_paste(
12525                        clipboard_string.text(),
12526                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12527                        true,
12528                        window,
12529                        cx,
12530                    ),
12531                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12532            }
12533        }
12534    }
12535
12536    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12537        if self.read_only(cx) {
12538            return;
12539        }
12540
12541        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12542
12543        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12544            if let Some((selections, _)) =
12545                self.selection_history.transaction(transaction_id).cloned()
12546            {
12547                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12548                    s.select_anchors(selections.to_vec());
12549                });
12550            } else {
12551                log::error!(
12552                    "No entry in selection_history found for undo. \
12553                     This may correspond to a bug where undo does not update the selection. \
12554                     If this is occurring, please add details to \
12555                     https://github.com/zed-industries/zed/issues/22692"
12556                );
12557            }
12558            self.request_autoscroll(Autoscroll::fit(), cx);
12559            self.unmark_text(window, cx);
12560            self.refresh_edit_prediction(true, false, window, cx);
12561            cx.emit(EditorEvent::Edited { transaction_id });
12562            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12563        }
12564    }
12565
12566    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12567        if self.read_only(cx) {
12568            return;
12569        }
12570
12571        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12572
12573        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12574            if let Some((_, Some(selections))) =
12575                self.selection_history.transaction(transaction_id).cloned()
12576            {
12577                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12578                    s.select_anchors(selections.to_vec());
12579                });
12580            } else {
12581                log::error!(
12582                    "No entry in selection_history found for redo. \
12583                     This may correspond to a bug where undo does not update the selection. \
12584                     If this is occurring, please add details to \
12585                     https://github.com/zed-industries/zed/issues/22692"
12586                );
12587            }
12588            self.request_autoscroll(Autoscroll::fit(), cx);
12589            self.unmark_text(window, cx);
12590            self.refresh_edit_prediction(true, false, window, cx);
12591            cx.emit(EditorEvent::Edited { transaction_id });
12592        }
12593    }
12594
12595    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12596        self.buffer
12597            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12598    }
12599
12600    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12601        self.buffer
12602            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12603    }
12604
12605    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12606        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12607        self.change_selections(Default::default(), window, cx, |s| {
12608            s.move_with(|map, selection| {
12609                let cursor = if selection.is_empty() {
12610                    movement::left(map, selection.start)
12611                } else {
12612                    selection.start
12613                };
12614                selection.collapse_to(cursor, SelectionGoal::None);
12615            });
12616        })
12617    }
12618
12619    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12620        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12621        self.change_selections(Default::default(), window, cx, |s| {
12622            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12623        })
12624    }
12625
12626    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12627        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12628        self.change_selections(Default::default(), window, cx, |s| {
12629            s.move_with(|map, selection| {
12630                let cursor = if selection.is_empty() {
12631                    movement::right(map, selection.end)
12632                } else {
12633                    selection.end
12634                };
12635                selection.collapse_to(cursor, SelectionGoal::None)
12636            });
12637        })
12638    }
12639
12640    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12641        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12642        self.change_selections(Default::default(), window, cx, |s| {
12643            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12644        })
12645    }
12646
12647    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12648        if self.take_rename(true, window, cx).is_some() {
12649            return;
12650        }
12651
12652        if self.mode.is_single_line() {
12653            cx.propagate();
12654            return;
12655        }
12656
12657        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12658
12659        let text_layout_details = &self.text_layout_details(window);
12660        let selection_count = self.selections.count();
12661        let first_selection = self.selections.first_anchor();
12662
12663        self.change_selections(Default::default(), window, cx, |s| {
12664            s.move_with(|map, selection| {
12665                if !selection.is_empty() {
12666                    selection.goal = SelectionGoal::None;
12667                }
12668                let (cursor, goal) = movement::up(
12669                    map,
12670                    selection.start,
12671                    selection.goal,
12672                    false,
12673                    text_layout_details,
12674                );
12675                selection.collapse_to(cursor, goal);
12676            });
12677        });
12678
12679        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12680        {
12681            cx.propagate();
12682        }
12683    }
12684
12685    pub fn move_up_by_lines(
12686        &mut self,
12687        action: &MoveUpByLines,
12688        window: &mut Window,
12689        cx: &mut Context<Self>,
12690    ) {
12691        if self.take_rename(true, window, cx).is_some() {
12692            return;
12693        }
12694
12695        if self.mode.is_single_line() {
12696            cx.propagate();
12697            return;
12698        }
12699
12700        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12701
12702        let text_layout_details = &self.text_layout_details(window);
12703
12704        self.change_selections(Default::default(), window, cx, |s| {
12705            s.move_with(|map, selection| {
12706                if !selection.is_empty() {
12707                    selection.goal = SelectionGoal::None;
12708                }
12709                let (cursor, goal) = movement::up_by_rows(
12710                    map,
12711                    selection.start,
12712                    action.lines,
12713                    selection.goal,
12714                    false,
12715                    text_layout_details,
12716                );
12717                selection.collapse_to(cursor, goal);
12718            });
12719        })
12720    }
12721
12722    pub fn move_down_by_lines(
12723        &mut self,
12724        action: &MoveDownByLines,
12725        window: &mut Window,
12726        cx: &mut Context<Self>,
12727    ) {
12728        if self.take_rename(true, window, cx).is_some() {
12729            return;
12730        }
12731
12732        if self.mode.is_single_line() {
12733            cx.propagate();
12734            return;
12735        }
12736
12737        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12738
12739        let text_layout_details = &self.text_layout_details(window);
12740
12741        self.change_selections(Default::default(), window, cx, |s| {
12742            s.move_with(|map, selection| {
12743                if !selection.is_empty() {
12744                    selection.goal = SelectionGoal::None;
12745                }
12746                let (cursor, goal) = movement::down_by_rows(
12747                    map,
12748                    selection.start,
12749                    action.lines,
12750                    selection.goal,
12751                    false,
12752                    text_layout_details,
12753                );
12754                selection.collapse_to(cursor, goal);
12755            });
12756        })
12757    }
12758
12759    pub fn select_down_by_lines(
12760        &mut self,
12761        action: &SelectDownByLines,
12762        window: &mut Window,
12763        cx: &mut Context<Self>,
12764    ) {
12765        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12766        let text_layout_details = &self.text_layout_details(window);
12767        self.change_selections(Default::default(), window, cx, |s| {
12768            s.move_heads_with(|map, head, goal| {
12769                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12770            })
12771        })
12772    }
12773
12774    pub fn select_up_by_lines(
12775        &mut self,
12776        action: &SelectUpByLines,
12777        window: &mut Window,
12778        cx: &mut Context<Self>,
12779    ) {
12780        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12781        let text_layout_details = &self.text_layout_details(window);
12782        self.change_selections(Default::default(), window, cx, |s| {
12783            s.move_heads_with(|map, head, goal| {
12784                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12785            })
12786        })
12787    }
12788
12789    pub fn select_page_up(
12790        &mut self,
12791        _: &SelectPageUp,
12792        window: &mut Window,
12793        cx: &mut Context<Self>,
12794    ) {
12795        let Some(row_count) = self.visible_row_count() else {
12796            return;
12797        };
12798
12799        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12800
12801        let text_layout_details = &self.text_layout_details(window);
12802
12803        self.change_selections(Default::default(), window, cx, |s| {
12804            s.move_heads_with(|map, head, goal| {
12805                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12806            })
12807        })
12808    }
12809
12810    pub fn move_page_up(
12811        &mut self,
12812        action: &MovePageUp,
12813        window: &mut Window,
12814        cx: &mut Context<Self>,
12815    ) {
12816        if self.take_rename(true, window, cx).is_some() {
12817            return;
12818        }
12819
12820        if self
12821            .context_menu
12822            .borrow_mut()
12823            .as_mut()
12824            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12825            .unwrap_or(false)
12826        {
12827            return;
12828        }
12829
12830        if matches!(self.mode, EditorMode::SingleLine) {
12831            cx.propagate();
12832            return;
12833        }
12834
12835        let Some(row_count) = self.visible_row_count() else {
12836            return;
12837        };
12838
12839        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12840
12841        let effects = if action.center_cursor {
12842            SelectionEffects::scroll(Autoscroll::center())
12843        } else {
12844            SelectionEffects::default()
12845        };
12846
12847        let text_layout_details = &self.text_layout_details(window);
12848
12849        self.change_selections(effects, window, cx, |s| {
12850            s.move_with(|map, selection| {
12851                if !selection.is_empty() {
12852                    selection.goal = SelectionGoal::None;
12853                }
12854                let (cursor, goal) = movement::up_by_rows(
12855                    map,
12856                    selection.end,
12857                    row_count,
12858                    selection.goal,
12859                    false,
12860                    text_layout_details,
12861                );
12862                selection.collapse_to(cursor, goal);
12863            });
12864        });
12865    }
12866
12867    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12868        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12869        let text_layout_details = &self.text_layout_details(window);
12870        self.change_selections(Default::default(), window, cx, |s| {
12871            s.move_heads_with(|map, head, goal| {
12872                movement::up(map, head, goal, false, text_layout_details)
12873            })
12874        })
12875    }
12876
12877    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12878        self.take_rename(true, window, cx);
12879
12880        if self.mode.is_single_line() {
12881            cx.propagate();
12882            return;
12883        }
12884
12885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12886
12887        let text_layout_details = &self.text_layout_details(window);
12888        let selection_count = self.selections.count();
12889        let first_selection = self.selections.first_anchor();
12890
12891        self.change_selections(Default::default(), window, cx, |s| {
12892            s.move_with(|map, selection| {
12893                if !selection.is_empty() {
12894                    selection.goal = SelectionGoal::None;
12895                }
12896                let (cursor, goal) = movement::down(
12897                    map,
12898                    selection.end,
12899                    selection.goal,
12900                    false,
12901                    text_layout_details,
12902                );
12903                selection.collapse_to(cursor, goal);
12904            });
12905        });
12906
12907        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12908        {
12909            cx.propagate();
12910        }
12911    }
12912
12913    pub fn select_page_down(
12914        &mut self,
12915        _: &SelectPageDown,
12916        window: &mut Window,
12917        cx: &mut Context<Self>,
12918    ) {
12919        let Some(row_count) = self.visible_row_count() else {
12920            return;
12921        };
12922
12923        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12924
12925        let text_layout_details = &self.text_layout_details(window);
12926
12927        self.change_selections(Default::default(), window, cx, |s| {
12928            s.move_heads_with(|map, head, goal| {
12929                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12930            })
12931        })
12932    }
12933
12934    pub fn move_page_down(
12935        &mut self,
12936        action: &MovePageDown,
12937        window: &mut Window,
12938        cx: &mut Context<Self>,
12939    ) {
12940        if self.take_rename(true, window, cx).is_some() {
12941            return;
12942        }
12943
12944        if self
12945            .context_menu
12946            .borrow_mut()
12947            .as_mut()
12948            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12949            .unwrap_or(false)
12950        {
12951            return;
12952        }
12953
12954        if matches!(self.mode, EditorMode::SingleLine) {
12955            cx.propagate();
12956            return;
12957        }
12958
12959        let Some(row_count) = self.visible_row_count() else {
12960            return;
12961        };
12962
12963        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12964
12965        let effects = if action.center_cursor {
12966            SelectionEffects::scroll(Autoscroll::center())
12967        } else {
12968            SelectionEffects::default()
12969        };
12970
12971        let text_layout_details = &self.text_layout_details(window);
12972        self.change_selections(effects, window, cx, |s| {
12973            s.move_with(|map, selection| {
12974                if !selection.is_empty() {
12975                    selection.goal = SelectionGoal::None;
12976                }
12977                let (cursor, goal) = movement::down_by_rows(
12978                    map,
12979                    selection.end,
12980                    row_count,
12981                    selection.goal,
12982                    false,
12983                    text_layout_details,
12984                );
12985                selection.collapse_to(cursor, goal);
12986            });
12987        });
12988    }
12989
12990    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12991        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12992        let text_layout_details = &self.text_layout_details(window);
12993        self.change_selections(Default::default(), window, cx, |s| {
12994            s.move_heads_with(|map, head, goal| {
12995                movement::down(map, head, goal, false, text_layout_details)
12996            })
12997        });
12998    }
12999
13000    pub fn context_menu_first(
13001        &mut self,
13002        _: &ContextMenuFirst,
13003        window: &mut Window,
13004        cx: &mut Context<Self>,
13005    ) {
13006        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13007            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13008        }
13009    }
13010
13011    pub fn context_menu_prev(
13012        &mut self,
13013        _: &ContextMenuPrevious,
13014        window: &mut Window,
13015        cx: &mut Context<Self>,
13016    ) {
13017        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13018            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13019        }
13020    }
13021
13022    pub fn context_menu_next(
13023        &mut self,
13024        _: &ContextMenuNext,
13025        window: &mut Window,
13026        cx: &mut Context<Self>,
13027    ) {
13028        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13029            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13030        }
13031    }
13032
13033    pub fn context_menu_last(
13034        &mut self,
13035        _: &ContextMenuLast,
13036        window: &mut Window,
13037        cx: &mut Context<Self>,
13038    ) {
13039        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13040            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13041        }
13042    }
13043
13044    pub fn signature_help_prev(
13045        &mut self,
13046        _: &SignatureHelpPrevious,
13047        _: &mut Window,
13048        cx: &mut Context<Self>,
13049    ) {
13050        if let Some(popover) = self.signature_help_state.popover_mut() {
13051            if popover.current_signature == 0 {
13052                popover.current_signature = popover.signatures.len() - 1;
13053            } else {
13054                popover.current_signature -= 1;
13055            }
13056            cx.notify();
13057        }
13058    }
13059
13060    pub fn signature_help_next(
13061        &mut self,
13062        _: &SignatureHelpNext,
13063        _: &mut Window,
13064        cx: &mut Context<Self>,
13065    ) {
13066        if let Some(popover) = self.signature_help_state.popover_mut() {
13067            if popover.current_signature + 1 == popover.signatures.len() {
13068                popover.current_signature = 0;
13069            } else {
13070                popover.current_signature += 1;
13071            }
13072            cx.notify();
13073        }
13074    }
13075
13076    pub fn move_to_previous_word_start(
13077        &mut self,
13078        _: &MoveToPreviousWordStart,
13079        window: &mut Window,
13080        cx: &mut Context<Self>,
13081    ) {
13082        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13083        self.change_selections(Default::default(), window, cx, |s| {
13084            s.move_cursors_with(|map, head, _| {
13085                (
13086                    movement::previous_word_start(map, head),
13087                    SelectionGoal::None,
13088                )
13089            });
13090        })
13091    }
13092
13093    pub fn move_to_previous_subword_start(
13094        &mut self,
13095        _: &MoveToPreviousSubwordStart,
13096        window: &mut Window,
13097        cx: &mut Context<Self>,
13098    ) {
13099        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13100        self.change_selections(Default::default(), window, cx, |s| {
13101            s.move_cursors_with(|map, head, _| {
13102                (
13103                    movement::previous_subword_start(map, head),
13104                    SelectionGoal::None,
13105                )
13106            });
13107        })
13108    }
13109
13110    pub fn select_to_previous_word_start(
13111        &mut self,
13112        _: &SelectToPreviousWordStart,
13113        window: &mut Window,
13114        cx: &mut Context<Self>,
13115    ) {
13116        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13117        self.change_selections(Default::default(), window, cx, |s| {
13118            s.move_heads_with(|map, head, _| {
13119                (
13120                    movement::previous_word_start(map, head),
13121                    SelectionGoal::None,
13122                )
13123            });
13124        })
13125    }
13126
13127    pub fn select_to_previous_subword_start(
13128        &mut self,
13129        _: &SelectToPreviousSubwordStart,
13130        window: &mut Window,
13131        cx: &mut Context<Self>,
13132    ) {
13133        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13134        self.change_selections(Default::default(), window, cx, |s| {
13135            s.move_heads_with(|map, head, _| {
13136                (
13137                    movement::previous_subword_start(map, head),
13138                    SelectionGoal::None,
13139                )
13140            });
13141        })
13142    }
13143
13144    pub fn delete_to_previous_word_start(
13145        &mut self,
13146        action: &DeleteToPreviousWordStart,
13147        window: &mut Window,
13148        cx: &mut Context<Self>,
13149    ) {
13150        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13151        self.transact(window, cx, |this, window, cx| {
13152            this.select_autoclose_pair(window, cx);
13153            this.change_selections(Default::default(), window, cx, |s| {
13154                s.move_with(|map, selection| {
13155                    if selection.is_empty() {
13156                        let mut cursor = if action.ignore_newlines {
13157                            movement::previous_word_start(map, selection.head())
13158                        } else {
13159                            movement::previous_word_start_or_newline(map, selection.head())
13160                        };
13161                        cursor = movement::adjust_greedy_deletion(
13162                            map,
13163                            selection.head(),
13164                            cursor,
13165                            action.ignore_brackets,
13166                        );
13167                        selection.set_head(cursor, SelectionGoal::None);
13168                    }
13169                });
13170            });
13171            this.insert("", window, cx);
13172        });
13173    }
13174
13175    pub fn delete_to_previous_subword_start(
13176        &mut self,
13177        _: &DeleteToPreviousSubwordStart,
13178        window: &mut Window,
13179        cx: &mut Context<Self>,
13180    ) {
13181        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13182        self.transact(window, cx, |this, window, cx| {
13183            this.select_autoclose_pair(window, cx);
13184            this.change_selections(Default::default(), window, cx, |s| {
13185                s.move_with(|map, selection| {
13186                    if selection.is_empty() {
13187                        let mut cursor = movement::previous_subword_start(map, selection.head());
13188                        cursor =
13189                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13190                        selection.set_head(cursor, SelectionGoal::None);
13191                    }
13192                });
13193            });
13194            this.insert("", window, cx);
13195        });
13196    }
13197
13198    pub fn move_to_next_word_end(
13199        &mut self,
13200        _: &MoveToNextWordEnd,
13201        window: &mut Window,
13202        cx: &mut Context<Self>,
13203    ) {
13204        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13205        self.change_selections(Default::default(), window, cx, |s| {
13206            s.move_cursors_with(|map, head, _| {
13207                (movement::next_word_end(map, head), SelectionGoal::None)
13208            });
13209        })
13210    }
13211
13212    pub fn move_to_next_subword_end(
13213        &mut self,
13214        _: &MoveToNextSubwordEnd,
13215        window: &mut Window,
13216        cx: &mut Context<Self>,
13217    ) {
13218        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13219        self.change_selections(Default::default(), window, cx, |s| {
13220            s.move_cursors_with(|map, head, _| {
13221                (movement::next_subword_end(map, head), SelectionGoal::None)
13222            });
13223        })
13224    }
13225
13226    pub fn select_to_next_word_end(
13227        &mut self,
13228        _: &SelectToNextWordEnd,
13229        window: &mut Window,
13230        cx: &mut Context<Self>,
13231    ) {
13232        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13233        self.change_selections(Default::default(), window, cx, |s| {
13234            s.move_heads_with(|map, head, _| {
13235                (movement::next_word_end(map, head), SelectionGoal::None)
13236            });
13237        })
13238    }
13239
13240    pub fn select_to_next_subword_end(
13241        &mut self,
13242        _: &SelectToNextSubwordEnd,
13243        window: &mut Window,
13244        cx: &mut Context<Self>,
13245    ) {
13246        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13247        self.change_selections(Default::default(), window, cx, |s| {
13248            s.move_heads_with(|map, head, _| {
13249                (movement::next_subword_end(map, head), SelectionGoal::None)
13250            });
13251        })
13252    }
13253
13254    pub fn delete_to_next_word_end(
13255        &mut self,
13256        action: &DeleteToNextWordEnd,
13257        window: &mut Window,
13258        cx: &mut Context<Self>,
13259    ) {
13260        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13261        self.transact(window, cx, |this, window, cx| {
13262            this.change_selections(Default::default(), window, cx, |s| {
13263                s.move_with(|map, selection| {
13264                    if selection.is_empty() {
13265                        let mut cursor = if action.ignore_newlines {
13266                            movement::next_word_end(map, selection.head())
13267                        } else {
13268                            movement::next_word_end_or_newline(map, selection.head())
13269                        };
13270                        cursor = movement::adjust_greedy_deletion(
13271                            map,
13272                            selection.head(),
13273                            cursor,
13274                            action.ignore_brackets,
13275                        );
13276                        selection.set_head(cursor, SelectionGoal::None);
13277                    }
13278                });
13279            });
13280            this.insert("", window, cx);
13281        });
13282    }
13283
13284    pub fn delete_to_next_subword_end(
13285        &mut self,
13286        _: &DeleteToNextSubwordEnd,
13287        window: &mut Window,
13288        cx: &mut Context<Self>,
13289    ) {
13290        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13291        self.transact(window, cx, |this, window, cx| {
13292            this.change_selections(Default::default(), window, cx, |s| {
13293                s.move_with(|map, selection| {
13294                    if selection.is_empty() {
13295                        let mut cursor = movement::next_subword_end(map, selection.head());
13296                        cursor =
13297                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13298                        selection.set_head(cursor, SelectionGoal::None);
13299                    }
13300                });
13301            });
13302            this.insert("", window, cx);
13303        });
13304    }
13305
13306    pub fn move_to_beginning_of_line(
13307        &mut self,
13308        action: &MoveToBeginningOfLine,
13309        window: &mut Window,
13310        cx: &mut Context<Self>,
13311    ) {
13312        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13313        self.change_selections(Default::default(), window, cx, |s| {
13314            s.move_cursors_with(|map, head, _| {
13315                (
13316                    movement::indented_line_beginning(
13317                        map,
13318                        head,
13319                        action.stop_at_soft_wraps,
13320                        action.stop_at_indent,
13321                    ),
13322                    SelectionGoal::None,
13323                )
13324            });
13325        })
13326    }
13327
13328    pub fn select_to_beginning_of_line(
13329        &mut self,
13330        action: &SelectToBeginningOfLine,
13331        window: &mut Window,
13332        cx: &mut Context<Self>,
13333    ) {
13334        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13335        self.change_selections(Default::default(), window, cx, |s| {
13336            s.move_heads_with(|map, head, _| {
13337                (
13338                    movement::indented_line_beginning(
13339                        map,
13340                        head,
13341                        action.stop_at_soft_wraps,
13342                        action.stop_at_indent,
13343                    ),
13344                    SelectionGoal::None,
13345                )
13346            });
13347        });
13348    }
13349
13350    pub fn delete_to_beginning_of_line(
13351        &mut self,
13352        action: &DeleteToBeginningOfLine,
13353        window: &mut Window,
13354        cx: &mut Context<Self>,
13355    ) {
13356        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13357        self.transact(window, cx, |this, window, cx| {
13358            this.change_selections(Default::default(), window, cx, |s| {
13359                s.move_with(|_, selection| {
13360                    selection.reversed = true;
13361                });
13362            });
13363
13364            this.select_to_beginning_of_line(
13365                &SelectToBeginningOfLine {
13366                    stop_at_soft_wraps: false,
13367                    stop_at_indent: action.stop_at_indent,
13368                },
13369                window,
13370                cx,
13371            );
13372            this.backspace(&Backspace, window, cx);
13373        });
13374    }
13375
13376    pub fn move_to_end_of_line(
13377        &mut self,
13378        action: &MoveToEndOfLine,
13379        window: &mut Window,
13380        cx: &mut Context<Self>,
13381    ) {
13382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13383        self.change_selections(Default::default(), window, cx, |s| {
13384            s.move_cursors_with(|map, head, _| {
13385                (
13386                    movement::line_end(map, head, action.stop_at_soft_wraps),
13387                    SelectionGoal::None,
13388                )
13389            });
13390        })
13391    }
13392
13393    pub fn select_to_end_of_line(
13394        &mut self,
13395        action: &SelectToEndOfLine,
13396        window: &mut Window,
13397        cx: &mut Context<Self>,
13398    ) {
13399        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13400        self.change_selections(Default::default(), window, cx, |s| {
13401            s.move_heads_with(|map, head, _| {
13402                (
13403                    movement::line_end(map, head, action.stop_at_soft_wraps),
13404                    SelectionGoal::None,
13405                )
13406            });
13407        })
13408    }
13409
13410    pub fn delete_to_end_of_line(
13411        &mut self,
13412        _: &DeleteToEndOfLine,
13413        window: &mut Window,
13414        cx: &mut Context<Self>,
13415    ) {
13416        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13417        self.transact(window, cx, |this, window, cx| {
13418            this.select_to_end_of_line(
13419                &SelectToEndOfLine {
13420                    stop_at_soft_wraps: false,
13421                },
13422                window,
13423                cx,
13424            );
13425            this.delete(&Delete, window, cx);
13426        });
13427    }
13428
13429    pub fn cut_to_end_of_line(
13430        &mut self,
13431        _: &CutToEndOfLine,
13432        window: &mut Window,
13433        cx: &mut Context<Self>,
13434    ) {
13435        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13436        self.transact(window, cx, |this, window, cx| {
13437            this.select_to_end_of_line(
13438                &SelectToEndOfLine {
13439                    stop_at_soft_wraps: false,
13440                },
13441                window,
13442                cx,
13443            );
13444            this.cut(&Cut, window, cx);
13445        });
13446    }
13447
13448    pub fn move_to_start_of_paragraph(
13449        &mut self,
13450        _: &MoveToStartOfParagraph,
13451        window: &mut Window,
13452        cx: &mut Context<Self>,
13453    ) {
13454        if matches!(self.mode, EditorMode::SingleLine) {
13455            cx.propagate();
13456            return;
13457        }
13458        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13459        self.change_selections(Default::default(), window, cx, |s| {
13460            s.move_with(|map, selection| {
13461                selection.collapse_to(
13462                    movement::start_of_paragraph(map, selection.head(), 1),
13463                    SelectionGoal::None,
13464                )
13465            });
13466        })
13467    }
13468
13469    pub fn move_to_end_of_paragraph(
13470        &mut self,
13471        _: &MoveToEndOfParagraph,
13472        window: &mut Window,
13473        cx: &mut Context<Self>,
13474    ) {
13475        if matches!(self.mode, EditorMode::SingleLine) {
13476            cx.propagate();
13477            return;
13478        }
13479        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13480        self.change_selections(Default::default(), window, cx, |s| {
13481            s.move_with(|map, selection| {
13482                selection.collapse_to(
13483                    movement::end_of_paragraph(map, selection.head(), 1),
13484                    SelectionGoal::None,
13485                )
13486            });
13487        })
13488    }
13489
13490    pub fn select_to_start_of_paragraph(
13491        &mut self,
13492        _: &SelectToStartOfParagraph,
13493        window: &mut Window,
13494        cx: &mut Context<Self>,
13495    ) {
13496        if matches!(self.mode, EditorMode::SingleLine) {
13497            cx.propagate();
13498            return;
13499        }
13500        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13501        self.change_selections(Default::default(), window, cx, |s| {
13502            s.move_heads_with(|map, head, _| {
13503                (
13504                    movement::start_of_paragraph(map, head, 1),
13505                    SelectionGoal::None,
13506                )
13507            });
13508        })
13509    }
13510
13511    pub fn select_to_end_of_paragraph(
13512        &mut self,
13513        _: &SelectToEndOfParagraph,
13514        window: &mut Window,
13515        cx: &mut Context<Self>,
13516    ) {
13517        if matches!(self.mode, EditorMode::SingleLine) {
13518            cx.propagate();
13519            return;
13520        }
13521        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13522        self.change_selections(Default::default(), window, cx, |s| {
13523            s.move_heads_with(|map, head, _| {
13524                (
13525                    movement::end_of_paragraph(map, head, 1),
13526                    SelectionGoal::None,
13527                )
13528            });
13529        })
13530    }
13531
13532    pub fn move_to_start_of_excerpt(
13533        &mut self,
13534        _: &MoveToStartOfExcerpt,
13535        window: &mut Window,
13536        cx: &mut Context<Self>,
13537    ) {
13538        if matches!(self.mode, EditorMode::SingleLine) {
13539            cx.propagate();
13540            return;
13541        }
13542        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13543        self.change_selections(Default::default(), window, cx, |s| {
13544            s.move_with(|map, selection| {
13545                selection.collapse_to(
13546                    movement::start_of_excerpt(
13547                        map,
13548                        selection.head(),
13549                        workspace::searchable::Direction::Prev,
13550                    ),
13551                    SelectionGoal::None,
13552                )
13553            });
13554        })
13555    }
13556
13557    pub fn move_to_start_of_next_excerpt(
13558        &mut self,
13559        _: &MoveToStartOfNextExcerpt,
13560        window: &mut Window,
13561        cx: &mut Context<Self>,
13562    ) {
13563        if matches!(self.mode, EditorMode::SingleLine) {
13564            cx.propagate();
13565            return;
13566        }
13567
13568        self.change_selections(Default::default(), window, cx, |s| {
13569            s.move_with(|map, selection| {
13570                selection.collapse_to(
13571                    movement::start_of_excerpt(
13572                        map,
13573                        selection.head(),
13574                        workspace::searchable::Direction::Next,
13575                    ),
13576                    SelectionGoal::None,
13577                )
13578            });
13579        })
13580    }
13581
13582    pub fn move_to_end_of_excerpt(
13583        &mut self,
13584        _: &MoveToEndOfExcerpt,
13585        window: &mut Window,
13586        cx: &mut Context<Self>,
13587    ) {
13588        if matches!(self.mode, EditorMode::SingleLine) {
13589            cx.propagate();
13590            return;
13591        }
13592        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13593        self.change_selections(Default::default(), window, cx, |s| {
13594            s.move_with(|map, selection| {
13595                selection.collapse_to(
13596                    movement::end_of_excerpt(
13597                        map,
13598                        selection.head(),
13599                        workspace::searchable::Direction::Next,
13600                    ),
13601                    SelectionGoal::None,
13602                )
13603            });
13604        })
13605    }
13606
13607    pub fn move_to_end_of_previous_excerpt(
13608        &mut self,
13609        _: &MoveToEndOfPreviousExcerpt,
13610        window: &mut Window,
13611        cx: &mut Context<Self>,
13612    ) {
13613        if matches!(self.mode, EditorMode::SingleLine) {
13614            cx.propagate();
13615            return;
13616        }
13617        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13618        self.change_selections(Default::default(), window, cx, |s| {
13619            s.move_with(|map, selection| {
13620                selection.collapse_to(
13621                    movement::end_of_excerpt(
13622                        map,
13623                        selection.head(),
13624                        workspace::searchable::Direction::Prev,
13625                    ),
13626                    SelectionGoal::None,
13627                )
13628            });
13629        })
13630    }
13631
13632    pub fn select_to_start_of_excerpt(
13633        &mut self,
13634        _: &SelectToStartOfExcerpt,
13635        window: &mut Window,
13636        cx: &mut Context<Self>,
13637    ) {
13638        if matches!(self.mode, EditorMode::SingleLine) {
13639            cx.propagate();
13640            return;
13641        }
13642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13643        self.change_selections(Default::default(), window, cx, |s| {
13644            s.move_heads_with(|map, head, _| {
13645                (
13646                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13647                    SelectionGoal::None,
13648                )
13649            });
13650        })
13651    }
13652
13653    pub fn select_to_start_of_next_excerpt(
13654        &mut self,
13655        _: &SelectToStartOfNextExcerpt,
13656        window: &mut Window,
13657        cx: &mut Context<Self>,
13658    ) {
13659        if matches!(self.mode, EditorMode::SingleLine) {
13660            cx.propagate();
13661            return;
13662        }
13663        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13664        self.change_selections(Default::default(), window, cx, |s| {
13665            s.move_heads_with(|map, head, _| {
13666                (
13667                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13668                    SelectionGoal::None,
13669                )
13670            });
13671        })
13672    }
13673
13674    pub fn select_to_end_of_excerpt(
13675        &mut self,
13676        _: &SelectToEndOfExcerpt,
13677        window: &mut Window,
13678        cx: &mut Context<Self>,
13679    ) {
13680        if matches!(self.mode, EditorMode::SingleLine) {
13681            cx.propagate();
13682            return;
13683        }
13684        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13685        self.change_selections(Default::default(), window, cx, |s| {
13686            s.move_heads_with(|map, head, _| {
13687                (
13688                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13689                    SelectionGoal::None,
13690                )
13691            });
13692        })
13693    }
13694
13695    pub fn select_to_end_of_previous_excerpt(
13696        &mut self,
13697        _: &SelectToEndOfPreviousExcerpt,
13698        window: &mut Window,
13699        cx: &mut Context<Self>,
13700    ) {
13701        if matches!(self.mode, EditorMode::SingleLine) {
13702            cx.propagate();
13703            return;
13704        }
13705        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13706        self.change_selections(Default::default(), window, cx, |s| {
13707            s.move_heads_with(|map, head, _| {
13708                (
13709                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13710                    SelectionGoal::None,
13711                )
13712            });
13713        })
13714    }
13715
13716    pub fn move_to_beginning(
13717        &mut self,
13718        _: &MoveToBeginning,
13719        window: &mut Window,
13720        cx: &mut Context<Self>,
13721    ) {
13722        if matches!(self.mode, EditorMode::SingleLine) {
13723            cx.propagate();
13724            return;
13725        }
13726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13727        self.change_selections(Default::default(), window, cx, |s| {
13728            s.select_ranges(vec![0..0]);
13729        });
13730    }
13731
13732    pub fn select_to_beginning(
13733        &mut self,
13734        _: &SelectToBeginning,
13735        window: &mut Window,
13736        cx: &mut Context<Self>,
13737    ) {
13738        let mut selection = self.selections.last::<Point>(cx);
13739        selection.set_head(Point::zero(), SelectionGoal::None);
13740        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13741        self.change_selections(Default::default(), window, cx, |s| {
13742            s.select(vec![selection]);
13743        });
13744    }
13745
13746    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13747        if matches!(self.mode, EditorMode::SingleLine) {
13748            cx.propagate();
13749            return;
13750        }
13751        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13752        let cursor = self.buffer.read(cx).read(cx).len();
13753        self.change_selections(Default::default(), window, cx, |s| {
13754            s.select_ranges(vec![cursor..cursor])
13755        });
13756    }
13757
13758    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13759        self.nav_history = nav_history;
13760    }
13761
13762    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13763        self.nav_history.as_ref()
13764    }
13765
13766    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13767        self.push_to_nav_history(
13768            self.selections.newest_anchor().head(),
13769            None,
13770            false,
13771            true,
13772            cx,
13773        );
13774    }
13775
13776    fn push_to_nav_history(
13777        &mut self,
13778        cursor_anchor: Anchor,
13779        new_position: Option<Point>,
13780        is_deactivate: bool,
13781        always: bool,
13782        cx: &mut Context<Self>,
13783    ) {
13784        if let Some(nav_history) = self.nav_history.as_mut() {
13785            let buffer = self.buffer.read(cx).read(cx);
13786            let cursor_position = cursor_anchor.to_point(&buffer);
13787            let scroll_state = self.scroll_manager.anchor();
13788            let scroll_top_row = scroll_state.top_row(&buffer);
13789            drop(buffer);
13790
13791            if let Some(new_position) = new_position {
13792                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13793                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13794                    return;
13795                }
13796            }
13797
13798            nav_history.push(
13799                Some(NavigationData {
13800                    cursor_anchor,
13801                    cursor_position,
13802                    scroll_anchor: scroll_state,
13803                    scroll_top_row,
13804                }),
13805                cx,
13806            );
13807            cx.emit(EditorEvent::PushedToNavHistory {
13808                anchor: cursor_anchor,
13809                is_deactivate,
13810            })
13811        }
13812    }
13813
13814    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13815        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13816        let buffer = self.buffer.read(cx).snapshot(cx);
13817        let mut selection = self.selections.first::<usize>(cx);
13818        selection.set_head(buffer.len(), SelectionGoal::None);
13819        self.change_selections(Default::default(), window, cx, |s| {
13820            s.select(vec![selection]);
13821        });
13822    }
13823
13824    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13826        let end = self.buffer.read(cx).read(cx).len();
13827        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13828            s.select_ranges(vec![0..end]);
13829        });
13830    }
13831
13832    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13833        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13834        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13835        let mut selections = self.selections.all::<Point>(cx);
13836        let max_point = display_map.buffer_snapshot.max_point();
13837        for selection in &mut selections {
13838            let rows = selection.spanned_rows(true, &display_map);
13839            selection.start = Point::new(rows.start.0, 0);
13840            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13841            selection.reversed = false;
13842        }
13843        self.change_selections(Default::default(), window, cx, |s| {
13844            s.select(selections);
13845        });
13846    }
13847
13848    pub fn split_selection_into_lines(
13849        &mut self,
13850        action: &SplitSelectionIntoLines,
13851        window: &mut Window,
13852        cx: &mut Context<Self>,
13853    ) {
13854        let selections = self
13855            .selections
13856            .all::<Point>(cx)
13857            .into_iter()
13858            .map(|selection| selection.start..selection.end)
13859            .collect::<Vec<_>>();
13860        self.unfold_ranges(&selections, true, true, cx);
13861
13862        let mut new_selection_ranges = Vec::new();
13863        {
13864            let buffer = self.buffer.read(cx).read(cx);
13865            for selection in selections {
13866                for row in selection.start.row..selection.end.row {
13867                    let line_start = Point::new(row, 0);
13868                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13869
13870                    if action.keep_selections {
13871                        // Keep the selection range for each line
13872                        let selection_start = if row == selection.start.row {
13873                            selection.start
13874                        } else {
13875                            line_start
13876                        };
13877                        new_selection_ranges.push(selection_start..line_end);
13878                    } else {
13879                        // Collapse to cursor at end of line
13880                        new_selection_ranges.push(line_end..line_end);
13881                    }
13882                }
13883
13884                let is_multiline_selection = selection.start.row != selection.end.row;
13885                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13886                // so this action feels more ergonomic when paired with other selection operations
13887                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13888                if !should_skip_last {
13889                    if action.keep_selections {
13890                        if is_multiline_selection {
13891                            let line_start = Point::new(selection.end.row, 0);
13892                            new_selection_ranges.push(line_start..selection.end);
13893                        } else {
13894                            new_selection_ranges.push(selection.start..selection.end);
13895                        }
13896                    } else {
13897                        new_selection_ranges.push(selection.end..selection.end);
13898                    }
13899                }
13900            }
13901        }
13902        self.change_selections(Default::default(), window, cx, |s| {
13903            s.select_ranges(new_selection_ranges);
13904        });
13905    }
13906
13907    pub fn add_selection_above(
13908        &mut self,
13909        _: &AddSelectionAbove,
13910        window: &mut Window,
13911        cx: &mut Context<Self>,
13912    ) {
13913        self.add_selection(true, window, cx);
13914    }
13915
13916    pub fn add_selection_below(
13917        &mut self,
13918        _: &AddSelectionBelow,
13919        window: &mut Window,
13920        cx: &mut Context<Self>,
13921    ) {
13922        self.add_selection(false, window, cx);
13923    }
13924
13925    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13927
13928        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13929        let all_selections = self.selections.all::<Point>(cx);
13930        let text_layout_details = self.text_layout_details(window);
13931
13932        let (mut columnar_selections, new_selections_to_columnarize) = {
13933            if let Some(state) = self.add_selections_state.as_ref() {
13934                let columnar_selection_ids: HashSet<_> = state
13935                    .groups
13936                    .iter()
13937                    .flat_map(|group| group.stack.iter())
13938                    .copied()
13939                    .collect();
13940
13941                all_selections
13942                    .into_iter()
13943                    .partition(|s| columnar_selection_ids.contains(&s.id))
13944            } else {
13945                (Vec::new(), all_selections)
13946            }
13947        };
13948
13949        let mut state = self
13950            .add_selections_state
13951            .take()
13952            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13953
13954        for selection in new_selections_to_columnarize {
13955            let range = selection.display_range(&display_map).sorted();
13956            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13957            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13958            let positions = start_x.min(end_x)..start_x.max(end_x);
13959            let mut stack = Vec::new();
13960            for row in range.start.row().0..=range.end.row().0 {
13961                if let Some(selection) = self.selections.build_columnar_selection(
13962                    &display_map,
13963                    DisplayRow(row),
13964                    &positions,
13965                    selection.reversed,
13966                    &text_layout_details,
13967                ) {
13968                    stack.push(selection.id);
13969                    columnar_selections.push(selection);
13970                }
13971            }
13972            if !stack.is_empty() {
13973                if above {
13974                    stack.reverse();
13975                }
13976                state.groups.push(AddSelectionsGroup { above, stack });
13977            }
13978        }
13979
13980        let mut final_selections = Vec::new();
13981        let end_row = if above {
13982            DisplayRow(0)
13983        } else {
13984            display_map.max_point().row()
13985        };
13986
13987        let mut last_added_item_per_group = HashMap::default();
13988        for group in state.groups.iter_mut() {
13989            if let Some(last_id) = group.stack.last() {
13990                last_added_item_per_group.insert(*last_id, group);
13991            }
13992        }
13993
13994        for selection in columnar_selections {
13995            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13996                if above == group.above {
13997                    let range = selection.display_range(&display_map).sorted();
13998                    debug_assert_eq!(range.start.row(), range.end.row());
13999                    let mut row = range.start.row();
14000                    let positions =
14001                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14002                            px(start)..px(end)
14003                        } else {
14004                            let start_x =
14005                                display_map.x_for_display_point(range.start, &text_layout_details);
14006                            let end_x =
14007                                display_map.x_for_display_point(range.end, &text_layout_details);
14008                            start_x.min(end_x)..start_x.max(end_x)
14009                        };
14010
14011                    let mut maybe_new_selection = None;
14012                    while row != end_row {
14013                        if above {
14014                            row.0 -= 1;
14015                        } else {
14016                            row.0 += 1;
14017                        }
14018                        if let Some(new_selection) = self.selections.build_columnar_selection(
14019                            &display_map,
14020                            row,
14021                            &positions,
14022                            selection.reversed,
14023                            &text_layout_details,
14024                        ) {
14025                            maybe_new_selection = Some(new_selection);
14026                            break;
14027                        }
14028                    }
14029
14030                    if let Some(new_selection) = maybe_new_selection {
14031                        group.stack.push(new_selection.id);
14032                        if above {
14033                            final_selections.push(new_selection);
14034                            final_selections.push(selection);
14035                        } else {
14036                            final_selections.push(selection);
14037                            final_selections.push(new_selection);
14038                        }
14039                    } else {
14040                        final_selections.push(selection);
14041                    }
14042                } else {
14043                    group.stack.pop();
14044                }
14045            } else {
14046                final_selections.push(selection);
14047            }
14048        }
14049
14050        self.change_selections(Default::default(), window, cx, |s| {
14051            s.select(final_selections);
14052        });
14053
14054        let final_selection_ids: HashSet<_> = self
14055            .selections
14056            .all::<Point>(cx)
14057            .iter()
14058            .map(|s| s.id)
14059            .collect();
14060        state.groups.retain_mut(|group| {
14061            // selections might get merged above so we remove invalid items from stacks
14062            group.stack.retain(|id| final_selection_ids.contains(id));
14063
14064            // single selection in stack can be treated as initial state
14065            group.stack.len() > 1
14066        });
14067
14068        if !state.groups.is_empty() {
14069            self.add_selections_state = Some(state);
14070        }
14071    }
14072
14073    fn select_match_ranges(
14074        &mut self,
14075        range: Range<usize>,
14076        reversed: bool,
14077        replace_newest: bool,
14078        auto_scroll: Option<Autoscroll>,
14079        window: &mut Window,
14080        cx: &mut Context<Editor>,
14081    ) {
14082        self.unfold_ranges(
14083            std::slice::from_ref(&range),
14084            false,
14085            auto_scroll.is_some(),
14086            cx,
14087        );
14088        let effects = if let Some(scroll) = auto_scroll {
14089            SelectionEffects::scroll(scroll)
14090        } else {
14091            SelectionEffects::no_scroll()
14092        };
14093        self.change_selections(effects, window, cx, |s| {
14094            if replace_newest {
14095                s.delete(s.newest_anchor().id);
14096            }
14097            if reversed {
14098                s.insert_range(range.end..range.start);
14099            } else {
14100                s.insert_range(range);
14101            }
14102        });
14103    }
14104
14105    pub fn select_next_match_internal(
14106        &mut self,
14107        display_map: &DisplaySnapshot,
14108        replace_newest: bool,
14109        autoscroll: Option<Autoscroll>,
14110        window: &mut Window,
14111        cx: &mut Context<Self>,
14112    ) -> Result<()> {
14113        let buffer = &display_map.buffer_snapshot;
14114        let mut selections = self.selections.all::<usize>(cx);
14115        if let Some(mut select_next_state) = self.select_next_state.take() {
14116            let query = &select_next_state.query;
14117            if !select_next_state.done {
14118                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14119                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14120                let mut next_selected_range = None;
14121
14122                let bytes_after_last_selection =
14123                    buffer.bytes_in_range(last_selection.end..buffer.len());
14124                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14125                let query_matches = query
14126                    .stream_find_iter(bytes_after_last_selection)
14127                    .map(|result| (last_selection.end, result))
14128                    .chain(
14129                        query
14130                            .stream_find_iter(bytes_before_first_selection)
14131                            .map(|result| (0, result)),
14132                    );
14133
14134                for (start_offset, query_match) in query_matches {
14135                    let query_match = query_match.unwrap(); // can only fail due to I/O
14136                    let offset_range =
14137                        start_offset + query_match.start()..start_offset + query_match.end();
14138
14139                    if !select_next_state.wordwise
14140                        || (!buffer.is_inside_word(offset_range.start, false)
14141                            && !buffer.is_inside_word(offset_range.end, false))
14142                    {
14143                        // TODO: This is n^2, because we might check all the selections
14144                        if !selections
14145                            .iter()
14146                            .any(|selection| selection.range().overlaps(&offset_range))
14147                        {
14148                            next_selected_range = Some(offset_range);
14149                            break;
14150                        }
14151                    }
14152                }
14153
14154                if let Some(next_selected_range) = next_selected_range {
14155                    self.select_match_ranges(
14156                        next_selected_range,
14157                        last_selection.reversed,
14158                        replace_newest,
14159                        autoscroll,
14160                        window,
14161                        cx,
14162                    );
14163                } else {
14164                    select_next_state.done = true;
14165                }
14166            }
14167
14168            self.select_next_state = Some(select_next_state);
14169        } else {
14170            let mut only_carets = true;
14171            let mut same_text_selected = true;
14172            let mut selected_text = None;
14173
14174            let mut selections_iter = selections.iter().peekable();
14175            while let Some(selection) = selections_iter.next() {
14176                if selection.start != selection.end {
14177                    only_carets = false;
14178                }
14179
14180                if same_text_selected {
14181                    if selected_text.is_none() {
14182                        selected_text =
14183                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14184                    }
14185
14186                    if let Some(next_selection) = selections_iter.peek() {
14187                        if next_selection.range().len() == selection.range().len() {
14188                            let next_selected_text = buffer
14189                                .text_for_range(next_selection.range())
14190                                .collect::<String>();
14191                            if Some(next_selected_text) != selected_text {
14192                                same_text_selected = false;
14193                                selected_text = None;
14194                            }
14195                        } else {
14196                            same_text_selected = false;
14197                            selected_text = None;
14198                        }
14199                    }
14200                }
14201            }
14202
14203            if only_carets {
14204                for selection in &mut selections {
14205                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14206                    selection.start = word_range.start;
14207                    selection.end = word_range.end;
14208                    selection.goal = SelectionGoal::None;
14209                    selection.reversed = false;
14210                    self.select_match_ranges(
14211                        selection.start..selection.end,
14212                        selection.reversed,
14213                        replace_newest,
14214                        autoscroll,
14215                        window,
14216                        cx,
14217                    );
14218                }
14219
14220                if selections.len() == 1 {
14221                    let selection = selections
14222                        .last()
14223                        .expect("ensured that there's only one selection");
14224                    let query = buffer
14225                        .text_for_range(selection.start..selection.end)
14226                        .collect::<String>();
14227                    let is_empty = query.is_empty();
14228                    let select_state = SelectNextState {
14229                        query: AhoCorasick::new(&[query])?,
14230                        wordwise: true,
14231                        done: is_empty,
14232                    };
14233                    self.select_next_state = Some(select_state);
14234                } else {
14235                    self.select_next_state = None;
14236                }
14237            } else if let Some(selected_text) = selected_text {
14238                self.select_next_state = Some(SelectNextState {
14239                    query: AhoCorasick::new(&[selected_text])?,
14240                    wordwise: false,
14241                    done: false,
14242                });
14243                self.select_next_match_internal(
14244                    display_map,
14245                    replace_newest,
14246                    autoscroll,
14247                    window,
14248                    cx,
14249                )?;
14250            }
14251        }
14252        Ok(())
14253    }
14254
14255    pub fn select_all_matches(
14256        &mut self,
14257        _action: &SelectAllMatches,
14258        window: &mut Window,
14259        cx: &mut Context<Self>,
14260    ) -> Result<()> {
14261        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14262
14263        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14264
14265        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14266        let Some(select_next_state) = self.select_next_state.as_mut() else {
14267            return Ok(());
14268        };
14269        if select_next_state.done {
14270            return Ok(());
14271        }
14272
14273        let mut new_selections = Vec::new();
14274
14275        let reversed = self.selections.oldest::<usize>(cx).reversed;
14276        let buffer = &display_map.buffer_snapshot;
14277        let query_matches = select_next_state
14278            .query
14279            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14280
14281        for query_match in query_matches.into_iter() {
14282            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14283            let offset_range = if reversed {
14284                query_match.end()..query_match.start()
14285            } else {
14286                query_match.start()..query_match.end()
14287            };
14288
14289            if !select_next_state.wordwise
14290                || (!buffer.is_inside_word(offset_range.start, false)
14291                    && !buffer.is_inside_word(offset_range.end, false))
14292            {
14293                new_selections.push(offset_range.start..offset_range.end);
14294            }
14295        }
14296
14297        select_next_state.done = true;
14298
14299        if new_selections.is_empty() {
14300            log::error!("bug: new_selections is empty in select_all_matches");
14301            return Ok(());
14302        }
14303
14304        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14305        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14306            selections.select_ranges(new_selections)
14307        });
14308
14309        Ok(())
14310    }
14311
14312    pub fn select_next(
14313        &mut self,
14314        action: &SelectNext,
14315        window: &mut Window,
14316        cx: &mut Context<Self>,
14317    ) -> Result<()> {
14318        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14319        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14320        self.select_next_match_internal(
14321            &display_map,
14322            action.replace_newest,
14323            Some(Autoscroll::newest()),
14324            window,
14325            cx,
14326        )?;
14327        Ok(())
14328    }
14329
14330    pub fn select_previous(
14331        &mut self,
14332        action: &SelectPrevious,
14333        window: &mut Window,
14334        cx: &mut Context<Self>,
14335    ) -> Result<()> {
14336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14337        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14338        let buffer = &display_map.buffer_snapshot;
14339        let mut selections = self.selections.all::<usize>(cx);
14340        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14341            let query = &select_prev_state.query;
14342            if !select_prev_state.done {
14343                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14344                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14345                let mut next_selected_range = None;
14346                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14347                let bytes_before_last_selection =
14348                    buffer.reversed_bytes_in_range(0..last_selection.start);
14349                let bytes_after_first_selection =
14350                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14351                let query_matches = query
14352                    .stream_find_iter(bytes_before_last_selection)
14353                    .map(|result| (last_selection.start, result))
14354                    .chain(
14355                        query
14356                            .stream_find_iter(bytes_after_first_selection)
14357                            .map(|result| (buffer.len(), result)),
14358                    );
14359                for (end_offset, query_match) in query_matches {
14360                    let query_match = query_match.unwrap(); // can only fail due to I/O
14361                    let offset_range =
14362                        end_offset - query_match.end()..end_offset - query_match.start();
14363
14364                    if !select_prev_state.wordwise
14365                        || (!buffer.is_inside_word(offset_range.start, false)
14366                            && !buffer.is_inside_word(offset_range.end, false))
14367                    {
14368                        next_selected_range = Some(offset_range);
14369                        break;
14370                    }
14371                }
14372
14373                if let Some(next_selected_range) = next_selected_range {
14374                    self.select_match_ranges(
14375                        next_selected_range,
14376                        last_selection.reversed,
14377                        action.replace_newest,
14378                        Some(Autoscroll::newest()),
14379                        window,
14380                        cx,
14381                    );
14382                } else {
14383                    select_prev_state.done = true;
14384                }
14385            }
14386
14387            self.select_prev_state = Some(select_prev_state);
14388        } else {
14389            let mut only_carets = true;
14390            let mut same_text_selected = true;
14391            let mut selected_text = None;
14392
14393            let mut selections_iter = selections.iter().peekable();
14394            while let Some(selection) = selections_iter.next() {
14395                if selection.start != selection.end {
14396                    only_carets = false;
14397                }
14398
14399                if same_text_selected {
14400                    if selected_text.is_none() {
14401                        selected_text =
14402                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14403                    }
14404
14405                    if let Some(next_selection) = selections_iter.peek() {
14406                        if next_selection.range().len() == selection.range().len() {
14407                            let next_selected_text = buffer
14408                                .text_for_range(next_selection.range())
14409                                .collect::<String>();
14410                            if Some(next_selected_text) != selected_text {
14411                                same_text_selected = false;
14412                                selected_text = None;
14413                            }
14414                        } else {
14415                            same_text_selected = false;
14416                            selected_text = None;
14417                        }
14418                    }
14419                }
14420            }
14421
14422            if only_carets {
14423                for selection in &mut selections {
14424                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14425                    selection.start = word_range.start;
14426                    selection.end = word_range.end;
14427                    selection.goal = SelectionGoal::None;
14428                    selection.reversed = false;
14429                    self.select_match_ranges(
14430                        selection.start..selection.end,
14431                        selection.reversed,
14432                        action.replace_newest,
14433                        Some(Autoscroll::newest()),
14434                        window,
14435                        cx,
14436                    );
14437                }
14438                if selections.len() == 1 {
14439                    let selection = selections
14440                        .last()
14441                        .expect("ensured that there's only one selection");
14442                    let query = buffer
14443                        .text_for_range(selection.start..selection.end)
14444                        .collect::<String>();
14445                    let is_empty = query.is_empty();
14446                    let select_state = SelectNextState {
14447                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14448                        wordwise: true,
14449                        done: is_empty,
14450                    };
14451                    self.select_prev_state = Some(select_state);
14452                } else {
14453                    self.select_prev_state = None;
14454                }
14455            } else if let Some(selected_text) = selected_text {
14456                self.select_prev_state = Some(SelectNextState {
14457                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14458                    wordwise: false,
14459                    done: false,
14460                });
14461                self.select_previous(action, window, cx)?;
14462            }
14463        }
14464        Ok(())
14465    }
14466
14467    pub fn find_next_match(
14468        &mut self,
14469        _: &FindNextMatch,
14470        window: &mut Window,
14471        cx: &mut Context<Self>,
14472    ) -> Result<()> {
14473        let selections = self.selections.disjoint_anchors();
14474        match selections.first() {
14475            Some(first) if selections.len() >= 2 => {
14476                self.change_selections(Default::default(), window, cx, |s| {
14477                    s.select_ranges([first.range()]);
14478                });
14479            }
14480            _ => self.select_next(
14481                &SelectNext {
14482                    replace_newest: true,
14483                },
14484                window,
14485                cx,
14486            )?,
14487        }
14488        Ok(())
14489    }
14490
14491    pub fn find_previous_match(
14492        &mut self,
14493        _: &FindPreviousMatch,
14494        window: &mut Window,
14495        cx: &mut Context<Self>,
14496    ) -> Result<()> {
14497        let selections = self.selections.disjoint_anchors();
14498        match selections.last() {
14499            Some(last) if selections.len() >= 2 => {
14500                self.change_selections(Default::default(), window, cx, |s| {
14501                    s.select_ranges([last.range()]);
14502                });
14503            }
14504            _ => self.select_previous(
14505                &SelectPrevious {
14506                    replace_newest: true,
14507                },
14508                window,
14509                cx,
14510            )?,
14511        }
14512        Ok(())
14513    }
14514
14515    pub fn toggle_comments(
14516        &mut self,
14517        action: &ToggleComments,
14518        window: &mut Window,
14519        cx: &mut Context<Self>,
14520    ) {
14521        if self.read_only(cx) {
14522            return;
14523        }
14524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14525        let text_layout_details = &self.text_layout_details(window);
14526        self.transact(window, cx, |this, window, cx| {
14527            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14528            let mut edits = Vec::new();
14529            let mut selection_edit_ranges = Vec::new();
14530            let mut last_toggled_row = None;
14531            let snapshot = this.buffer.read(cx).read(cx);
14532            let empty_str: Arc<str> = Arc::default();
14533            let mut suffixes_inserted = Vec::new();
14534            let ignore_indent = action.ignore_indent;
14535
14536            fn comment_prefix_range(
14537                snapshot: &MultiBufferSnapshot,
14538                row: MultiBufferRow,
14539                comment_prefix: &str,
14540                comment_prefix_whitespace: &str,
14541                ignore_indent: bool,
14542            ) -> Range<Point> {
14543                let indent_size = if ignore_indent {
14544                    0
14545                } else {
14546                    snapshot.indent_size_for_line(row).len
14547                };
14548
14549                let start = Point::new(row.0, indent_size);
14550
14551                let mut line_bytes = snapshot
14552                    .bytes_in_range(start..snapshot.max_point())
14553                    .flatten()
14554                    .copied();
14555
14556                // If this line currently begins with the line comment prefix, then record
14557                // the range containing the prefix.
14558                if line_bytes
14559                    .by_ref()
14560                    .take(comment_prefix.len())
14561                    .eq(comment_prefix.bytes())
14562                {
14563                    // Include any whitespace that matches the comment prefix.
14564                    let matching_whitespace_len = line_bytes
14565                        .zip(comment_prefix_whitespace.bytes())
14566                        .take_while(|(a, b)| a == b)
14567                        .count() as u32;
14568                    let end = Point::new(
14569                        start.row,
14570                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14571                    );
14572                    start..end
14573                } else {
14574                    start..start
14575                }
14576            }
14577
14578            fn comment_suffix_range(
14579                snapshot: &MultiBufferSnapshot,
14580                row: MultiBufferRow,
14581                comment_suffix: &str,
14582                comment_suffix_has_leading_space: bool,
14583            ) -> Range<Point> {
14584                let end = Point::new(row.0, snapshot.line_len(row));
14585                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14586
14587                let mut line_end_bytes = snapshot
14588                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14589                    .flatten()
14590                    .copied();
14591
14592                let leading_space_len = if suffix_start_column > 0
14593                    && line_end_bytes.next() == Some(b' ')
14594                    && comment_suffix_has_leading_space
14595                {
14596                    1
14597                } else {
14598                    0
14599                };
14600
14601                // If this line currently begins with the line comment prefix, then record
14602                // the range containing the prefix.
14603                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14604                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14605                    start..end
14606                } else {
14607                    end..end
14608                }
14609            }
14610
14611            // TODO: Handle selections that cross excerpts
14612            for selection in &mut selections {
14613                let start_column = snapshot
14614                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14615                    .len;
14616                let language = if let Some(language) =
14617                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14618                {
14619                    language
14620                } else {
14621                    continue;
14622                };
14623
14624                selection_edit_ranges.clear();
14625
14626                // If multiple selections contain a given row, avoid processing that
14627                // row more than once.
14628                let mut start_row = MultiBufferRow(selection.start.row);
14629                if last_toggled_row == Some(start_row) {
14630                    start_row = start_row.next_row();
14631                }
14632                let end_row =
14633                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14634                        MultiBufferRow(selection.end.row - 1)
14635                    } else {
14636                        MultiBufferRow(selection.end.row)
14637                    };
14638                last_toggled_row = Some(end_row);
14639
14640                if start_row > end_row {
14641                    continue;
14642                }
14643
14644                // If the language has line comments, toggle those.
14645                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14646
14647                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14648                if ignore_indent {
14649                    full_comment_prefixes = full_comment_prefixes
14650                        .into_iter()
14651                        .map(|s| Arc::from(s.trim_end()))
14652                        .collect();
14653                }
14654
14655                if !full_comment_prefixes.is_empty() {
14656                    let first_prefix = full_comment_prefixes
14657                        .first()
14658                        .expect("prefixes is non-empty");
14659                    let prefix_trimmed_lengths = full_comment_prefixes
14660                        .iter()
14661                        .map(|p| p.trim_end_matches(' ').len())
14662                        .collect::<SmallVec<[usize; 4]>>();
14663
14664                    let mut all_selection_lines_are_comments = true;
14665
14666                    for row in start_row.0..=end_row.0 {
14667                        let row = MultiBufferRow(row);
14668                        if start_row < end_row && snapshot.is_line_blank(row) {
14669                            continue;
14670                        }
14671
14672                        let prefix_range = full_comment_prefixes
14673                            .iter()
14674                            .zip(prefix_trimmed_lengths.iter().copied())
14675                            .map(|(prefix, trimmed_prefix_len)| {
14676                                comment_prefix_range(
14677                                    snapshot.deref(),
14678                                    row,
14679                                    &prefix[..trimmed_prefix_len],
14680                                    &prefix[trimmed_prefix_len..],
14681                                    ignore_indent,
14682                                )
14683                            })
14684                            .max_by_key(|range| range.end.column - range.start.column)
14685                            .expect("prefixes is non-empty");
14686
14687                        if prefix_range.is_empty() {
14688                            all_selection_lines_are_comments = false;
14689                        }
14690
14691                        selection_edit_ranges.push(prefix_range);
14692                    }
14693
14694                    if all_selection_lines_are_comments {
14695                        edits.extend(
14696                            selection_edit_ranges
14697                                .iter()
14698                                .cloned()
14699                                .map(|range| (range, empty_str.clone())),
14700                        );
14701                    } else {
14702                        let min_column = selection_edit_ranges
14703                            .iter()
14704                            .map(|range| range.start.column)
14705                            .min()
14706                            .unwrap_or(0);
14707                        edits.extend(selection_edit_ranges.iter().map(|range| {
14708                            let position = Point::new(range.start.row, min_column);
14709                            (position..position, first_prefix.clone())
14710                        }));
14711                    }
14712                } else if let Some(BlockCommentConfig {
14713                    start: full_comment_prefix,
14714                    end: comment_suffix,
14715                    ..
14716                }) = language.block_comment()
14717                {
14718                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14719                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14720                    let prefix_range = comment_prefix_range(
14721                        snapshot.deref(),
14722                        start_row,
14723                        comment_prefix,
14724                        comment_prefix_whitespace,
14725                        ignore_indent,
14726                    );
14727                    let suffix_range = comment_suffix_range(
14728                        snapshot.deref(),
14729                        end_row,
14730                        comment_suffix.trim_start_matches(' '),
14731                        comment_suffix.starts_with(' '),
14732                    );
14733
14734                    if prefix_range.is_empty() || suffix_range.is_empty() {
14735                        edits.push((
14736                            prefix_range.start..prefix_range.start,
14737                            full_comment_prefix.clone(),
14738                        ));
14739                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14740                        suffixes_inserted.push((end_row, comment_suffix.len()));
14741                    } else {
14742                        edits.push((prefix_range, empty_str.clone()));
14743                        edits.push((suffix_range, empty_str.clone()));
14744                    }
14745                } else {
14746                    continue;
14747                }
14748            }
14749
14750            drop(snapshot);
14751            this.buffer.update(cx, |buffer, cx| {
14752                buffer.edit(edits, None, cx);
14753            });
14754
14755            // Adjust selections so that they end before any comment suffixes that
14756            // were inserted.
14757            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14758            let mut selections = this.selections.all::<Point>(cx);
14759            let snapshot = this.buffer.read(cx).read(cx);
14760            for selection in &mut selections {
14761                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14762                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14763                        Ordering::Less => {
14764                            suffixes_inserted.next();
14765                            continue;
14766                        }
14767                        Ordering::Greater => break,
14768                        Ordering::Equal => {
14769                            if selection.end.column == snapshot.line_len(row) {
14770                                if selection.is_empty() {
14771                                    selection.start.column -= suffix_len as u32;
14772                                }
14773                                selection.end.column -= suffix_len as u32;
14774                            }
14775                            break;
14776                        }
14777                    }
14778                }
14779            }
14780
14781            drop(snapshot);
14782            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14783
14784            let selections = this.selections.all::<Point>(cx);
14785            let selections_on_single_row = selections.windows(2).all(|selections| {
14786                selections[0].start.row == selections[1].start.row
14787                    && selections[0].end.row == selections[1].end.row
14788                    && selections[0].start.row == selections[0].end.row
14789            });
14790            let selections_selecting = selections
14791                .iter()
14792                .any(|selection| selection.start != selection.end);
14793            let advance_downwards = action.advance_downwards
14794                && selections_on_single_row
14795                && !selections_selecting
14796                && !matches!(this.mode, EditorMode::SingleLine);
14797
14798            if advance_downwards {
14799                let snapshot = this.buffer.read(cx).snapshot(cx);
14800
14801                this.change_selections(Default::default(), window, cx, |s| {
14802                    s.move_cursors_with(|display_snapshot, display_point, _| {
14803                        let mut point = display_point.to_point(display_snapshot);
14804                        point.row += 1;
14805                        point = snapshot.clip_point(point, Bias::Left);
14806                        let display_point = point.to_display_point(display_snapshot);
14807                        let goal = SelectionGoal::HorizontalPosition(
14808                            display_snapshot
14809                                .x_for_display_point(display_point, text_layout_details)
14810                                .into(),
14811                        );
14812                        (display_point, goal)
14813                    })
14814                });
14815            }
14816        });
14817    }
14818
14819    pub fn select_enclosing_symbol(
14820        &mut self,
14821        _: &SelectEnclosingSymbol,
14822        window: &mut Window,
14823        cx: &mut Context<Self>,
14824    ) {
14825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14826
14827        let buffer = self.buffer.read(cx).snapshot(cx);
14828        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14829
14830        fn update_selection(
14831            selection: &Selection<usize>,
14832            buffer_snap: &MultiBufferSnapshot,
14833        ) -> Option<Selection<usize>> {
14834            let cursor = selection.head();
14835            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14836            for symbol in symbols.iter().rev() {
14837                let start = symbol.range.start.to_offset(buffer_snap);
14838                let end = symbol.range.end.to_offset(buffer_snap);
14839                let new_range = start..end;
14840                if start < selection.start || end > selection.end {
14841                    return Some(Selection {
14842                        id: selection.id,
14843                        start: new_range.start,
14844                        end: new_range.end,
14845                        goal: SelectionGoal::None,
14846                        reversed: selection.reversed,
14847                    });
14848                }
14849            }
14850            None
14851        }
14852
14853        let mut selected_larger_symbol = false;
14854        let new_selections = old_selections
14855            .iter()
14856            .map(|selection| match update_selection(selection, &buffer) {
14857                Some(new_selection) => {
14858                    if new_selection.range() != selection.range() {
14859                        selected_larger_symbol = true;
14860                    }
14861                    new_selection
14862                }
14863                None => selection.clone(),
14864            })
14865            .collect::<Vec<_>>();
14866
14867        if selected_larger_symbol {
14868            self.change_selections(Default::default(), window, cx, |s| {
14869                s.select(new_selections);
14870            });
14871        }
14872    }
14873
14874    pub fn select_larger_syntax_node(
14875        &mut self,
14876        _: &SelectLargerSyntaxNode,
14877        window: &mut Window,
14878        cx: &mut Context<Self>,
14879    ) {
14880        let Some(visible_row_count) = self.visible_row_count() else {
14881            return;
14882        };
14883        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14884        if old_selections.is_empty() {
14885            return;
14886        }
14887
14888        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14889
14890        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14891        let buffer = self.buffer.read(cx).snapshot(cx);
14892
14893        let mut selected_larger_node = false;
14894        let mut new_selections = old_selections
14895            .iter()
14896            .map(|selection| {
14897                let old_range = selection.start..selection.end;
14898
14899                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14900                    // manually select word at selection
14901                    if ["string_content", "inline"].contains(&node.kind()) {
14902                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14903                        // ignore if word is already selected
14904                        if !word_range.is_empty() && old_range != word_range {
14905                            let (last_word_range, _) =
14906                                buffer.surrounding_word(old_range.end, false);
14907                            // only select word if start and end point belongs to same word
14908                            if word_range == last_word_range {
14909                                selected_larger_node = true;
14910                                return Selection {
14911                                    id: selection.id,
14912                                    start: word_range.start,
14913                                    end: word_range.end,
14914                                    goal: SelectionGoal::None,
14915                                    reversed: selection.reversed,
14916                                };
14917                            }
14918                        }
14919                    }
14920                }
14921
14922                let mut new_range = old_range.clone();
14923                while let Some((_node, containing_range)) =
14924                    buffer.syntax_ancestor(new_range.clone())
14925                {
14926                    new_range = match containing_range {
14927                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14928                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14929                    };
14930                    if !display_map.intersects_fold(new_range.start)
14931                        && !display_map.intersects_fold(new_range.end)
14932                    {
14933                        break;
14934                    }
14935                }
14936
14937                selected_larger_node |= new_range != old_range;
14938                Selection {
14939                    id: selection.id,
14940                    start: new_range.start,
14941                    end: new_range.end,
14942                    goal: SelectionGoal::None,
14943                    reversed: selection.reversed,
14944                }
14945            })
14946            .collect::<Vec<_>>();
14947
14948        if !selected_larger_node {
14949            return; // don't put this call in the history
14950        }
14951
14952        // scroll based on transformation done to the last selection created by the user
14953        let (last_old, last_new) = old_selections
14954            .last()
14955            .zip(new_selections.last().cloned())
14956            .expect("old_selections isn't empty");
14957
14958        // revert selection
14959        let is_selection_reversed = {
14960            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14961            new_selections.last_mut().expect("checked above").reversed =
14962                should_newest_selection_be_reversed;
14963            should_newest_selection_be_reversed
14964        };
14965
14966        if selected_larger_node {
14967            self.select_syntax_node_history.disable_clearing = true;
14968            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14969                s.select(new_selections.clone());
14970            });
14971            self.select_syntax_node_history.disable_clearing = false;
14972        }
14973
14974        let start_row = last_new.start.to_display_point(&display_map).row().0;
14975        let end_row = last_new.end.to_display_point(&display_map).row().0;
14976        let selection_height = end_row - start_row + 1;
14977        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14978
14979        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14980        let scroll_behavior = if fits_on_the_screen {
14981            self.request_autoscroll(Autoscroll::fit(), cx);
14982            SelectSyntaxNodeScrollBehavior::FitSelection
14983        } else if is_selection_reversed {
14984            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14985            SelectSyntaxNodeScrollBehavior::CursorTop
14986        } else {
14987            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14988            SelectSyntaxNodeScrollBehavior::CursorBottom
14989        };
14990
14991        self.select_syntax_node_history.push((
14992            old_selections,
14993            scroll_behavior,
14994            is_selection_reversed,
14995        ));
14996    }
14997
14998    pub fn select_smaller_syntax_node(
14999        &mut self,
15000        _: &SelectSmallerSyntaxNode,
15001        window: &mut Window,
15002        cx: &mut Context<Self>,
15003    ) {
15004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15005
15006        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15007            self.select_syntax_node_history.pop()
15008        {
15009            if let Some(selection) = selections.last_mut() {
15010                selection.reversed = is_selection_reversed;
15011            }
15012
15013            self.select_syntax_node_history.disable_clearing = true;
15014            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15015                s.select(selections.to_vec());
15016            });
15017            self.select_syntax_node_history.disable_clearing = false;
15018
15019            match scroll_behavior {
15020                SelectSyntaxNodeScrollBehavior::CursorTop => {
15021                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15022                }
15023                SelectSyntaxNodeScrollBehavior::FitSelection => {
15024                    self.request_autoscroll(Autoscroll::fit(), cx);
15025                }
15026                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15027                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15028                }
15029            }
15030        }
15031    }
15032
15033    pub fn unwrap_syntax_node(
15034        &mut self,
15035        _: &UnwrapSyntaxNode,
15036        window: &mut Window,
15037        cx: &mut Context<Self>,
15038    ) {
15039        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15040
15041        let buffer = self.buffer.read(cx).snapshot(cx);
15042        let selections = self
15043            .selections
15044            .all::<usize>(cx)
15045            .into_iter()
15046            // subtracting the offset requires sorting
15047            .sorted_by_key(|i| i.start);
15048
15049        let full_edits = selections
15050            .into_iter()
15051            .filter_map(|selection| {
15052                // Only requires two branches once if-let-chains stabilize (#53667)
15053                let child = if !selection.is_empty() {
15054                    selection.range()
15055                } else if let Some((_, ancestor_range)) =
15056                    buffer.syntax_ancestor(selection.start..selection.end)
15057                {
15058                    match ancestor_range {
15059                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15060                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15061                    }
15062                } else {
15063                    selection.range()
15064                };
15065
15066                let mut parent = child.clone();
15067                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15068                    parent = match ancestor_range {
15069                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15070                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15071                    };
15072                    if parent.start < child.start || parent.end > child.end {
15073                        break;
15074                    }
15075                }
15076
15077                if parent == child {
15078                    return None;
15079                }
15080                let text = buffer.text_for_range(child).collect::<String>();
15081                Some((selection.id, parent, text))
15082            })
15083            .collect::<Vec<_>>();
15084
15085        self.transact(window, cx, |this, window, cx| {
15086            this.buffer.update(cx, |buffer, cx| {
15087                buffer.edit(
15088                    full_edits
15089                        .iter()
15090                        .map(|(_, p, t)| (p.clone(), t.clone()))
15091                        .collect::<Vec<_>>(),
15092                    None,
15093                    cx,
15094                );
15095            });
15096            this.change_selections(Default::default(), window, cx, |s| {
15097                let mut offset = 0;
15098                let mut selections = vec![];
15099                for (id, parent, text) in full_edits {
15100                    let start = parent.start - offset;
15101                    offset += parent.len() - text.len();
15102                    selections.push(Selection {
15103                        id,
15104                        start,
15105                        end: start + text.len(),
15106                        reversed: false,
15107                        goal: Default::default(),
15108                    });
15109                }
15110                s.select(selections);
15111            });
15112        });
15113    }
15114
15115    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15116        if !EditorSettings::get_global(cx).gutter.runnables {
15117            self.clear_tasks();
15118            return Task::ready(());
15119        }
15120        let project = self.project().map(Entity::downgrade);
15121        let task_sources = self.lsp_task_sources(cx);
15122        let multi_buffer = self.buffer.downgrade();
15123        cx.spawn_in(window, async move |editor, cx| {
15124            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15125            let Some(project) = project.and_then(|p| p.upgrade()) else {
15126                return;
15127            };
15128            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15129                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15130            }) else {
15131                return;
15132            };
15133
15134            let hide_runnables = project
15135                .update(cx, |project, _| project.is_via_collab())
15136                .unwrap_or(true);
15137            if hide_runnables {
15138                return;
15139            }
15140            let new_rows =
15141                cx.background_spawn({
15142                    let snapshot = display_snapshot.clone();
15143                    async move {
15144                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15145                    }
15146                })
15147                    .await;
15148            let Ok(lsp_tasks) =
15149                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15150            else {
15151                return;
15152            };
15153            let lsp_tasks = lsp_tasks.await;
15154
15155            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15156                lsp_tasks
15157                    .into_iter()
15158                    .flat_map(|(kind, tasks)| {
15159                        tasks.into_iter().filter_map(move |(location, task)| {
15160                            Some((kind.clone(), location?, task))
15161                        })
15162                    })
15163                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15164                        let buffer = location.target.buffer;
15165                        let buffer_snapshot = buffer.read(cx).snapshot();
15166                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15167                            |(excerpt_id, snapshot, _)| {
15168                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15169                                    display_snapshot
15170                                        .buffer_snapshot
15171                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15172                                } else {
15173                                    None
15174                                }
15175                            },
15176                        );
15177                        if let Some(offset) = offset {
15178                            let task_buffer_range =
15179                                location.target.range.to_point(&buffer_snapshot);
15180                            let context_buffer_range =
15181                                task_buffer_range.to_offset(&buffer_snapshot);
15182                            let context_range = BufferOffset(context_buffer_range.start)
15183                                ..BufferOffset(context_buffer_range.end);
15184
15185                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15186                                .or_insert_with(|| RunnableTasks {
15187                                    templates: Vec::new(),
15188                                    offset,
15189                                    column: task_buffer_range.start.column,
15190                                    extra_variables: HashMap::default(),
15191                                    context_range,
15192                                })
15193                                .templates
15194                                .push((kind, task.original_task().clone()));
15195                        }
15196
15197                        acc
15198                    })
15199            }) else {
15200                return;
15201            };
15202
15203            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15204                buffer.language_settings(cx).tasks.prefer_lsp
15205            }) else {
15206                return;
15207            };
15208
15209            let rows = Self::runnable_rows(
15210                project,
15211                display_snapshot,
15212                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15213                new_rows,
15214                cx.clone(),
15215            )
15216            .await;
15217            editor
15218                .update(cx, |editor, _| {
15219                    editor.clear_tasks();
15220                    for (key, mut value) in rows {
15221                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15222                            value.templates.extend(lsp_tasks.templates);
15223                        }
15224
15225                        editor.insert_tasks(key, value);
15226                    }
15227                    for (key, value) in lsp_tasks_by_rows {
15228                        editor.insert_tasks(key, value);
15229                    }
15230                })
15231                .ok();
15232        })
15233    }
15234    fn fetch_runnable_ranges(
15235        snapshot: &DisplaySnapshot,
15236        range: Range<Anchor>,
15237    ) -> Vec<language::RunnableRange> {
15238        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15239    }
15240
15241    fn runnable_rows(
15242        project: Entity<Project>,
15243        snapshot: DisplaySnapshot,
15244        prefer_lsp: bool,
15245        runnable_ranges: Vec<RunnableRange>,
15246        cx: AsyncWindowContext,
15247    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15248        cx.spawn(async move |cx| {
15249            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15250            for mut runnable in runnable_ranges {
15251                let Some(tasks) = cx
15252                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15253                    .ok()
15254                else {
15255                    continue;
15256                };
15257                let mut tasks = tasks.await;
15258
15259                if prefer_lsp {
15260                    tasks.retain(|(task_kind, _)| {
15261                        !matches!(task_kind, TaskSourceKind::Language { .. })
15262                    });
15263                }
15264                if tasks.is_empty() {
15265                    continue;
15266                }
15267
15268                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15269                let Some(row) = snapshot
15270                    .buffer_snapshot
15271                    .buffer_line_for_row(MultiBufferRow(point.row))
15272                    .map(|(_, range)| range.start.row)
15273                else {
15274                    continue;
15275                };
15276
15277                let context_range =
15278                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15279                runnable_rows.push((
15280                    (runnable.buffer_id, row),
15281                    RunnableTasks {
15282                        templates: tasks,
15283                        offset: snapshot
15284                            .buffer_snapshot
15285                            .anchor_before(runnable.run_range.start),
15286                        context_range,
15287                        column: point.column,
15288                        extra_variables: runnable.extra_captures,
15289                    },
15290                ));
15291            }
15292            runnable_rows
15293        })
15294    }
15295
15296    fn templates_with_tags(
15297        project: &Entity<Project>,
15298        runnable: &mut Runnable,
15299        cx: &mut App,
15300    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15301        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15302            let (worktree_id, file) = project
15303                .buffer_for_id(runnable.buffer, cx)
15304                .and_then(|buffer| buffer.read(cx).file())
15305                .map(|file| (file.worktree_id(cx), file.clone()))
15306                .unzip();
15307
15308            (
15309                project.task_store().read(cx).task_inventory().cloned(),
15310                worktree_id,
15311                file,
15312            )
15313        });
15314
15315        let tags = mem::take(&mut runnable.tags);
15316        let language = runnable.language.clone();
15317        cx.spawn(async move |cx| {
15318            let mut templates_with_tags = Vec::new();
15319            if let Some(inventory) = inventory {
15320                for RunnableTag(tag) in tags {
15321                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15322                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15323                    }) else {
15324                        return templates_with_tags;
15325                    };
15326                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15327                        move |(_, template)| {
15328                            template.tags.iter().any(|source_tag| source_tag == &tag)
15329                        },
15330                    ));
15331                }
15332            }
15333            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15334
15335            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15336                // Strongest source wins; if we have worktree tag binding, prefer that to
15337                // global and language bindings;
15338                // if we have a global binding, prefer that to language binding.
15339                let first_mismatch = templates_with_tags
15340                    .iter()
15341                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15342                if let Some(index) = first_mismatch {
15343                    templates_with_tags.truncate(index);
15344                }
15345            }
15346
15347            templates_with_tags
15348        })
15349    }
15350
15351    pub fn move_to_enclosing_bracket(
15352        &mut self,
15353        _: &MoveToEnclosingBracket,
15354        window: &mut Window,
15355        cx: &mut Context<Self>,
15356    ) {
15357        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15358        self.change_selections(Default::default(), window, cx, |s| {
15359            s.move_offsets_with(|snapshot, selection| {
15360                let Some(enclosing_bracket_ranges) =
15361                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15362                else {
15363                    return;
15364                };
15365
15366                let mut best_length = usize::MAX;
15367                let mut best_inside = false;
15368                let mut best_in_bracket_range = false;
15369                let mut best_destination = None;
15370                for (open, close) in enclosing_bracket_ranges {
15371                    let close = close.to_inclusive();
15372                    let length = close.end() - open.start;
15373                    let inside = selection.start >= open.end && selection.end <= *close.start();
15374                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15375                        || close.contains(&selection.head());
15376
15377                    // If best is next to a bracket and current isn't, skip
15378                    if !in_bracket_range && best_in_bracket_range {
15379                        continue;
15380                    }
15381
15382                    // Prefer smaller lengths unless best is inside and current isn't
15383                    if length > best_length && (best_inside || !inside) {
15384                        continue;
15385                    }
15386
15387                    best_length = length;
15388                    best_inside = inside;
15389                    best_in_bracket_range = in_bracket_range;
15390                    best_destination = Some(
15391                        if close.contains(&selection.start) && close.contains(&selection.end) {
15392                            if inside { open.end } else { open.start }
15393                        } else if inside {
15394                            *close.start()
15395                        } else {
15396                            *close.end()
15397                        },
15398                    );
15399                }
15400
15401                if let Some(destination) = best_destination {
15402                    selection.collapse_to(destination, SelectionGoal::None);
15403                }
15404            })
15405        });
15406    }
15407
15408    pub fn undo_selection(
15409        &mut self,
15410        _: &UndoSelection,
15411        window: &mut Window,
15412        cx: &mut Context<Self>,
15413    ) {
15414        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15415        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15416            self.selection_history.mode = SelectionHistoryMode::Undoing;
15417            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15418                this.end_selection(window, cx);
15419                this.change_selections(
15420                    SelectionEffects::scroll(Autoscroll::newest()),
15421                    window,
15422                    cx,
15423                    |s| s.select_anchors(entry.selections.to_vec()),
15424                );
15425            });
15426            self.selection_history.mode = SelectionHistoryMode::Normal;
15427
15428            self.select_next_state = entry.select_next_state;
15429            self.select_prev_state = entry.select_prev_state;
15430            self.add_selections_state = entry.add_selections_state;
15431        }
15432    }
15433
15434    pub fn redo_selection(
15435        &mut self,
15436        _: &RedoSelection,
15437        window: &mut Window,
15438        cx: &mut Context<Self>,
15439    ) {
15440        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15441        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15442            self.selection_history.mode = SelectionHistoryMode::Redoing;
15443            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15444                this.end_selection(window, cx);
15445                this.change_selections(
15446                    SelectionEffects::scroll(Autoscroll::newest()),
15447                    window,
15448                    cx,
15449                    |s| s.select_anchors(entry.selections.to_vec()),
15450                );
15451            });
15452            self.selection_history.mode = SelectionHistoryMode::Normal;
15453
15454            self.select_next_state = entry.select_next_state;
15455            self.select_prev_state = entry.select_prev_state;
15456            self.add_selections_state = entry.add_selections_state;
15457        }
15458    }
15459
15460    pub fn expand_excerpts(
15461        &mut self,
15462        action: &ExpandExcerpts,
15463        _: &mut Window,
15464        cx: &mut Context<Self>,
15465    ) {
15466        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15467    }
15468
15469    pub fn expand_excerpts_down(
15470        &mut self,
15471        action: &ExpandExcerptsDown,
15472        _: &mut Window,
15473        cx: &mut Context<Self>,
15474    ) {
15475        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15476    }
15477
15478    pub fn expand_excerpts_up(
15479        &mut self,
15480        action: &ExpandExcerptsUp,
15481        _: &mut Window,
15482        cx: &mut Context<Self>,
15483    ) {
15484        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15485    }
15486
15487    pub fn expand_excerpts_for_direction(
15488        &mut self,
15489        lines: u32,
15490        direction: ExpandExcerptDirection,
15491
15492        cx: &mut Context<Self>,
15493    ) {
15494        let selections = self.selections.disjoint_anchors();
15495
15496        let lines = if lines == 0 {
15497            EditorSettings::get_global(cx).expand_excerpt_lines
15498        } else {
15499            lines
15500        };
15501
15502        self.buffer.update(cx, |buffer, cx| {
15503            let snapshot = buffer.snapshot(cx);
15504            let mut excerpt_ids = selections
15505                .iter()
15506                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15507                .collect::<Vec<_>>();
15508            excerpt_ids.sort();
15509            excerpt_ids.dedup();
15510            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15511        })
15512    }
15513
15514    pub fn expand_excerpt(
15515        &mut self,
15516        excerpt: ExcerptId,
15517        direction: ExpandExcerptDirection,
15518        window: &mut Window,
15519        cx: &mut Context<Self>,
15520    ) {
15521        let current_scroll_position = self.scroll_position(cx);
15522        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15523        let mut should_scroll_up = false;
15524
15525        if direction == ExpandExcerptDirection::Down {
15526            let multi_buffer = self.buffer.read(cx);
15527            let snapshot = multi_buffer.snapshot(cx);
15528            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15529                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15530                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15531            {
15532                let buffer_snapshot = buffer.read(cx).snapshot();
15533                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15534                let last_row = buffer_snapshot.max_point().row;
15535                let lines_below = last_row.saturating_sub(excerpt_end_row);
15536                should_scroll_up = lines_below >= lines_to_expand;
15537            }
15538        }
15539
15540        self.buffer.update(cx, |buffer, cx| {
15541            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15542        });
15543
15544        if should_scroll_up {
15545            let new_scroll_position =
15546                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15547            self.set_scroll_position(new_scroll_position, window, cx);
15548        }
15549    }
15550
15551    pub fn go_to_singleton_buffer_point(
15552        &mut self,
15553        point: Point,
15554        window: &mut Window,
15555        cx: &mut Context<Self>,
15556    ) {
15557        self.go_to_singleton_buffer_range(point..point, window, cx);
15558    }
15559
15560    pub fn go_to_singleton_buffer_range(
15561        &mut self,
15562        range: Range<Point>,
15563        window: &mut Window,
15564        cx: &mut Context<Self>,
15565    ) {
15566        let multibuffer = self.buffer().read(cx);
15567        let Some(buffer) = multibuffer.as_singleton() else {
15568            return;
15569        };
15570        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15571            return;
15572        };
15573        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15574            return;
15575        };
15576        self.change_selections(
15577            SelectionEffects::default().nav_history(true),
15578            window,
15579            cx,
15580            |s| s.select_anchor_ranges([start..end]),
15581        );
15582    }
15583
15584    pub fn go_to_diagnostic(
15585        &mut self,
15586        action: &GoToDiagnostic,
15587        window: &mut Window,
15588        cx: &mut Context<Self>,
15589    ) {
15590        if !self.diagnostics_enabled() {
15591            return;
15592        }
15593        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15594        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15595    }
15596
15597    pub fn go_to_prev_diagnostic(
15598        &mut self,
15599        action: &GoToPreviousDiagnostic,
15600        window: &mut Window,
15601        cx: &mut Context<Self>,
15602    ) {
15603        if !self.diagnostics_enabled() {
15604            return;
15605        }
15606        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15607        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15608    }
15609
15610    pub fn go_to_diagnostic_impl(
15611        &mut self,
15612        direction: Direction,
15613        severity: GoToDiagnosticSeverityFilter,
15614        window: &mut Window,
15615        cx: &mut Context<Self>,
15616    ) {
15617        let buffer = self.buffer.read(cx).snapshot(cx);
15618        let selection = self.selections.newest::<usize>(cx);
15619
15620        let mut active_group_id = None;
15621        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15622            && active_group.active_range.start.to_offset(&buffer) == selection.start
15623        {
15624            active_group_id = Some(active_group.group_id);
15625        }
15626
15627        fn filtered(
15628            snapshot: EditorSnapshot,
15629            severity: GoToDiagnosticSeverityFilter,
15630            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15631        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15632            diagnostics
15633                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15634                .filter(|entry| entry.range.start != entry.range.end)
15635                .filter(|entry| !entry.diagnostic.is_unnecessary)
15636                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15637        }
15638
15639        let snapshot = self.snapshot(window, cx);
15640        let before = filtered(
15641            snapshot.clone(),
15642            severity,
15643            buffer
15644                .diagnostics_in_range(0..selection.start)
15645                .filter(|entry| entry.range.start <= selection.start),
15646        );
15647        let after = filtered(
15648            snapshot,
15649            severity,
15650            buffer
15651                .diagnostics_in_range(selection.start..buffer.len())
15652                .filter(|entry| entry.range.start >= selection.start),
15653        );
15654
15655        let mut found: Option<DiagnosticEntry<usize>> = None;
15656        if direction == Direction::Prev {
15657            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15658            {
15659                for diagnostic in prev_diagnostics.into_iter().rev() {
15660                    if diagnostic.range.start != selection.start
15661                        || active_group_id
15662                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15663                    {
15664                        found = Some(diagnostic);
15665                        break 'outer;
15666                    }
15667                }
15668            }
15669        } else {
15670            for diagnostic in after.chain(before) {
15671                if diagnostic.range.start != selection.start
15672                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15673                {
15674                    found = Some(diagnostic);
15675                    break;
15676                }
15677            }
15678        }
15679        let Some(next_diagnostic) = found else {
15680            return;
15681        };
15682
15683        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15684        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15685            return;
15686        };
15687        self.change_selections(Default::default(), window, cx, |s| {
15688            s.select_ranges(vec![
15689                next_diagnostic.range.start..next_diagnostic.range.start,
15690            ])
15691        });
15692        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15693        self.refresh_edit_prediction(false, true, window, cx);
15694    }
15695
15696    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15697        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15698        let snapshot = self.snapshot(window, cx);
15699        let selection = self.selections.newest::<Point>(cx);
15700        self.go_to_hunk_before_or_after_position(
15701            &snapshot,
15702            selection.head(),
15703            Direction::Next,
15704            window,
15705            cx,
15706        );
15707    }
15708
15709    pub fn go_to_hunk_before_or_after_position(
15710        &mut self,
15711        snapshot: &EditorSnapshot,
15712        position: Point,
15713        direction: Direction,
15714        window: &mut Window,
15715        cx: &mut Context<Editor>,
15716    ) {
15717        let row = if direction == Direction::Next {
15718            self.hunk_after_position(snapshot, position)
15719                .map(|hunk| hunk.row_range.start)
15720        } else {
15721            self.hunk_before_position(snapshot, position)
15722        };
15723
15724        if let Some(row) = row {
15725            let destination = Point::new(row.0, 0);
15726            let autoscroll = Autoscroll::center();
15727
15728            self.unfold_ranges(&[destination..destination], false, false, cx);
15729            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15730                s.select_ranges([destination..destination]);
15731            });
15732        }
15733    }
15734
15735    fn hunk_after_position(
15736        &mut self,
15737        snapshot: &EditorSnapshot,
15738        position: Point,
15739    ) -> Option<MultiBufferDiffHunk> {
15740        snapshot
15741            .buffer_snapshot
15742            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15743            .find(|hunk| hunk.row_range.start.0 > position.row)
15744            .or_else(|| {
15745                snapshot
15746                    .buffer_snapshot
15747                    .diff_hunks_in_range(Point::zero()..position)
15748                    .find(|hunk| hunk.row_range.end.0 < position.row)
15749            })
15750    }
15751
15752    fn go_to_prev_hunk(
15753        &mut self,
15754        _: &GoToPreviousHunk,
15755        window: &mut Window,
15756        cx: &mut Context<Self>,
15757    ) {
15758        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15759        let snapshot = self.snapshot(window, cx);
15760        let selection = self.selections.newest::<Point>(cx);
15761        self.go_to_hunk_before_or_after_position(
15762            &snapshot,
15763            selection.head(),
15764            Direction::Prev,
15765            window,
15766            cx,
15767        );
15768    }
15769
15770    fn hunk_before_position(
15771        &mut self,
15772        snapshot: &EditorSnapshot,
15773        position: Point,
15774    ) -> Option<MultiBufferRow> {
15775        snapshot
15776            .buffer_snapshot
15777            .diff_hunk_before(position)
15778            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15779    }
15780
15781    fn go_to_next_change(
15782        &mut self,
15783        _: &GoToNextChange,
15784        window: &mut Window,
15785        cx: &mut Context<Self>,
15786    ) {
15787        if let Some(selections) = self
15788            .change_list
15789            .next_change(1, Direction::Next)
15790            .map(|s| s.to_vec())
15791        {
15792            self.change_selections(Default::default(), window, cx, |s| {
15793                let map = s.display_map();
15794                s.select_display_ranges(selections.iter().map(|a| {
15795                    let point = a.to_display_point(&map);
15796                    point..point
15797                }))
15798            })
15799        }
15800    }
15801
15802    fn go_to_previous_change(
15803        &mut self,
15804        _: &GoToPreviousChange,
15805        window: &mut Window,
15806        cx: &mut Context<Self>,
15807    ) {
15808        if let Some(selections) = self
15809            .change_list
15810            .next_change(1, Direction::Prev)
15811            .map(|s| s.to_vec())
15812        {
15813            self.change_selections(Default::default(), window, cx, |s| {
15814                let map = s.display_map();
15815                s.select_display_ranges(selections.iter().map(|a| {
15816                    let point = a.to_display_point(&map);
15817                    point..point
15818                }))
15819            })
15820        }
15821    }
15822
15823    fn go_to_line<T: 'static>(
15824        &mut self,
15825        position: Anchor,
15826        highlight_color: Option<Hsla>,
15827        window: &mut Window,
15828        cx: &mut Context<Self>,
15829    ) {
15830        let snapshot = self.snapshot(window, cx).display_snapshot;
15831        let position = position.to_point(&snapshot.buffer_snapshot);
15832        let start = snapshot
15833            .buffer_snapshot
15834            .clip_point(Point::new(position.row, 0), Bias::Left);
15835        let end = start + Point::new(1, 0);
15836        let start = snapshot.buffer_snapshot.anchor_before(start);
15837        let end = snapshot.buffer_snapshot.anchor_before(end);
15838
15839        self.highlight_rows::<T>(
15840            start..end,
15841            highlight_color
15842                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15843            Default::default(),
15844            cx,
15845        );
15846
15847        if self.buffer.read(cx).is_singleton() {
15848            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15849        }
15850    }
15851
15852    pub fn go_to_definition(
15853        &mut self,
15854        _: &GoToDefinition,
15855        window: &mut Window,
15856        cx: &mut Context<Self>,
15857    ) -> Task<Result<Navigated>> {
15858        let definition =
15859            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15860        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15861        cx.spawn_in(window, async move |editor, cx| {
15862            if definition.await? == Navigated::Yes {
15863                return Ok(Navigated::Yes);
15864            }
15865            match fallback_strategy {
15866                GoToDefinitionFallback::None => Ok(Navigated::No),
15867                GoToDefinitionFallback::FindAllReferences => {
15868                    match editor.update_in(cx, |editor, window, cx| {
15869                        editor.find_all_references(&FindAllReferences, window, cx)
15870                    })? {
15871                        Some(references) => references.await,
15872                        None => Ok(Navigated::No),
15873                    }
15874                }
15875            }
15876        })
15877    }
15878
15879    pub fn go_to_declaration(
15880        &mut self,
15881        _: &GoToDeclaration,
15882        window: &mut Window,
15883        cx: &mut Context<Self>,
15884    ) -> Task<Result<Navigated>> {
15885        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15886    }
15887
15888    pub fn go_to_declaration_split(
15889        &mut self,
15890        _: &GoToDeclaration,
15891        window: &mut Window,
15892        cx: &mut Context<Self>,
15893    ) -> Task<Result<Navigated>> {
15894        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15895    }
15896
15897    pub fn go_to_implementation(
15898        &mut self,
15899        _: &GoToImplementation,
15900        window: &mut Window,
15901        cx: &mut Context<Self>,
15902    ) -> Task<Result<Navigated>> {
15903        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15904    }
15905
15906    pub fn go_to_implementation_split(
15907        &mut self,
15908        _: &GoToImplementationSplit,
15909        window: &mut Window,
15910        cx: &mut Context<Self>,
15911    ) -> Task<Result<Navigated>> {
15912        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15913    }
15914
15915    pub fn go_to_type_definition(
15916        &mut self,
15917        _: &GoToTypeDefinition,
15918        window: &mut Window,
15919        cx: &mut Context<Self>,
15920    ) -> Task<Result<Navigated>> {
15921        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15922    }
15923
15924    pub fn go_to_definition_split(
15925        &mut self,
15926        _: &GoToDefinitionSplit,
15927        window: &mut Window,
15928        cx: &mut Context<Self>,
15929    ) -> Task<Result<Navigated>> {
15930        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15931    }
15932
15933    pub fn go_to_type_definition_split(
15934        &mut self,
15935        _: &GoToTypeDefinitionSplit,
15936        window: &mut Window,
15937        cx: &mut Context<Self>,
15938    ) -> Task<Result<Navigated>> {
15939        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15940    }
15941
15942    fn go_to_definition_of_kind(
15943        &mut self,
15944        kind: GotoDefinitionKind,
15945        split: bool,
15946        window: &mut Window,
15947        cx: &mut Context<Self>,
15948    ) -> Task<Result<Navigated>> {
15949        let Some(provider) = self.semantics_provider.clone() else {
15950            return Task::ready(Ok(Navigated::No));
15951        };
15952        let head = self.selections.newest::<usize>(cx).head();
15953        let buffer = self.buffer.read(cx);
15954        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15955            return Task::ready(Ok(Navigated::No));
15956        };
15957        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15958            return Task::ready(Ok(Navigated::No));
15959        };
15960
15961        cx.spawn_in(window, async move |editor, cx| {
15962            let Some(definitions) = definitions.await? else {
15963                return Ok(Navigated::No);
15964            };
15965            let navigated = editor
15966                .update_in(cx, |editor, window, cx| {
15967                    editor.navigate_to_hover_links(
15968                        Some(kind),
15969                        definitions
15970                            .into_iter()
15971                            .filter(|location| {
15972                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15973                            })
15974                            .map(HoverLink::Text)
15975                            .collect::<Vec<_>>(),
15976                        split,
15977                        window,
15978                        cx,
15979                    )
15980                })?
15981                .await?;
15982            anyhow::Ok(navigated)
15983        })
15984    }
15985
15986    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15987        let selection = self.selections.newest_anchor();
15988        let head = selection.head();
15989        let tail = selection.tail();
15990
15991        let Some((buffer, start_position)) =
15992            self.buffer.read(cx).text_anchor_for_position(head, cx)
15993        else {
15994            return;
15995        };
15996
15997        let end_position = if head != tail {
15998            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15999                return;
16000            };
16001            Some(pos)
16002        } else {
16003            None
16004        };
16005
16006        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16007            let url = if let Some(end_pos) = end_position {
16008                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16009            } else {
16010                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16011            };
16012
16013            if let Some(url) = url {
16014                editor.update(cx, |_, cx| {
16015                    cx.open_url(&url);
16016                })
16017            } else {
16018                Ok(())
16019            }
16020        });
16021
16022        url_finder.detach();
16023    }
16024
16025    pub fn open_selected_filename(
16026        &mut self,
16027        _: &OpenSelectedFilename,
16028        window: &mut Window,
16029        cx: &mut Context<Self>,
16030    ) {
16031        let Some(workspace) = self.workspace() else {
16032            return;
16033        };
16034
16035        let position = self.selections.newest_anchor().head();
16036
16037        let Some((buffer, buffer_position)) =
16038            self.buffer.read(cx).text_anchor_for_position(position, cx)
16039        else {
16040            return;
16041        };
16042
16043        let project = self.project.clone();
16044
16045        cx.spawn_in(window, async move |_, cx| {
16046            let result = find_file(&buffer, project, buffer_position, cx).await;
16047
16048            if let Some((_, path)) = result {
16049                workspace
16050                    .update_in(cx, |workspace, window, cx| {
16051                        workspace.open_resolved_path(path, window, cx)
16052                    })?
16053                    .await?;
16054            }
16055            anyhow::Ok(())
16056        })
16057        .detach();
16058    }
16059
16060    pub(crate) fn navigate_to_hover_links(
16061        &mut self,
16062        kind: Option<GotoDefinitionKind>,
16063        definitions: Vec<HoverLink>,
16064        split: bool,
16065        window: &mut Window,
16066        cx: &mut Context<Editor>,
16067    ) -> Task<Result<Navigated>> {
16068        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16069        let mut first_url_or_file = None;
16070        let definitions: Vec<_> = definitions
16071            .into_iter()
16072            .filter_map(|def| match def {
16073                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16074                HoverLink::InlayHint(lsp_location, server_id) => {
16075                    let computation =
16076                        self.compute_target_location(lsp_location, server_id, window, cx);
16077                    Some(cx.background_spawn(computation))
16078                }
16079                HoverLink::Url(url) => {
16080                    first_url_or_file = Some(Either::Left(url));
16081                    None
16082                }
16083                HoverLink::File(path) => {
16084                    first_url_or_file = Some(Either::Right(path));
16085                    None
16086                }
16087            })
16088            .collect();
16089
16090        let workspace = self.workspace();
16091
16092        cx.spawn_in(window, async move |editor, acx| {
16093            let mut locations: Vec<Location> = future::join_all(definitions)
16094                .await
16095                .into_iter()
16096                .filter_map(|location| location.transpose())
16097                .collect::<Result<_>>()
16098                .context("location tasks")?;
16099
16100            if locations.len() > 1 {
16101                let Some(workspace) = workspace else {
16102                    return Ok(Navigated::No);
16103                };
16104
16105                let tab_kind = match kind {
16106                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16107                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16108                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16109                    Some(GotoDefinitionKind::Type) => "Types",
16110                };
16111                let title = editor
16112                    .update_in(acx, |_, _, cx| {
16113                        let target = locations
16114                            .iter()
16115                            .map(|location| {
16116                                location
16117                                    .buffer
16118                                    .read(cx)
16119                                    .text_for_range(location.range.clone())
16120                                    .collect::<String>()
16121                            })
16122                            .filter(|text| !text.contains('\n'))
16123                            .unique()
16124                            .take(3)
16125                            .join(", ");
16126                        if target.is_empty() {
16127                            tab_kind.to_owned()
16128                        } else {
16129                            format!("{tab_kind} for {target}")
16130                        }
16131                    })
16132                    .context("buffer title")?;
16133
16134                let opened = workspace
16135                    .update_in(acx, |workspace, window, cx| {
16136                        Self::open_locations_in_multibuffer(
16137                            workspace,
16138                            locations,
16139                            title,
16140                            split,
16141                            MultibufferSelectionMode::First,
16142                            window,
16143                            cx,
16144                        )
16145                    })
16146                    .is_ok();
16147
16148                anyhow::Ok(Navigated::from_bool(opened))
16149            } else if locations.is_empty() {
16150                // If there is one definition, just open it directly
16151                match first_url_or_file {
16152                    Some(Either::Left(url)) => {
16153                        acx.update(|_, cx| cx.open_url(&url))?;
16154                        Ok(Navigated::Yes)
16155                    }
16156                    Some(Either::Right(path)) => {
16157                        let Some(workspace) = workspace else {
16158                            return Ok(Navigated::No);
16159                        };
16160
16161                        workspace
16162                            .update_in(acx, |workspace, window, cx| {
16163                                workspace.open_resolved_path(path, window, cx)
16164                            })?
16165                            .await?;
16166                        Ok(Navigated::Yes)
16167                    }
16168                    None => Ok(Navigated::No),
16169                }
16170            } else {
16171                let Some(workspace) = workspace else {
16172                    return Ok(Navigated::No);
16173                };
16174
16175                let target = locations.pop().unwrap();
16176                editor.update_in(acx, |editor, window, cx| {
16177                    let pane = workspace.read(cx).active_pane().clone();
16178
16179                    let range = target.range.to_point(target.buffer.read(cx));
16180                    let range = editor.range_for_match(&range);
16181                    let range = collapse_multiline_range(range);
16182
16183                    if !split
16184                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16185                    {
16186                        editor.go_to_singleton_buffer_range(range, window, cx);
16187                    } else {
16188                        window.defer(cx, move |window, cx| {
16189                            let target_editor: Entity<Self> =
16190                                workspace.update(cx, |workspace, cx| {
16191                                    let pane = if split {
16192                                        workspace.adjacent_pane(window, cx)
16193                                    } else {
16194                                        workspace.active_pane().clone()
16195                                    };
16196
16197                                    workspace.open_project_item(
16198                                        pane,
16199                                        target.buffer.clone(),
16200                                        true,
16201                                        true,
16202                                        window,
16203                                        cx,
16204                                    )
16205                                });
16206                            target_editor.update(cx, |target_editor, cx| {
16207                                // When selecting a definition in a different buffer, disable the nav history
16208                                // to avoid creating a history entry at the previous cursor location.
16209                                pane.update(cx, |pane, _| pane.disable_history());
16210                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16211                                pane.update(cx, |pane, _| pane.enable_history());
16212                            });
16213                        });
16214                    }
16215                    Navigated::Yes
16216                })
16217            }
16218        })
16219    }
16220
16221    fn compute_target_location(
16222        &self,
16223        lsp_location: lsp::Location,
16224        server_id: LanguageServerId,
16225        window: &mut Window,
16226        cx: &mut Context<Self>,
16227    ) -> Task<anyhow::Result<Option<Location>>> {
16228        let Some(project) = self.project.clone() else {
16229            return Task::ready(Ok(None));
16230        };
16231
16232        cx.spawn_in(window, async move |editor, cx| {
16233            let location_task = editor.update(cx, |_, cx| {
16234                project.update(cx, |project, cx| {
16235                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16236                })
16237            })?;
16238            let location = Some({
16239                let target_buffer_handle = location_task.await.context("open local buffer")?;
16240                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16241                    let target_start = target_buffer
16242                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16243                    let target_end = target_buffer
16244                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16245                    target_buffer.anchor_after(target_start)
16246                        ..target_buffer.anchor_before(target_end)
16247                })?;
16248                Location {
16249                    buffer: target_buffer_handle,
16250                    range,
16251                }
16252            });
16253            Ok(location)
16254        })
16255    }
16256
16257    pub fn find_all_references(
16258        &mut self,
16259        _: &FindAllReferences,
16260        window: &mut Window,
16261        cx: &mut Context<Self>,
16262    ) -> Option<Task<Result<Navigated>>> {
16263        let selection = self.selections.newest::<usize>(cx);
16264        let multi_buffer = self.buffer.read(cx);
16265        let head = selection.head();
16266
16267        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16268        let head_anchor = multi_buffer_snapshot.anchor_at(
16269            head,
16270            if head < selection.tail() {
16271                Bias::Right
16272            } else {
16273                Bias::Left
16274            },
16275        );
16276
16277        match self
16278            .find_all_references_task_sources
16279            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16280        {
16281            Ok(_) => {
16282                log::info!(
16283                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16284                );
16285                return None;
16286            }
16287            Err(i) => {
16288                self.find_all_references_task_sources.insert(i, head_anchor);
16289            }
16290        }
16291
16292        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16293        let workspace = self.workspace()?;
16294        let project = workspace.read(cx).project().clone();
16295        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16296        Some(cx.spawn_in(window, async move |editor, cx| {
16297            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16298                if let Ok(i) = editor
16299                    .find_all_references_task_sources
16300                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16301                {
16302                    editor.find_all_references_task_sources.remove(i);
16303                }
16304            });
16305
16306            let Some(locations) = references.await? else {
16307                return anyhow::Ok(Navigated::No);
16308            };
16309            if locations.is_empty() {
16310                return anyhow::Ok(Navigated::No);
16311            }
16312
16313            workspace.update_in(cx, |workspace, window, cx| {
16314                let target = locations
16315                    .iter()
16316                    .map(|location| {
16317                        location
16318                            .buffer
16319                            .read(cx)
16320                            .text_for_range(location.range.clone())
16321                            .collect::<String>()
16322                    })
16323                    .filter(|text| !text.contains('\n'))
16324                    .unique()
16325                    .take(3)
16326                    .join(", ");
16327                let title = if target.is_empty() {
16328                    "References".to_owned()
16329                } else {
16330                    format!("References to {target}")
16331                };
16332                Self::open_locations_in_multibuffer(
16333                    workspace,
16334                    locations,
16335                    title,
16336                    false,
16337                    MultibufferSelectionMode::First,
16338                    window,
16339                    cx,
16340                );
16341                Navigated::Yes
16342            })
16343        }))
16344    }
16345
16346    /// Opens a multibuffer with the given project locations in it
16347    pub fn open_locations_in_multibuffer(
16348        workspace: &mut Workspace,
16349        mut locations: Vec<Location>,
16350        title: String,
16351        split: bool,
16352        multibuffer_selection_mode: MultibufferSelectionMode,
16353        window: &mut Window,
16354        cx: &mut Context<Workspace>,
16355    ) {
16356        if locations.is_empty() {
16357            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16358            return;
16359        }
16360
16361        // If there are multiple definitions, open them in a multibuffer
16362        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16363        let mut locations = locations.into_iter().peekable();
16364        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16365        let capability = workspace.project().read(cx).capability();
16366
16367        let excerpt_buffer = cx.new(|cx| {
16368            let mut multibuffer = MultiBuffer::new(capability);
16369            while let Some(location) = locations.next() {
16370                let buffer = location.buffer.read(cx);
16371                let mut ranges_for_buffer = Vec::new();
16372                let range = location.range.to_point(buffer);
16373                ranges_for_buffer.push(range.clone());
16374
16375                while let Some(next_location) = locations.peek() {
16376                    if next_location.buffer == location.buffer {
16377                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16378                        locations.next();
16379                    } else {
16380                        break;
16381                    }
16382                }
16383
16384                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16385                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16386                    PathKey::for_buffer(&location.buffer, cx),
16387                    location.buffer.clone(),
16388                    ranges_for_buffer,
16389                    multibuffer_context_lines(cx),
16390                    cx,
16391                );
16392                ranges.extend(new_ranges)
16393            }
16394
16395            multibuffer.with_title(title)
16396        });
16397
16398        let editor = cx.new(|cx| {
16399            Editor::for_multibuffer(
16400                excerpt_buffer,
16401                Some(workspace.project().clone()),
16402                window,
16403                cx,
16404            )
16405        });
16406        editor.update(cx, |editor, cx| {
16407            match multibuffer_selection_mode {
16408                MultibufferSelectionMode::First => {
16409                    if let Some(first_range) = ranges.first() {
16410                        editor.change_selections(
16411                            SelectionEffects::no_scroll(),
16412                            window,
16413                            cx,
16414                            |selections| {
16415                                selections.clear_disjoint();
16416                                selections
16417                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16418                            },
16419                        );
16420                    }
16421                    editor.highlight_background::<Self>(
16422                        &ranges,
16423                        |theme| theme.colors().editor_highlighted_line_background,
16424                        cx,
16425                    );
16426                }
16427                MultibufferSelectionMode::All => {
16428                    editor.change_selections(
16429                        SelectionEffects::no_scroll(),
16430                        window,
16431                        cx,
16432                        |selections| {
16433                            selections.clear_disjoint();
16434                            selections.select_anchor_ranges(ranges);
16435                        },
16436                    );
16437                }
16438            }
16439            editor.register_buffers_with_language_servers(cx);
16440        });
16441
16442        let item = Box::new(editor);
16443        let item_id = item.item_id();
16444
16445        if split {
16446            workspace.split_item(SplitDirection::Right, item, window, cx);
16447        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16448            let (preview_item_id, preview_item_idx) =
16449                workspace.active_pane().read_with(cx, |pane, _| {
16450                    (pane.preview_item_id(), pane.preview_item_idx())
16451                });
16452
16453            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16454
16455            if let Some(preview_item_id) = preview_item_id {
16456                workspace.active_pane().update(cx, |pane, cx| {
16457                    pane.remove_item(preview_item_id, false, false, window, cx);
16458                });
16459            }
16460        } else {
16461            workspace.add_item_to_active_pane(item, None, true, window, cx);
16462        }
16463        workspace.active_pane().update(cx, |pane, cx| {
16464            pane.set_preview_item_id(Some(item_id), cx);
16465        });
16466    }
16467
16468    pub fn rename(
16469        &mut self,
16470        _: &Rename,
16471        window: &mut Window,
16472        cx: &mut Context<Self>,
16473    ) -> Option<Task<Result<()>>> {
16474        use language::ToOffset as _;
16475
16476        let provider = self.semantics_provider.clone()?;
16477        let selection = self.selections.newest_anchor().clone();
16478        let (cursor_buffer, cursor_buffer_position) = self
16479            .buffer
16480            .read(cx)
16481            .text_anchor_for_position(selection.head(), cx)?;
16482        let (tail_buffer, cursor_buffer_position_end) = self
16483            .buffer
16484            .read(cx)
16485            .text_anchor_for_position(selection.tail(), cx)?;
16486        if tail_buffer != cursor_buffer {
16487            return None;
16488        }
16489
16490        let snapshot = cursor_buffer.read(cx).snapshot();
16491        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16492        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16493        let prepare_rename = provider
16494            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16495            .unwrap_or_else(|| Task::ready(Ok(None)));
16496        drop(snapshot);
16497
16498        Some(cx.spawn_in(window, async move |this, cx| {
16499            let rename_range = if let Some(range) = prepare_rename.await? {
16500                Some(range)
16501            } else {
16502                this.update(cx, |this, cx| {
16503                    let buffer = this.buffer.read(cx).snapshot(cx);
16504                    let mut buffer_highlights = this
16505                        .document_highlights_for_position(selection.head(), &buffer)
16506                        .filter(|highlight| {
16507                            highlight.start.excerpt_id == selection.head().excerpt_id
16508                                && highlight.end.excerpt_id == selection.head().excerpt_id
16509                        });
16510                    buffer_highlights
16511                        .next()
16512                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16513                })?
16514            };
16515            if let Some(rename_range) = rename_range {
16516                this.update_in(cx, |this, window, cx| {
16517                    let snapshot = cursor_buffer.read(cx).snapshot();
16518                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16519                    let cursor_offset_in_rename_range =
16520                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16521                    let cursor_offset_in_rename_range_end =
16522                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16523
16524                    this.take_rename(false, window, cx);
16525                    let buffer = this.buffer.read(cx).read(cx);
16526                    let cursor_offset = selection.head().to_offset(&buffer);
16527                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16528                    let rename_end = rename_start + rename_buffer_range.len();
16529                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16530                    let mut old_highlight_id = None;
16531                    let old_name: Arc<str> = buffer
16532                        .chunks(rename_start..rename_end, true)
16533                        .map(|chunk| {
16534                            if old_highlight_id.is_none() {
16535                                old_highlight_id = chunk.syntax_highlight_id;
16536                            }
16537                            chunk.text
16538                        })
16539                        .collect::<String>()
16540                        .into();
16541
16542                    drop(buffer);
16543
16544                    // Position the selection in the rename editor so that it matches the current selection.
16545                    this.show_local_selections = false;
16546                    let rename_editor = cx.new(|cx| {
16547                        let mut editor = Editor::single_line(window, cx);
16548                        editor.buffer.update(cx, |buffer, cx| {
16549                            buffer.edit([(0..0, old_name.clone())], None, cx)
16550                        });
16551                        let rename_selection_range = match cursor_offset_in_rename_range
16552                            .cmp(&cursor_offset_in_rename_range_end)
16553                        {
16554                            Ordering::Equal => {
16555                                editor.select_all(&SelectAll, window, cx);
16556                                return editor;
16557                            }
16558                            Ordering::Less => {
16559                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16560                            }
16561                            Ordering::Greater => {
16562                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16563                            }
16564                        };
16565                        if rename_selection_range.end > old_name.len() {
16566                            editor.select_all(&SelectAll, window, cx);
16567                        } else {
16568                            editor.change_selections(Default::default(), window, cx, |s| {
16569                                s.select_ranges([rename_selection_range]);
16570                            });
16571                        }
16572                        editor
16573                    });
16574                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16575                        if e == &EditorEvent::Focused {
16576                            cx.emit(EditorEvent::FocusedIn)
16577                        }
16578                    })
16579                    .detach();
16580
16581                    let write_highlights =
16582                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16583                    let read_highlights =
16584                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16585                    let ranges = write_highlights
16586                        .iter()
16587                        .flat_map(|(_, ranges)| ranges.iter())
16588                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16589                        .cloned()
16590                        .collect();
16591
16592                    this.highlight_text::<Rename>(
16593                        ranges,
16594                        HighlightStyle {
16595                            fade_out: Some(0.6),
16596                            ..Default::default()
16597                        },
16598                        cx,
16599                    );
16600                    let rename_focus_handle = rename_editor.focus_handle(cx);
16601                    window.focus(&rename_focus_handle);
16602                    let block_id = this.insert_blocks(
16603                        [BlockProperties {
16604                            style: BlockStyle::Flex,
16605                            placement: BlockPlacement::Below(range.start),
16606                            height: Some(1),
16607                            render: Arc::new({
16608                                let rename_editor = rename_editor.clone();
16609                                move |cx: &mut BlockContext| {
16610                                    let mut text_style = cx.editor_style.text.clone();
16611                                    if let Some(highlight_style) = old_highlight_id
16612                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16613                                    {
16614                                        text_style = text_style.highlight(highlight_style);
16615                                    }
16616                                    div()
16617                                        .block_mouse_except_scroll()
16618                                        .pl(cx.anchor_x)
16619                                        .child(EditorElement::new(
16620                                            &rename_editor,
16621                                            EditorStyle {
16622                                                background: cx.theme().system().transparent,
16623                                                local_player: cx.editor_style.local_player,
16624                                                text: text_style,
16625                                                scrollbar_width: cx.editor_style.scrollbar_width,
16626                                                syntax: cx.editor_style.syntax.clone(),
16627                                                status: cx.editor_style.status.clone(),
16628                                                inlay_hints_style: HighlightStyle {
16629                                                    font_weight: Some(FontWeight::BOLD),
16630                                                    ..make_inlay_hints_style(cx.app)
16631                                                },
16632                                                edit_prediction_styles: make_suggestion_styles(
16633                                                    cx.app,
16634                                                ),
16635                                                ..EditorStyle::default()
16636                                            },
16637                                        ))
16638                                        .into_any_element()
16639                                }
16640                            }),
16641                            priority: 0,
16642                        }],
16643                        Some(Autoscroll::fit()),
16644                        cx,
16645                    )[0];
16646                    this.pending_rename = Some(RenameState {
16647                        range,
16648                        old_name,
16649                        editor: rename_editor,
16650                        block_id,
16651                    });
16652                })?;
16653            }
16654
16655            Ok(())
16656        }))
16657    }
16658
16659    pub fn confirm_rename(
16660        &mut self,
16661        _: &ConfirmRename,
16662        window: &mut Window,
16663        cx: &mut Context<Self>,
16664    ) -> Option<Task<Result<()>>> {
16665        let rename = self.take_rename(false, window, cx)?;
16666        let workspace = self.workspace()?.downgrade();
16667        let (buffer, start) = self
16668            .buffer
16669            .read(cx)
16670            .text_anchor_for_position(rename.range.start, cx)?;
16671        let (end_buffer, _) = self
16672            .buffer
16673            .read(cx)
16674            .text_anchor_for_position(rename.range.end, cx)?;
16675        if buffer != end_buffer {
16676            return None;
16677        }
16678
16679        let old_name = rename.old_name;
16680        let new_name = rename.editor.read(cx).text(cx);
16681
16682        let rename = self.semantics_provider.as_ref()?.perform_rename(
16683            &buffer,
16684            start,
16685            new_name.clone(),
16686            cx,
16687        )?;
16688
16689        Some(cx.spawn_in(window, async move |editor, cx| {
16690            let project_transaction = rename.await?;
16691            Self::open_project_transaction(
16692                &editor,
16693                workspace,
16694                project_transaction,
16695                format!("Rename: {}{}", old_name, new_name),
16696                cx,
16697            )
16698            .await?;
16699
16700            editor.update(cx, |editor, cx| {
16701                editor.refresh_document_highlights(cx);
16702            })?;
16703            Ok(())
16704        }))
16705    }
16706
16707    fn take_rename(
16708        &mut self,
16709        moving_cursor: bool,
16710        window: &mut Window,
16711        cx: &mut Context<Self>,
16712    ) -> Option<RenameState> {
16713        let rename = self.pending_rename.take()?;
16714        if rename.editor.focus_handle(cx).is_focused(window) {
16715            window.focus(&self.focus_handle);
16716        }
16717
16718        self.remove_blocks(
16719            [rename.block_id].into_iter().collect(),
16720            Some(Autoscroll::fit()),
16721            cx,
16722        );
16723        self.clear_highlights::<Rename>(cx);
16724        self.show_local_selections = true;
16725
16726        if moving_cursor {
16727            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16728                editor.selections.newest::<usize>(cx).head()
16729            });
16730
16731            // Update the selection to match the position of the selection inside
16732            // the rename editor.
16733            let snapshot = self.buffer.read(cx).read(cx);
16734            let rename_range = rename.range.to_offset(&snapshot);
16735            let cursor_in_editor = snapshot
16736                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16737                .min(rename_range.end);
16738            drop(snapshot);
16739
16740            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16741                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16742            });
16743        } else {
16744            self.refresh_document_highlights(cx);
16745        }
16746
16747        Some(rename)
16748    }
16749
16750    pub fn pending_rename(&self) -> Option<&RenameState> {
16751        self.pending_rename.as_ref()
16752    }
16753
16754    fn format(
16755        &mut self,
16756        _: &Format,
16757        window: &mut Window,
16758        cx: &mut Context<Self>,
16759    ) -> Option<Task<Result<()>>> {
16760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16761
16762        let project = match &self.project {
16763            Some(project) => project.clone(),
16764            None => return None,
16765        };
16766
16767        Some(self.perform_format(
16768            project,
16769            FormatTrigger::Manual,
16770            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16771            window,
16772            cx,
16773        ))
16774    }
16775
16776    fn format_selections(
16777        &mut self,
16778        _: &FormatSelections,
16779        window: &mut Window,
16780        cx: &mut Context<Self>,
16781    ) -> Option<Task<Result<()>>> {
16782        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16783
16784        let project = match &self.project {
16785            Some(project) => project.clone(),
16786            None => return None,
16787        };
16788
16789        let ranges = self
16790            .selections
16791            .all_adjusted(cx)
16792            .into_iter()
16793            .map(|selection| selection.range())
16794            .collect_vec();
16795
16796        Some(self.perform_format(
16797            project,
16798            FormatTrigger::Manual,
16799            FormatTarget::Ranges(ranges),
16800            window,
16801            cx,
16802        ))
16803    }
16804
16805    fn perform_format(
16806        &mut self,
16807        project: Entity<Project>,
16808        trigger: FormatTrigger,
16809        target: FormatTarget,
16810        window: &mut Window,
16811        cx: &mut Context<Self>,
16812    ) -> Task<Result<()>> {
16813        let buffer = self.buffer.clone();
16814        let (buffers, target) = match target {
16815            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16816            FormatTarget::Ranges(selection_ranges) => {
16817                let multi_buffer = buffer.read(cx);
16818                let snapshot = multi_buffer.read(cx);
16819                let mut buffers = HashSet::default();
16820                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16821                    BTreeMap::new();
16822                for selection_range in selection_ranges {
16823                    for (buffer, buffer_range, _) in
16824                        snapshot.range_to_buffer_ranges(selection_range)
16825                    {
16826                        let buffer_id = buffer.remote_id();
16827                        let start = buffer.anchor_before(buffer_range.start);
16828                        let end = buffer.anchor_after(buffer_range.end);
16829                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16830                        buffer_id_to_ranges
16831                            .entry(buffer_id)
16832                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16833                            .or_insert_with(|| vec![start..end]);
16834                    }
16835                }
16836                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16837            }
16838        };
16839
16840        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16841        let selections_prev = transaction_id_prev
16842            .and_then(|transaction_id_prev| {
16843                // default to selections as they were after the last edit, if we have them,
16844                // instead of how they are now.
16845                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16846                // will take you back to where you made the last edit, instead of staying where you scrolled
16847                self.selection_history
16848                    .transaction(transaction_id_prev)
16849                    .map(|t| t.0.clone())
16850            })
16851            .unwrap_or_else(|| self.selections.disjoint_anchors());
16852
16853        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16854        let format = project.update(cx, |project, cx| {
16855            project.format(buffers, target, true, trigger, cx)
16856        });
16857
16858        cx.spawn_in(window, async move |editor, cx| {
16859            let transaction = futures::select_biased! {
16860                transaction = format.log_err().fuse() => transaction,
16861                () = timeout => {
16862                    log::warn!("timed out waiting for formatting");
16863                    None
16864                }
16865            };
16866
16867            buffer
16868                .update(cx, |buffer, cx| {
16869                    if let Some(transaction) = transaction
16870                        && !buffer.is_singleton()
16871                    {
16872                        buffer.push_transaction(&transaction.0, cx);
16873                    }
16874                    cx.notify();
16875                })
16876                .ok();
16877
16878            if let Some(transaction_id_now) =
16879                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16880            {
16881                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16882                if has_new_transaction {
16883                    _ = editor.update(cx, |editor, _| {
16884                        editor
16885                            .selection_history
16886                            .insert_transaction(transaction_id_now, selections_prev);
16887                    });
16888                }
16889            }
16890
16891            Ok(())
16892        })
16893    }
16894
16895    fn organize_imports(
16896        &mut self,
16897        _: &OrganizeImports,
16898        window: &mut Window,
16899        cx: &mut Context<Self>,
16900    ) -> Option<Task<Result<()>>> {
16901        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16902        let project = match &self.project {
16903            Some(project) => project.clone(),
16904            None => return None,
16905        };
16906        Some(self.perform_code_action_kind(
16907            project,
16908            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16909            window,
16910            cx,
16911        ))
16912    }
16913
16914    fn perform_code_action_kind(
16915        &mut self,
16916        project: Entity<Project>,
16917        kind: CodeActionKind,
16918        window: &mut Window,
16919        cx: &mut Context<Self>,
16920    ) -> Task<Result<()>> {
16921        let buffer = self.buffer.clone();
16922        let buffers = buffer.read(cx).all_buffers();
16923        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16924        let apply_action = project.update(cx, |project, cx| {
16925            project.apply_code_action_kind(buffers, kind, true, cx)
16926        });
16927        cx.spawn_in(window, async move |_, cx| {
16928            let transaction = futures::select_biased! {
16929                () = timeout => {
16930                    log::warn!("timed out waiting for executing code action");
16931                    None
16932                }
16933                transaction = apply_action.log_err().fuse() => transaction,
16934            };
16935            buffer
16936                .update(cx, |buffer, cx| {
16937                    // check if we need this
16938                    if let Some(transaction) = transaction
16939                        && !buffer.is_singleton()
16940                    {
16941                        buffer.push_transaction(&transaction.0, cx);
16942                    }
16943                    cx.notify();
16944                })
16945                .ok();
16946            Ok(())
16947        })
16948    }
16949
16950    pub fn restart_language_server(
16951        &mut self,
16952        _: &RestartLanguageServer,
16953        _: &mut Window,
16954        cx: &mut Context<Self>,
16955    ) {
16956        if let Some(project) = self.project.clone() {
16957            self.buffer.update(cx, |multi_buffer, cx| {
16958                project.update(cx, |project, cx| {
16959                    project.restart_language_servers_for_buffers(
16960                        multi_buffer.all_buffers().into_iter().collect(),
16961                        HashSet::default(),
16962                        cx,
16963                    );
16964                });
16965            })
16966        }
16967    }
16968
16969    pub fn stop_language_server(
16970        &mut self,
16971        _: &StopLanguageServer,
16972        _: &mut Window,
16973        cx: &mut Context<Self>,
16974    ) {
16975        if let Some(project) = self.project.clone() {
16976            self.buffer.update(cx, |multi_buffer, cx| {
16977                project.update(cx, |project, cx| {
16978                    project.stop_language_servers_for_buffers(
16979                        multi_buffer.all_buffers().into_iter().collect(),
16980                        HashSet::default(),
16981                        cx,
16982                    );
16983                    cx.emit(project::Event::RefreshInlayHints);
16984                });
16985            });
16986        }
16987    }
16988
16989    fn cancel_language_server_work(
16990        workspace: &mut Workspace,
16991        _: &actions::CancelLanguageServerWork,
16992        _: &mut Window,
16993        cx: &mut Context<Workspace>,
16994    ) {
16995        let project = workspace.project();
16996        let buffers = workspace
16997            .active_item(cx)
16998            .and_then(|item| item.act_as::<Editor>(cx))
16999            .map_or(HashSet::default(), |editor| {
17000                editor.read(cx).buffer.read(cx).all_buffers()
17001            });
17002        project.update(cx, |project, cx| {
17003            project.cancel_language_server_work_for_buffers(buffers, cx);
17004        });
17005    }
17006
17007    fn show_character_palette(
17008        &mut self,
17009        _: &ShowCharacterPalette,
17010        window: &mut Window,
17011        _: &mut Context<Self>,
17012    ) {
17013        window.show_character_palette();
17014    }
17015
17016    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17017        if !self.diagnostics_enabled() {
17018            return;
17019        }
17020
17021        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17022            let buffer = self.buffer.read(cx).snapshot(cx);
17023            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17024            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17025            let is_valid = buffer
17026                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17027                .any(|entry| {
17028                    entry.diagnostic.is_primary
17029                        && !entry.range.is_empty()
17030                        && entry.range.start == primary_range_start
17031                        && entry.diagnostic.message == active_diagnostics.active_message
17032                });
17033
17034            if !is_valid {
17035                self.dismiss_diagnostics(cx);
17036            }
17037        }
17038    }
17039
17040    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17041        match &self.active_diagnostics {
17042            ActiveDiagnostic::Group(group) => Some(group),
17043            _ => None,
17044        }
17045    }
17046
17047    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17048        if !self.diagnostics_enabled() {
17049            return;
17050        }
17051        self.dismiss_diagnostics(cx);
17052        self.active_diagnostics = ActiveDiagnostic::All;
17053    }
17054
17055    fn activate_diagnostics(
17056        &mut self,
17057        buffer_id: BufferId,
17058        diagnostic: DiagnosticEntry<usize>,
17059        window: &mut Window,
17060        cx: &mut Context<Self>,
17061    ) {
17062        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17063            return;
17064        }
17065        self.dismiss_diagnostics(cx);
17066        let snapshot = self.snapshot(window, cx);
17067        let buffer = self.buffer.read(cx).snapshot(cx);
17068        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17069            return;
17070        };
17071
17072        let diagnostic_group = buffer
17073            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17074            .collect::<Vec<_>>();
17075
17076        let blocks =
17077            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17078
17079        let blocks = self.display_map.update(cx, |display_map, cx| {
17080            display_map.insert_blocks(blocks, cx).into_iter().collect()
17081        });
17082        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17083            active_range: buffer.anchor_before(diagnostic.range.start)
17084                ..buffer.anchor_after(diagnostic.range.end),
17085            active_message: diagnostic.diagnostic.message.clone(),
17086            group_id: diagnostic.diagnostic.group_id,
17087            blocks,
17088        });
17089        cx.notify();
17090    }
17091
17092    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17093        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17094            return;
17095        };
17096
17097        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17098        if let ActiveDiagnostic::Group(group) = prev {
17099            self.display_map.update(cx, |display_map, cx| {
17100                display_map.remove_blocks(group.blocks, cx);
17101            });
17102            cx.notify();
17103        }
17104    }
17105
17106    /// Disable inline diagnostics rendering for this editor.
17107    pub fn disable_inline_diagnostics(&mut self) {
17108        self.inline_diagnostics_enabled = false;
17109        self.inline_diagnostics_update = Task::ready(());
17110        self.inline_diagnostics.clear();
17111    }
17112
17113    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17114        self.diagnostics_enabled = false;
17115        self.dismiss_diagnostics(cx);
17116        self.inline_diagnostics_update = Task::ready(());
17117        self.inline_diagnostics.clear();
17118    }
17119
17120    pub fn diagnostics_enabled(&self) -> bool {
17121        self.diagnostics_enabled && self.mode.is_full()
17122    }
17123
17124    pub fn inline_diagnostics_enabled(&self) -> bool {
17125        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17126    }
17127
17128    pub fn show_inline_diagnostics(&self) -> bool {
17129        self.show_inline_diagnostics
17130    }
17131
17132    pub fn toggle_inline_diagnostics(
17133        &mut self,
17134        _: &ToggleInlineDiagnostics,
17135        window: &mut Window,
17136        cx: &mut Context<Editor>,
17137    ) {
17138        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17139        self.refresh_inline_diagnostics(false, window, cx);
17140    }
17141
17142    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17143        self.diagnostics_max_severity = severity;
17144        self.display_map.update(cx, |display_map, _| {
17145            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17146        });
17147    }
17148
17149    pub fn toggle_diagnostics(
17150        &mut self,
17151        _: &ToggleDiagnostics,
17152        window: &mut Window,
17153        cx: &mut Context<Editor>,
17154    ) {
17155        if !self.diagnostics_enabled() {
17156            return;
17157        }
17158
17159        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17160            EditorSettings::get_global(cx)
17161                .diagnostics_max_severity
17162                .filter(|severity| severity != &DiagnosticSeverity::Off)
17163                .unwrap_or(DiagnosticSeverity::Hint)
17164        } else {
17165            DiagnosticSeverity::Off
17166        };
17167        self.set_max_diagnostics_severity(new_severity, cx);
17168        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17169            self.active_diagnostics = ActiveDiagnostic::None;
17170            self.inline_diagnostics_update = Task::ready(());
17171            self.inline_diagnostics.clear();
17172        } else {
17173            self.refresh_inline_diagnostics(false, window, cx);
17174        }
17175
17176        cx.notify();
17177    }
17178
17179    pub fn toggle_minimap(
17180        &mut self,
17181        _: &ToggleMinimap,
17182        window: &mut Window,
17183        cx: &mut Context<Editor>,
17184    ) {
17185        if self.supports_minimap(cx) {
17186            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17187        }
17188    }
17189
17190    fn refresh_inline_diagnostics(
17191        &mut self,
17192        debounce: bool,
17193        window: &mut Window,
17194        cx: &mut Context<Self>,
17195    ) {
17196        let max_severity = ProjectSettings::get_global(cx)
17197            .diagnostics
17198            .inline
17199            .max_severity
17200            .unwrap_or(self.diagnostics_max_severity);
17201
17202        if !self.inline_diagnostics_enabled()
17203            || !self.show_inline_diagnostics
17204            || max_severity == DiagnosticSeverity::Off
17205        {
17206            self.inline_diagnostics_update = Task::ready(());
17207            self.inline_diagnostics.clear();
17208            return;
17209        }
17210
17211        let debounce_ms = ProjectSettings::get_global(cx)
17212            .diagnostics
17213            .inline
17214            .update_debounce_ms;
17215        let debounce = if debounce && debounce_ms > 0 {
17216            Some(Duration::from_millis(debounce_ms))
17217        } else {
17218            None
17219        };
17220        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17221            if let Some(debounce) = debounce {
17222                cx.background_executor().timer(debounce).await;
17223            }
17224            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17225                editor
17226                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17227                    .ok()
17228            }) else {
17229                return;
17230            };
17231
17232            let new_inline_diagnostics = cx
17233                .background_spawn(async move {
17234                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17235                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17236                        let message = diagnostic_entry
17237                            .diagnostic
17238                            .message
17239                            .split_once('\n')
17240                            .map(|(line, _)| line)
17241                            .map(SharedString::new)
17242                            .unwrap_or_else(|| {
17243                                SharedString::from(diagnostic_entry.diagnostic.message)
17244                            });
17245                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17246                        let (Ok(i) | Err(i)) = inline_diagnostics
17247                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17248                        inline_diagnostics.insert(
17249                            i,
17250                            (
17251                                start_anchor,
17252                                InlineDiagnostic {
17253                                    message,
17254                                    group_id: diagnostic_entry.diagnostic.group_id,
17255                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17256                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17257                                    severity: diagnostic_entry.diagnostic.severity,
17258                                },
17259                            ),
17260                        );
17261                    }
17262                    inline_diagnostics
17263                })
17264                .await;
17265
17266            editor
17267                .update(cx, |editor, cx| {
17268                    editor.inline_diagnostics = new_inline_diagnostics;
17269                    cx.notify();
17270                })
17271                .ok();
17272        });
17273    }
17274
17275    fn pull_diagnostics(
17276        &mut self,
17277        buffer_id: Option<BufferId>,
17278        window: &Window,
17279        cx: &mut Context<Self>,
17280    ) -> Option<()> {
17281        if !self.mode().is_full() {
17282            return None;
17283        }
17284        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17285            .diagnostics
17286            .lsp_pull_diagnostics;
17287        if !pull_diagnostics_settings.enabled {
17288            return None;
17289        }
17290        let project = self.project()?.downgrade();
17291        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17292        let mut buffers = self.buffer.read(cx).all_buffers();
17293        if let Some(buffer_id) = buffer_id {
17294            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17295        }
17296
17297        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17298            cx.background_executor().timer(debounce).await;
17299
17300            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17301                buffers
17302                    .into_iter()
17303                    .filter_map(|buffer| {
17304                        project
17305                            .update(cx, |project, cx| {
17306                                project.lsp_store().update(cx, |lsp_store, cx| {
17307                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17308                                })
17309                            })
17310                            .ok()
17311                    })
17312                    .collect::<FuturesUnordered<_>>()
17313            }) else {
17314                return;
17315            };
17316
17317            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17318                match pull_task {
17319                    Ok(()) => {
17320                        if editor
17321                            .update_in(cx, |editor, window, cx| {
17322                                editor.update_diagnostics_state(window, cx);
17323                            })
17324                            .is_err()
17325                        {
17326                            return;
17327                        }
17328                    }
17329                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17330                }
17331            }
17332        });
17333
17334        Some(())
17335    }
17336
17337    pub fn set_selections_from_remote(
17338        &mut self,
17339        selections: Vec<Selection<Anchor>>,
17340        pending_selection: Option<Selection<Anchor>>,
17341        window: &mut Window,
17342        cx: &mut Context<Self>,
17343    ) {
17344        let old_cursor_position = self.selections.newest_anchor().head();
17345        self.selections.change_with(cx, |s| {
17346            s.select_anchors(selections);
17347            if let Some(pending_selection) = pending_selection {
17348                s.set_pending(pending_selection, SelectMode::Character);
17349            } else {
17350                s.clear_pending();
17351            }
17352        });
17353        self.selections_did_change(
17354            false,
17355            &old_cursor_position,
17356            SelectionEffects::default(),
17357            window,
17358            cx,
17359        );
17360    }
17361
17362    pub fn transact(
17363        &mut self,
17364        window: &mut Window,
17365        cx: &mut Context<Self>,
17366        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17367    ) -> Option<TransactionId> {
17368        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17369            this.start_transaction_at(Instant::now(), window, cx);
17370            update(this, window, cx);
17371            this.end_transaction_at(Instant::now(), cx)
17372        })
17373    }
17374
17375    pub fn start_transaction_at(
17376        &mut self,
17377        now: Instant,
17378        window: &mut Window,
17379        cx: &mut Context<Self>,
17380    ) -> Option<TransactionId> {
17381        self.end_selection(window, cx);
17382        if let Some(tx_id) = self
17383            .buffer
17384            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17385        {
17386            self.selection_history
17387                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17388            cx.emit(EditorEvent::TransactionBegun {
17389                transaction_id: tx_id,
17390            });
17391            Some(tx_id)
17392        } else {
17393            None
17394        }
17395    }
17396
17397    pub fn end_transaction_at(
17398        &mut self,
17399        now: Instant,
17400        cx: &mut Context<Self>,
17401    ) -> Option<TransactionId> {
17402        if let Some(transaction_id) = self
17403            .buffer
17404            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17405        {
17406            if let Some((_, end_selections)) =
17407                self.selection_history.transaction_mut(transaction_id)
17408            {
17409                *end_selections = Some(self.selections.disjoint_anchors());
17410            } else {
17411                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17412            }
17413
17414            cx.emit(EditorEvent::Edited { transaction_id });
17415            Some(transaction_id)
17416        } else {
17417            None
17418        }
17419    }
17420
17421    pub fn modify_transaction_selection_history(
17422        &mut self,
17423        transaction_id: TransactionId,
17424        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17425    ) -> bool {
17426        self.selection_history
17427            .transaction_mut(transaction_id)
17428            .map(modify)
17429            .is_some()
17430    }
17431
17432    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17433        if self.selection_mark_mode {
17434            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17435                s.move_with(|_, sel| {
17436                    sel.collapse_to(sel.head(), SelectionGoal::None);
17437                });
17438            })
17439        }
17440        self.selection_mark_mode = true;
17441        cx.notify();
17442    }
17443
17444    pub fn swap_selection_ends(
17445        &mut self,
17446        _: &actions::SwapSelectionEnds,
17447        window: &mut Window,
17448        cx: &mut Context<Self>,
17449    ) {
17450        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17451            s.move_with(|_, sel| {
17452                if sel.start != sel.end {
17453                    sel.reversed = !sel.reversed
17454                }
17455            });
17456        });
17457        self.request_autoscroll(Autoscroll::newest(), cx);
17458        cx.notify();
17459    }
17460
17461    pub fn toggle_focus(
17462        workspace: &mut Workspace,
17463        _: &actions::ToggleFocus,
17464        window: &mut Window,
17465        cx: &mut Context<Workspace>,
17466    ) {
17467        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17468            return;
17469        };
17470        workspace.activate_item(&item, true, true, window, cx);
17471    }
17472
17473    pub fn toggle_fold(
17474        &mut self,
17475        _: &actions::ToggleFold,
17476        window: &mut Window,
17477        cx: &mut Context<Self>,
17478    ) {
17479        if self.is_singleton(cx) {
17480            let selection = self.selections.newest::<Point>(cx);
17481
17482            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17483            let range = if selection.is_empty() {
17484                let point = selection.head().to_display_point(&display_map);
17485                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17486                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17487                    .to_point(&display_map);
17488                start..end
17489            } else {
17490                selection.range()
17491            };
17492            if display_map.folds_in_range(range).next().is_some() {
17493                self.unfold_lines(&Default::default(), window, cx)
17494            } else {
17495                self.fold(&Default::default(), window, cx)
17496            }
17497        } else {
17498            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17499            let buffer_ids: HashSet<_> = self
17500                .selections
17501                .disjoint_anchor_ranges()
17502                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17503                .collect();
17504
17505            let should_unfold = buffer_ids
17506                .iter()
17507                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17508
17509            for buffer_id in buffer_ids {
17510                if should_unfold {
17511                    self.unfold_buffer(buffer_id, cx);
17512                } else {
17513                    self.fold_buffer(buffer_id, cx);
17514                }
17515            }
17516        }
17517    }
17518
17519    pub fn toggle_fold_recursive(
17520        &mut self,
17521        _: &actions::ToggleFoldRecursive,
17522        window: &mut Window,
17523        cx: &mut Context<Self>,
17524    ) {
17525        let selection = self.selections.newest::<Point>(cx);
17526
17527        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17528        let range = if selection.is_empty() {
17529            let point = selection.head().to_display_point(&display_map);
17530            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17531            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17532                .to_point(&display_map);
17533            start..end
17534        } else {
17535            selection.range()
17536        };
17537        if display_map.folds_in_range(range).next().is_some() {
17538            self.unfold_recursive(&Default::default(), window, cx)
17539        } else {
17540            self.fold_recursive(&Default::default(), window, cx)
17541        }
17542    }
17543
17544    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17545        if self.is_singleton(cx) {
17546            let mut to_fold = Vec::new();
17547            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17548            let selections = self.selections.all_adjusted(cx);
17549
17550            for selection in selections {
17551                let range = selection.range().sorted();
17552                let buffer_start_row = range.start.row;
17553
17554                if range.start.row != range.end.row {
17555                    let mut found = false;
17556                    let mut row = range.start.row;
17557                    while row <= range.end.row {
17558                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17559                        {
17560                            found = true;
17561                            row = crease.range().end.row + 1;
17562                            to_fold.push(crease);
17563                        } else {
17564                            row += 1
17565                        }
17566                    }
17567                    if found {
17568                        continue;
17569                    }
17570                }
17571
17572                for row in (0..=range.start.row).rev() {
17573                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17574                        && crease.range().end.row >= buffer_start_row
17575                    {
17576                        to_fold.push(crease);
17577                        if row <= range.start.row {
17578                            break;
17579                        }
17580                    }
17581                }
17582            }
17583
17584            self.fold_creases(to_fold, true, window, cx);
17585        } else {
17586            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17587            let buffer_ids = self
17588                .selections
17589                .disjoint_anchor_ranges()
17590                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17591                .collect::<HashSet<_>>();
17592            for buffer_id in buffer_ids {
17593                self.fold_buffer(buffer_id, cx);
17594            }
17595        }
17596    }
17597
17598    pub fn toggle_fold_all(
17599        &mut self,
17600        _: &actions::ToggleFoldAll,
17601        window: &mut Window,
17602        cx: &mut Context<Self>,
17603    ) {
17604        if self.buffer.read(cx).is_singleton() {
17605            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17606            let has_folds = display_map
17607                .folds_in_range(0..display_map.buffer_snapshot.len())
17608                .next()
17609                .is_some();
17610
17611            if has_folds {
17612                self.unfold_all(&actions::UnfoldAll, window, cx);
17613            } else {
17614                self.fold_all(&actions::FoldAll, window, cx);
17615            }
17616        } else {
17617            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17618            let should_unfold = buffer_ids
17619                .iter()
17620                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17621
17622            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17623                editor
17624                    .update_in(cx, |editor, _, cx| {
17625                        for buffer_id in buffer_ids {
17626                            if should_unfold {
17627                                editor.unfold_buffer(buffer_id, cx);
17628                            } else {
17629                                editor.fold_buffer(buffer_id, cx);
17630                            }
17631                        }
17632                    })
17633                    .ok();
17634            });
17635        }
17636    }
17637
17638    fn fold_at_level(
17639        &mut self,
17640        fold_at: &FoldAtLevel,
17641        window: &mut Window,
17642        cx: &mut Context<Self>,
17643    ) {
17644        if !self.buffer.read(cx).is_singleton() {
17645            return;
17646        }
17647
17648        let fold_at_level = fold_at.0;
17649        let snapshot = self.buffer.read(cx).snapshot(cx);
17650        let mut to_fold = Vec::new();
17651        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17652
17653        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17654            while start_row < end_row {
17655                match self
17656                    .snapshot(window, cx)
17657                    .crease_for_buffer_row(MultiBufferRow(start_row))
17658                {
17659                    Some(crease) => {
17660                        let nested_start_row = crease.range().start.row + 1;
17661                        let nested_end_row = crease.range().end.row;
17662
17663                        if current_level < fold_at_level {
17664                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17665                        } else if current_level == fold_at_level {
17666                            to_fold.push(crease);
17667                        }
17668
17669                        start_row = nested_end_row + 1;
17670                    }
17671                    None => start_row += 1,
17672                }
17673            }
17674        }
17675
17676        self.fold_creases(to_fold, true, window, cx);
17677    }
17678
17679    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17680        if self.buffer.read(cx).is_singleton() {
17681            let mut fold_ranges = Vec::new();
17682            let snapshot = self.buffer.read(cx).snapshot(cx);
17683
17684            for row in 0..snapshot.max_row().0 {
17685                if let Some(foldable_range) = self
17686                    .snapshot(window, cx)
17687                    .crease_for_buffer_row(MultiBufferRow(row))
17688                {
17689                    fold_ranges.push(foldable_range);
17690                }
17691            }
17692
17693            self.fold_creases(fold_ranges, true, window, cx);
17694        } else {
17695            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17696                editor
17697                    .update_in(cx, |editor, _, cx| {
17698                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17699                            editor.fold_buffer(buffer_id, cx);
17700                        }
17701                    })
17702                    .ok();
17703            });
17704        }
17705    }
17706
17707    pub fn fold_function_bodies(
17708        &mut self,
17709        _: &actions::FoldFunctionBodies,
17710        window: &mut Window,
17711        cx: &mut Context<Self>,
17712    ) {
17713        let snapshot = self.buffer.read(cx).snapshot(cx);
17714
17715        let ranges = snapshot
17716            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17717            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17718            .collect::<Vec<_>>();
17719
17720        let creases = ranges
17721            .into_iter()
17722            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17723            .collect();
17724
17725        self.fold_creases(creases, true, window, cx);
17726    }
17727
17728    pub fn fold_recursive(
17729        &mut self,
17730        _: &actions::FoldRecursive,
17731        window: &mut Window,
17732        cx: &mut Context<Self>,
17733    ) {
17734        let mut to_fold = Vec::new();
17735        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17736        let selections = self.selections.all_adjusted(cx);
17737
17738        for selection in selections {
17739            let range = selection.range().sorted();
17740            let buffer_start_row = range.start.row;
17741
17742            if range.start.row != range.end.row {
17743                let mut found = false;
17744                for row in range.start.row..=range.end.row {
17745                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17746                        found = true;
17747                        to_fold.push(crease);
17748                    }
17749                }
17750                if found {
17751                    continue;
17752                }
17753            }
17754
17755            for row in (0..=range.start.row).rev() {
17756                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17757                    if crease.range().end.row >= buffer_start_row {
17758                        to_fold.push(crease);
17759                    } else {
17760                        break;
17761                    }
17762                }
17763            }
17764        }
17765
17766        self.fold_creases(to_fold, true, window, cx);
17767    }
17768
17769    pub fn fold_at(
17770        &mut self,
17771        buffer_row: MultiBufferRow,
17772        window: &mut Window,
17773        cx: &mut Context<Self>,
17774    ) {
17775        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17776
17777        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17778            let autoscroll = self
17779                .selections
17780                .all::<Point>(cx)
17781                .iter()
17782                .any(|selection| crease.range().overlaps(&selection.range()));
17783
17784            self.fold_creases(vec![crease], autoscroll, window, cx);
17785        }
17786    }
17787
17788    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17789        if self.is_singleton(cx) {
17790            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17791            let buffer = &display_map.buffer_snapshot;
17792            let selections = self.selections.all::<Point>(cx);
17793            let ranges = selections
17794                .iter()
17795                .map(|s| {
17796                    let range = s.display_range(&display_map).sorted();
17797                    let mut start = range.start.to_point(&display_map);
17798                    let mut end = range.end.to_point(&display_map);
17799                    start.column = 0;
17800                    end.column = buffer.line_len(MultiBufferRow(end.row));
17801                    start..end
17802                })
17803                .collect::<Vec<_>>();
17804
17805            self.unfold_ranges(&ranges, true, true, cx);
17806        } else {
17807            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17808            let buffer_ids = self
17809                .selections
17810                .disjoint_anchor_ranges()
17811                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17812                .collect::<HashSet<_>>();
17813            for buffer_id in buffer_ids {
17814                self.unfold_buffer(buffer_id, cx);
17815            }
17816        }
17817    }
17818
17819    pub fn unfold_recursive(
17820        &mut self,
17821        _: &UnfoldRecursive,
17822        _window: &mut Window,
17823        cx: &mut Context<Self>,
17824    ) {
17825        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17826        let selections = self.selections.all::<Point>(cx);
17827        let ranges = selections
17828            .iter()
17829            .map(|s| {
17830                let mut range = s.display_range(&display_map).sorted();
17831                *range.start.column_mut() = 0;
17832                *range.end.column_mut() = display_map.line_len(range.end.row());
17833                let start = range.start.to_point(&display_map);
17834                let end = range.end.to_point(&display_map);
17835                start..end
17836            })
17837            .collect::<Vec<_>>();
17838
17839        self.unfold_ranges(&ranges, true, true, cx);
17840    }
17841
17842    pub fn unfold_at(
17843        &mut self,
17844        buffer_row: MultiBufferRow,
17845        _window: &mut Window,
17846        cx: &mut Context<Self>,
17847    ) {
17848        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17849
17850        let intersection_range = Point::new(buffer_row.0, 0)
17851            ..Point::new(
17852                buffer_row.0,
17853                display_map.buffer_snapshot.line_len(buffer_row),
17854            );
17855
17856        let autoscroll = self
17857            .selections
17858            .all::<Point>(cx)
17859            .iter()
17860            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17861
17862        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17863    }
17864
17865    pub fn unfold_all(
17866        &mut self,
17867        _: &actions::UnfoldAll,
17868        _window: &mut Window,
17869        cx: &mut Context<Self>,
17870    ) {
17871        if self.buffer.read(cx).is_singleton() {
17872            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17873            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17874        } else {
17875            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17876                editor
17877                    .update(cx, |editor, cx| {
17878                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17879                            editor.unfold_buffer(buffer_id, cx);
17880                        }
17881                    })
17882                    .ok();
17883            });
17884        }
17885    }
17886
17887    pub fn fold_selected_ranges(
17888        &mut self,
17889        _: &FoldSelectedRanges,
17890        window: &mut Window,
17891        cx: &mut Context<Self>,
17892    ) {
17893        let selections = self.selections.all_adjusted(cx);
17894        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17895        let ranges = selections
17896            .into_iter()
17897            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17898            .collect::<Vec<_>>();
17899        self.fold_creases(ranges, true, window, cx);
17900    }
17901
17902    pub fn fold_ranges<T: ToOffset + Clone>(
17903        &mut self,
17904        ranges: Vec<Range<T>>,
17905        auto_scroll: bool,
17906        window: &mut Window,
17907        cx: &mut Context<Self>,
17908    ) {
17909        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17910        let ranges = ranges
17911            .into_iter()
17912            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17913            .collect::<Vec<_>>();
17914        self.fold_creases(ranges, auto_scroll, window, cx);
17915    }
17916
17917    pub fn fold_creases<T: ToOffset + Clone>(
17918        &mut self,
17919        creases: Vec<Crease<T>>,
17920        auto_scroll: bool,
17921        _window: &mut Window,
17922        cx: &mut Context<Self>,
17923    ) {
17924        if creases.is_empty() {
17925            return;
17926        }
17927
17928        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17929
17930        if auto_scroll {
17931            self.request_autoscroll(Autoscroll::fit(), cx);
17932        }
17933
17934        cx.notify();
17935
17936        self.scrollbar_marker_state.dirty = true;
17937        self.folds_did_change(cx);
17938    }
17939
17940    /// Removes any folds whose ranges intersect any of the given ranges.
17941    pub fn unfold_ranges<T: ToOffset + Clone>(
17942        &mut self,
17943        ranges: &[Range<T>],
17944        inclusive: bool,
17945        auto_scroll: bool,
17946        cx: &mut Context<Self>,
17947    ) {
17948        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17949            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17950        });
17951        self.folds_did_change(cx);
17952    }
17953
17954    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17955        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17956            return;
17957        }
17958        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17959        self.display_map.update(cx, |display_map, cx| {
17960            display_map.fold_buffers([buffer_id], cx)
17961        });
17962        cx.emit(EditorEvent::BufferFoldToggled {
17963            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17964            folded: true,
17965        });
17966        cx.notify();
17967    }
17968
17969    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17970        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17971            return;
17972        }
17973        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17974        self.display_map.update(cx, |display_map, cx| {
17975            display_map.unfold_buffers([buffer_id], cx);
17976        });
17977        cx.emit(EditorEvent::BufferFoldToggled {
17978            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17979            folded: false,
17980        });
17981        cx.notify();
17982    }
17983
17984    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17985        self.display_map.read(cx).is_buffer_folded(buffer)
17986    }
17987
17988    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17989        self.display_map.read(cx).folded_buffers()
17990    }
17991
17992    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17993        self.display_map.update(cx, |display_map, cx| {
17994            display_map.disable_header_for_buffer(buffer_id, cx);
17995        });
17996        cx.notify();
17997    }
17998
17999    /// Removes any folds with the given ranges.
18000    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18001        &mut self,
18002        ranges: &[Range<T>],
18003        type_id: TypeId,
18004        auto_scroll: bool,
18005        cx: &mut Context<Self>,
18006    ) {
18007        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18008            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18009        });
18010        self.folds_did_change(cx);
18011    }
18012
18013    fn remove_folds_with<T: ToOffset + Clone>(
18014        &mut self,
18015        ranges: &[Range<T>],
18016        auto_scroll: bool,
18017        cx: &mut Context<Self>,
18018        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18019    ) {
18020        if ranges.is_empty() {
18021            return;
18022        }
18023
18024        let mut buffers_affected = HashSet::default();
18025        let multi_buffer = self.buffer().read(cx);
18026        for range in ranges {
18027            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18028                buffers_affected.insert(buffer.read(cx).remote_id());
18029            };
18030        }
18031
18032        self.display_map.update(cx, update);
18033
18034        if auto_scroll {
18035            self.request_autoscroll(Autoscroll::fit(), cx);
18036        }
18037
18038        cx.notify();
18039        self.scrollbar_marker_state.dirty = true;
18040        self.active_indent_guides_state.dirty = true;
18041    }
18042
18043    pub fn update_renderer_widths(
18044        &mut self,
18045        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18046        cx: &mut Context<Self>,
18047    ) -> bool {
18048        self.display_map
18049            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18050    }
18051
18052    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18053        self.display_map.read(cx).fold_placeholder.clone()
18054    }
18055
18056    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18057        self.buffer.update(cx, |buffer, cx| {
18058            buffer.set_all_diff_hunks_expanded(cx);
18059        });
18060    }
18061
18062    pub fn expand_all_diff_hunks(
18063        &mut self,
18064        _: &ExpandAllDiffHunks,
18065        _window: &mut Window,
18066        cx: &mut Context<Self>,
18067    ) {
18068        self.buffer.update(cx, |buffer, cx| {
18069            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18070        });
18071    }
18072
18073    pub fn toggle_selected_diff_hunks(
18074        &mut self,
18075        _: &ToggleSelectedDiffHunks,
18076        _window: &mut Window,
18077        cx: &mut Context<Self>,
18078    ) {
18079        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18080        self.toggle_diff_hunks_in_ranges(ranges, cx);
18081    }
18082
18083    pub fn diff_hunks_in_ranges<'a>(
18084        &'a self,
18085        ranges: &'a [Range<Anchor>],
18086        buffer: &'a MultiBufferSnapshot,
18087    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18088        ranges.iter().flat_map(move |range| {
18089            let end_excerpt_id = range.end.excerpt_id;
18090            let range = range.to_point(buffer);
18091            let mut peek_end = range.end;
18092            if range.end.row < buffer.max_row().0 {
18093                peek_end = Point::new(range.end.row + 1, 0);
18094            }
18095            buffer
18096                .diff_hunks_in_range(range.start..peek_end)
18097                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18098        })
18099    }
18100
18101    pub fn has_stageable_diff_hunks_in_ranges(
18102        &self,
18103        ranges: &[Range<Anchor>],
18104        snapshot: &MultiBufferSnapshot,
18105    ) -> bool {
18106        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18107        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18108    }
18109
18110    pub fn toggle_staged_selected_diff_hunks(
18111        &mut self,
18112        _: &::git::ToggleStaged,
18113        _: &mut Window,
18114        cx: &mut Context<Self>,
18115    ) {
18116        let snapshot = self.buffer.read(cx).snapshot(cx);
18117        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18118        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18119        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18120    }
18121
18122    pub fn set_render_diff_hunk_controls(
18123        &mut self,
18124        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18125        cx: &mut Context<Self>,
18126    ) {
18127        self.render_diff_hunk_controls = render_diff_hunk_controls;
18128        cx.notify();
18129    }
18130
18131    pub fn stage_and_next(
18132        &mut self,
18133        _: &::git::StageAndNext,
18134        window: &mut Window,
18135        cx: &mut Context<Self>,
18136    ) {
18137        self.do_stage_or_unstage_and_next(true, window, cx);
18138    }
18139
18140    pub fn unstage_and_next(
18141        &mut self,
18142        _: &::git::UnstageAndNext,
18143        window: &mut Window,
18144        cx: &mut Context<Self>,
18145    ) {
18146        self.do_stage_or_unstage_and_next(false, window, cx);
18147    }
18148
18149    pub fn stage_or_unstage_diff_hunks(
18150        &mut self,
18151        stage: bool,
18152        ranges: Vec<Range<Anchor>>,
18153        cx: &mut Context<Self>,
18154    ) {
18155        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18156        cx.spawn(async move |this, cx| {
18157            task.await?;
18158            this.update(cx, |this, cx| {
18159                let snapshot = this.buffer.read(cx).snapshot(cx);
18160                let chunk_by = this
18161                    .diff_hunks_in_ranges(&ranges, &snapshot)
18162                    .chunk_by(|hunk| hunk.buffer_id);
18163                for (buffer_id, hunks) in &chunk_by {
18164                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18165                }
18166            })
18167        })
18168        .detach_and_log_err(cx);
18169    }
18170
18171    fn save_buffers_for_ranges_if_needed(
18172        &mut self,
18173        ranges: &[Range<Anchor>],
18174        cx: &mut Context<Editor>,
18175    ) -> Task<Result<()>> {
18176        let multibuffer = self.buffer.read(cx);
18177        let snapshot = multibuffer.read(cx);
18178        let buffer_ids: HashSet<_> = ranges
18179            .iter()
18180            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18181            .collect();
18182        drop(snapshot);
18183
18184        let mut buffers = HashSet::default();
18185        for buffer_id in buffer_ids {
18186            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18187                let buffer = buffer_entity.read(cx);
18188                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18189                {
18190                    buffers.insert(buffer_entity);
18191                }
18192            }
18193        }
18194
18195        if let Some(project) = &self.project {
18196            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18197        } else {
18198            Task::ready(Ok(()))
18199        }
18200    }
18201
18202    fn do_stage_or_unstage_and_next(
18203        &mut self,
18204        stage: bool,
18205        window: &mut Window,
18206        cx: &mut Context<Self>,
18207    ) {
18208        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18209
18210        if ranges.iter().any(|range| range.start != range.end) {
18211            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18212            return;
18213        }
18214
18215        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18216        let snapshot = self.snapshot(window, cx);
18217        let position = self.selections.newest::<Point>(cx).head();
18218        let mut row = snapshot
18219            .buffer_snapshot
18220            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18221            .find(|hunk| hunk.row_range.start.0 > position.row)
18222            .map(|hunk| hunk.row_range.start);
18223
18224        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18225        // Outside of the project diff editor, wrap around to the beginning.
18226        if !all_diff_hunks_expanded {
18227            row = row.or_else(|| {
18228                snapshot
18229                    .buffer_snapshot
18230                    .diff_hunks_in_range(Point::zero()..position)
18231                    .find(|hunk| hunk.row_range.end.0 < position.row)
18232                    .map(|hunk| hunk.row_range.start)
18233            });
18234        }
18235
18236        if let Some(row) = row {
18237            let destination = Point::new(row.0, 0);
18238            let autoscroll = Autoscroll::center();
18239
18240            self.unfold_ranges(&[destination..destination], false, false, cx);
18241            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18242                s.select_ranges([destination..destination]);
18243            });
18244        }
18245    }
18246
18247    fn do_stage_or_unstage(
18248        &self,
18249        stage: bool,
18250        buffer_id: BufferId,
18251        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18252        cx: &mut App,
18253    ) -> Option<()> {
18254        let project = self.project()?;
18255        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18256        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18257        let buffer_snapshot = buffer.read(cx).snapshot();
18258        let file_exists = buffer_snapshot
18259            .file()
18260            .is_some_and(|file| file.disk_state().exists());
18261        diff.update(cx, |diff, cx| {
18262            diff.stage_or_unstage_hunks(
18263                stage,
18264                &hunks
18265                    .map(|hunk| buffer_diff::DiffHunk {
18266                        buffer_range: hunk.buffer_range,
18267                        diff_base_byte_range: hunk.diff_base_byte_range,
18268                        secondary_status: hunk.secondary_status,
18269                        range: Point::zero()..Point::zero(), // unused
18270                    })
18271                    .collect::<Vec<_>>(),
18272                &buffer_snapshot,
18273                file_exists,
18274                cx,
18275            )
18276        });
18277        None
18278    }
18279
18280    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18281        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18282        self.buffer
18283            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18284    }
18285
18286    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18287        self.buffer.update(cx, |buffer, cx| {
18288            let ranges = vec![Anchor::min()..Anchor::max()];
18289            if !buffer.all_diff_hunks_expanded()
18290                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18291            {
18292                buffer.collapse_diff_hunks(ranges, cx);
18293                true
18294            } else {
18295                false
18296            }
18297        })
18298    }
18299
18300    fn toggle_diff_hunks_in_ranges(
18301        &mut self,
18302        ranges: Vec<Range<Anchor>>,
18303        cx: &mut Context<Editor>,
18304    ) {
18305        self.buffer.update(cx, |buffer, cx| {
18306            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18307            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18308        })
18309    }
18310
18311    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18312        self.buffer.update(cx, |buffer, cx| {
18313            let snapshot = buffer.snapshot(cx);
18314            let excerpt_id = range.end.excerpt_id;
18315            let point_range = range.to_point(&snapshot);
18316            let expand = !buffer.single_hunk_is_expanded(range, cx);
18317            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18318        })
18319    }
18320
18321    pub(crate) fn apply_all_diff_hunks(
18322        &mut self,
18323        _: &ApplyAllDiffHunks,
18324        window: &mut Window,
18325        cx: &mut Context<Self>,
18326    ) {
18327        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18328
18329        let buffers = self.buffer.read(cx).all_buffers();
18330        for branch_buffer in buffers {
18331            branch_buffer.update(cx, |branch_buffer, cx| {
18332                branch_buffer.merge_into_base(Vec::new(), cx);
18333            });
18334        }
18335
18336        if let Some(project) = self.project.clone() {
18337            self.save(
18338                SaveOptions {
18339                    format: true,
18340                    autosave: false,
18341                },
18342                project,
18343                window,
18344                cx,
18345            )
18346            .detach_and_log_err(cx);
18347        }
18348    }
18349
18350    pub(crate) fn apply_selected_diff_hunks(
18351        &mut self,
18352        _: &ApplyDiffHunk,
18353        window: &mut Window,
18354        cx: &mut Context<Self>,
18355    ) {
18356        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18357        let snapshot = self.snapshot(window, cx);
18358        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18359        let mut ranges_by_buffer = HashMap::default();
18360        self.transact(window, cx, |editor, _window, cx| {
18361            for hunk in hunks {
18362                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18363                    ranges_by_buffer
18364                        .entry(buffer.clone())
18365                        .or_insert_with(Vec::new)
18366                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18367                }
18368            }
18369
18370            for (buffer, ranges) in ranges_by_buffer {
18371                buffer.update(cx, |buffer, cx| {
18372                    buffer.merge_into_base(ranges, cx);
18373                });
18374            }
18375        });
18376
18377        if let Some(project) = self.project.clone() {
18378            self.save(
18379                SaveOptions {
18380                    format: true,
18381                    autosave: false,
18382                },
18383                project,
18384                window,
18385                cx,
18386            )
18387            .detach_and_log_err(cx);
18388        }
18389    }
18390
18391    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18392        if hovered != self.gutter_hovered {
18393            self.gutter_hovered = hovered;
18394            cx.notify();
18395        }
18396    }
18397
18398    pub fn insert_blocks(
18399        &mut self,
18400        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18401        autoscroll: Option<Autoscroll>,
18402        cx: &mut Context<Self>,
18403    ) -> Vec<CustomBlockId> {
18404        let blocks = self
18405            .display_map
18406            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18407        if let Some(autoscroll) = autoscroll {
18408            self.request_autoscroll(autoscroll, cx);
18409        }
18410        cx.notify();
18411        blocks
18412    }
18413
18414    pub fn resize_blocks(
18415        &mut self,
18416        heights: HashMap<CustomBlockId, u32>,
18417        autoscroll: Option<Autoscroll>,
18418        cx: &mut Context<Self>,
18419    ) {
18420        self.display_map
18421            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18422        if let Some(autoscroll) = autoscroll {
18423            self.request_autoscroll(autoscroll, cx);
18424        }
18425        cx.notify();
18426    }
18427
18428    pub fn replace_blocks(
18429        &mut self,
18430        renderers: HashMap<CustomBlockId, RenderBlock>,
18431        autoscroll: Option<Autoscroll>,
18432        cx: &mut Context<Self>,
18433    ) {
18434        self.display_map
18435            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18436        if let Some(autoscroll) = autoscroll {
18437            self.request_autoscroll(autoscroll, cx);
18438        }
18439        cx.notify();
18440    }
18441
18442    pub fn remove_blocks(
18443        &mut self,
18444        block_ids: HashSet<CustomBlockId>,
18445        autoscroll: Option<Autoscroll>,
18446        cx: &mut Context<Self>,
18447    ) {
18448        self.display_map.update(cx, |display_map, cx| {
18449            display_map.remove_blocks(block_ids, cx)
18450        });
18451        if let Some(autoscroll) = autoscroll {
18452            self.request_autoscroll(autoscroll, cx);
18453        }
18454        cx.notify();
18455    }
18456
18457    pub fn row_for_block(
18458        &self,
18459        block_id: CustomBlockId,
18460        cx: &mut Context<Self>,
18461    ) -> Option<DisplayRow> {
18462        self.display_map
18463            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18464    }
18465
18466    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18467        self.focused_block = Some(focused_block);
18468    }
18469
18470    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18471        self.focused_block.take()
18472    }
18473
18474    pub fn insert_creases(
18475        &mut self,
18476        creases: impl IntoIterator<Item = Crease<Anchor>>,
18477        cx: &mut Context<Self>,
18478    ) -> Vec<CreaseId> {
18479        self.display_map
18480            .update(cx, |map, cx| map.insert_creases(creases, cx))
18481    }
18482
18483    pub fn remove_creases(
18484        &mut self,
18485        ids: impl IntoIterator<Item = CreaseId>,
18486        cx: &mut Context<Self>,
18487    ) -> Vec<(CreaseId, Range<Anchor>)> {
18488        self.display_map
18489            .update(cx, |map, cx| map.remove_creases(ids, cx))
18490    }
18491
18492    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18493        self.display_map
18494            .update(cx, |map, cx| map.snapshot(cx))
18495            .longest_row()
18496    }
18497
18498    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18499        self.display_map
18500            .update(cx, |map, cx| map.snapshot(cx))
18501            .max_point()
18502    }
18503
18504    pub fn text(&self, cx: &App) -> String {
18505        self.buffer.read(cx).read(cx).text()
18506    }
18507
18508    pub fn is_empty(&self, cx: &App) -> bool {
18509        self.buffer.read(cx).read(cx).is_empty()
18510    }
18511
18512    pub fn text_option(&self, cx: &App) -> Option<String> {
18513        let text = self.text(cx);
18514        let text = text.trim();
18515
18516        if text.is_empty() {
18517            return None;
18518        }
18519
18520        Some(text.to_string())
18521    }
18522
18523    pub fn set_text(
18524        &mut self,
18525        text: impl Into<Arc<str>>,
18526        window: &mut Window,
18527        cx: &mut Context<Self>,
18528    ) {
18529        self.transact(window, cx, |this, _, cx| {
18530            this.buffer
18531                .read(cx)
18532                .as_singleton()
18533                .expect("you can only call set_text on editors for singleton buffers")
18534                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18535        });
18536    }
18537
18538    pub fn display_text(&self, cx: &mut App) -> String {
18539        self.display_map
18540            .update(cx, |map, cx| map.snapshot(cx))
18541            .text()
18542    }
18543
18544    fn create_minimap(
18545        &self,
18546        minimap_settings: MinimapSettings,
18547        window: &mut Window,
18548        cx: &mut Context<Self>,
18549    ) -> Option<Entity<Self>> {
18550        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18551            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18552    }
18553
18554    fn initialize_new_minimap(
18555        &self,
18556        minimap_settings: MinimapSettings,
18557        window: &mut Window,
18558        cx: &mut Context<Self>,
18559    ) -> Entity<Self> {
18560        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18561
18562        let mut minimap = Editor::new_internal(
18563            EditorMode::Minimap {
18564                parent: cx.weak_entity(),
18565            },
18566            self.buffer.clone(),
18567            None,
18568            Some(self.display_map.clone()),
18569            window,
18570            cx,
18571        );
18572        minimap.scroll_manager.clone_state(&self.scroll_manager);
18573        minimap.set_text_style_refinement(TextStyleRefinement {
18574            font_size: Some(MINIMAP_FONT_SIZE),
18575            font_weight: Some(MINIMAP_FONT_WEIGHT),
18576            ..Default::default()
18577        });
18578        minimap.update_minimap_configuration(minimap_settings, cx);
18579        cx.new(|_| minimap)
18580    }
18581
18582    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18583        let current_line_highlight = minimap_settings
18584            .current_line_highlight
18585            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18586        self.set_current_line_highlight(Some(current_line_highlight));
18587    }
18588
18589    pub fn minimap(&self) -> Option<&Entity<Self>> {
18590        self.minimap
18591            .as_ref()
18592            .filter(|_| self.minimap_visibility.visible())
18593    }
18594
18595    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18596        let mut wrap_guides = smallvec![];
18597
18598        if self.show_wrap_guides == Some(false) {
18599            return wrap_guides;
18600        }
18601
18602        let settings = self.buffer.read(cx).language_settings(cx);
18603        if settings.show_wrap_guides {
18604            match self.soft_wrap_mode(cx) {
18605                SoftWrap::Column(soft_wrap) => {
18606                    wrap_guides.push((soft_wrap as usize, true));
18607                }
18608                SoftWrap::Bounded(soft_wrap) => {
18609                    wrap_guides.push((soft_wrap as usize, true));
18610                }
18611                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18612            }
18613            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18614        }
18615
18616        wrap_guides
18617    }
18618
18619    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18620        let settings = self.buffer.read(cx).language_settings(cx);
18621        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18622        match mode {
18623            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18624                SoftWrap::None
18625            }
18626            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18627            language_settings::SoftWrap::PreferredLineLength => {
18628                SoftWrap::Column(settings.preferred_line_length)
18629            }
18630            language_settings::SoftWrap::Bounded => {
18631                SoftWrap::Bounded(settings.preferred_line_length)
18632            }
18633        }
18634    }
18635
18636    pub fn set_soft_wrap_mode(
18637        &mut self,
18638        mode: language_settings::SoftWrap,
18639
18640        cx: &mut Context<Self>,
18641    ) {
18642        self.soft_wrap_mode_override = Some(mode);
18643        cx.notify();
18644    }
18645
18646    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18647        self.hard_wrap = hard_wrap;
18648        cx.notify();
18649    }
18650
18651    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18652        self.text_style_refinement = Some(style);
18653    }
18654
18655    /// called by the Element so we know what style we were most recently rendered with.
18656    pub(crate) fn set_style(
18657        &mut self,
18658        style: EditorStyle,
18659        window: &mut Window,
18660        cx: &mut Context<Self>,
18661    ) {
18662        // We intentionally do not inform the display map about the minimap style
18663        // so that wrapping is not recalculated and stays consistent for the editor
18664        // and its linked minimap.
18665        if !self.mode.is_minimap() {
18666            let rem_size = window.rem_size();
18667            self.display_map.update(cx, |map, cx| {
18668                map.set_font(
18669                    style.text.font(),
18670                    style.text.font_size.to_pixels(rem_size),
18671                    cx,
18672                )
18673            });
18674        }
18675        self.style = Some(style);
18676    }
18677
18678    pub fn style(&self) -> Option<&EditorStyle> {
18679        self.style.as_ref()
18680    }
18681
18682    // Called by the element. This method is not designed to be called outside of the editor
18683    // element's layout code because it does not notify when rewrapping is computed synchronously.
18684    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18685        self.display_map
18686            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18687    }
18688
18689    pub fn set_soft_wrap(&mut self) {
18690        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18691    }
18692
18693    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18694        if self.soft_wrap_mode_override.is_some() {
18695            self.soft_wrap_mode_override.take();
18696        } else {
18697            let soft_wrap = match self.soft_wrap_mode(cx) {
18698                SoftWrap::GitDiff => return,
18699                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18700                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18701                    language_settings::SoftWrap::None
18702                }
18703            };
18704            self.soft_wrap_mode_override = Some(soft_wrap);
18705        }
18706        cx.notify();
18707    }
18708
18709    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18710        let Some(workspace) = self.workspace() else {
18711            return;
18712        };
18713        let fs = workspace.read(cx).app_state().fs.clone();
18714        let current_show = TabBarSettings::get_global(cx).show;
18715        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18716            setting.show = Some(!current_show);
18717        });
18718    }
18719
18720    pub fn toggle_indent_guides(
18721        &mut self,
18722        _: &ToggleIndentGuides,
18723        _: &mut Window,
18724        cx: &mut Context<Self>,
18725    ) {
18726        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18727            self.buffer
18728                .read(cx)
18729                .language_settings(cx)
18730                .indent_guides
18731                .enabled
18732        });
18733        self.show_indent_guides = Some(!currently_enabled);
18734        cx.notify();
18735    }
18736
18737    fn should_show_indent_guides(&self) -> Option<bool> {
18738        self.show_indent_guides
18739    }
18740
18741    pub fn toggle_line_numbers(
18742        &mut self,
18743        _: &ToggleLineNumbers,
18744        _: &mut Window,
18745        cx: &mut Context<Self>,
18746    ) {
18747        let mut editor_settings = EditorSettings::get_global(cx).clone();
18748        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18749        EditorSettings::override_global(editor_settings, cx);
18750    }
18751
18752    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18753        if let Some(show_line_numbers) = self.show_line_numbers {
18754            return show_line_numbers;
18755        }
18756        EditorSettings::get_global(cx).gutter.line_numbers
18757    }
18758
18759    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18760        self.use_relative_line_numbers
18761            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18762    }
18763
18764    pub fn toggle_relative_line_numbers(
18765        &mut self,
18766        _: &ToggleRelativeLineNumbers,
18767        _: &mut Window,
18768        cx: &mut Context<Self>,
18769    ) {
18770        let is_relative = self.should_use_relative_line_numbers(cx);
18771        self.set_relative_line_number(Some(!is_relative), cx)
18772    }
18773
18774    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18775        self.use_relative_line_numbers = is_relative;
18776        cx.notify();
18777    }
18778
18779    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18780        self.show_gutter = show_gutter;
18781        cx.notify();
18782    }
18783
18784    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18785        self.show_scrollbars = ScrollbarAxes {
18786            horizontal: show,
18787            vertical: show,
18788        };
18789        cx.notify();
18790    }
18791
18792    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18793        self.show_scrollbars.vertical = show;
18794        cx.notify();
18795    }
18796
18797    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18798        self.show_scrollbars.horizontal = show;
18799        cx.notify();
18800    }
18801
18802    pub fn set_minimap_visibility(
18803        &mut self,
18804        minimap_visibility: MinimapVisibility,
18805        window: &mut Window,
18806        cx: &mut Context<Self>,
18807    ) {
18808        if self.minimap_visibility != minimap_visibility {
18809            if minimap_visibility.visible() && self.minimap.is_none() {
18810                let minimap_settings = EditorSettings::get_global(cx).minimap;
18811                self.minimap =
18812                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18813            }
18814            self.minimap_visibility = minimap_visibility;
18815            cx.notify();
18816        }
18817    }
18818
18819    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18820        self.set_show_scrollbars(false, cx);
18821        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18822    }
18823
18824    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18825        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18826    }
18827
18828    /// Normally the text in full mode and auto height editors is padded on the
18829    /// left side by roughly half a character width for improved hit testing.
18830    ///
18831    /// Use this method to disable this for cases where this is not wanted (e.g.
18832    /// if you want to align the editor text with some other text above or below)
18833    /// or if you want to add this padding to single-line editors.
18834    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18835        self.offset_content = offset_content;
18836        cx.notify();
18837    }
18838
18839    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18840        self.show_line_numbers = Some(show_line_numbers);
18841        cx.notify();
18842    }
18843
18844    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18845        self.disable_expand_excerpt_buttons = true;
18846        cx.notify();
18847    }
18848
18849    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18850        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18851        cx.notify();
18852    }
18853
18854    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18855        self.show_code_actions = Some(show_code_actions);
18856        cx.notify();
18857    }
18858
18859    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18860        self.show_runnables = Some(show_runnables);
18861        cx.notify();
18862    }
18863
18864    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18865        self.show_breakpoints = Some(show_breakpoints);
18866        cx.notify();
18867    }
18868
18869    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18870        if self.display_map.read(cx).masked != masked {
18871            self.display_map.update(cx, |map, _| map.masked = masked);
18872        }
18873        cx.notify()
18874    }
18875
18876    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18877        self.show_wrap_guides = Some(show_wrap_guides);
18878        cx.notify();
18879    }
18880
18881    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18882        self.show_indent_guides = Some(show_indent_guides);
18883        cx.notify();
18884    }
18885
18886    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18887        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18888            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18889                && let Some(dir) = file.abs_path(cx).parent()
18890            {
18891                return Some(dir.to_owned());
18892            }
18893
18894            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18895                return Some(project_path.path.to_path_buf());
18896            }
18897        }
18898
18899        None
18900    }
18901
18902    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18903        self.active_excerpt(cx)?
18904            .1
18905            .read(cx)
18906            .file()
18907            .and_then(|f| f.as_local())
18908    }
18909
18910    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18911        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18912            let buffer = buffer.read(cx);
18913            if let Some(project_path) = buffer.project_path(cx) {
18914                let project = self.project()?.read(cx);
18915                project.absolute_path(&project_path, cx)
18916            } else {
18917                buffer
18918                    .file()
18919                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18920            }
18921        })
18922    }
18923
18924    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18925        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18926            let project_path = buffer.read(cx).project_path(cx)?;
18927            let project = self.project()?.read(cx);
18928            let entry = project.entry_for_path(&project_path, cx)?;
18929            let path = entry.path.to_path_buf();
18930            Some(path)
18931        })
18932    }
18933
18934    pub fn reveal_in_finder(
18935        &mut self,
18936        _: &RevealInFileManager,
18937        _window: &mut Window,
18938        cx: &mut Context<Self>,
18939    ) {
18940        if let Some(target) = self.target_file(cx) {
18941            cx.reveal_path(&target.abs_path(cx));
18942        }
18943    }
18944
18945    pub fn copy_path(
18946        &mut self,
18947        _: &zed_actions::workspace::CopyPath,
18948        _window: &mut Window,
18949        cx: &mut Context<Self>,
18950    ) {
18951        if let Some(path) = self.target_file_abs_path(cx)
18952            && let Some(path) = path.to_str()
18953        {
18954            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18955        }
18956    }
18957
18958    pub fn copy_relative_path(
18959        &mut self,
18960        _: &zed_actions::workspace::CopyRelativePath,
18961        _window: &mut Window,
18962        cx: &mut Context<Self>,
18963    ) {
18964        if let Some(path) = self.target_file_path(cx)
18965            && let Some(path) = path.to_str()
18966        {
18967            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18968        }
18969    }
18970
18971    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18972        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18973            buffer.read(cx).project_path(cx)
18974        } else {
18975            None
18976        }
18977    }
18978
18979    // Returns true if the editor handled a go-to-line request
18980    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18981        maybe!({
18982            let breakpoint_store = self.breakpoint_store.as_ref()?;
18983
18984            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18985            else {
18986                self.clear_row_highlights::<ActiveDebugLine>();
18987                return None;
18988            };
18989
18990            let position = active_stack_frame.position;
18991            let buffer_id = position.buffer_id?;
18992            let snapshot = self
18993                .project
18994                .as_ref()?
18995                .read(cx)
18996                .buffer_for_id(buffer_id, cx)?
18997                .read(cx)
18998                .snapshot();
18999
19000            let mut handled = false;
19001            for (id, ExcerptRange { context, .. }) in
19002                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19003            {
19004                if context.start.cmp(&position, &snapshot).is_ge()
19005                    || context.end.cmp(&position, &snapshot).is_lt()
19006                {
19007                    continue;
19008                }
19009                let snapshot = self.buffer.read(cx).snapshot(cx);
19010                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19011
19012                handled = true;
19013                self.clear_row_highlights::<ActiveDebugLine>();
19014
19015                self.go_to_line::<ActiveDebugLine>(
19016                    multibuffer_anchor,
19017                    Some(cx.theme().colors().editor_debugger_active_line_background),
19018                    window,
19019                    cx,
19020                );
19021
19022                cx.notify();
19023            }
19024
19025            handled.then_some(())
19026        })
19027        .is_some()
19028    }
19029
19030    pub fn copy_file_name_without_extension(
19031        &mut self,
19032        _: &CopyFileNameWithoutExtension,
19033        _: &mut Window,
19034        cx: &mut Context<Self>,
19035    ) {
19036        if let Some(file) = self.target_file(cx)
19037            && let Some(file_stem) = file.path().file_stem()
19038            && let Some(name) = file_stem.to_str()
19039        {
19040            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19041        }
19042    }
19043
19044    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19045        if let Some(file) = self.target_file(cx)
19046            && let Some(file_name) = file.path().file_name()
19047            && let Some(name) = file_name.to_str()
19048        {
19049            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19050        }
19051    }
19052
19053    pub fn toggle_git_blame(
19054        &mut self,
19055        _: &::git::Blame,
19056        window: &mut Window,
19057        cx: &mut Context<Self>,
19058    ) {
19059        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19060
19061        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19062            self.start_git_blame(true, window, cx);
19063        }
19064
19065        cx.notify();
19066    }
19067
19068    pub fn toggle_git_blame_inline(
19069        &mut self,
19070        _: &ToggleGitBlameInline,
19071        window: &mut Window,
19072        cx: &mut Context<Self>,
19073    ) {
19074        self.toggle_git_blame_inline_internal(true, window, cx);
19075        cx.notify();
19076    }
19077
19078    pub fn open_git_blame_commit(
19079        &mut self,
19080        _: &OpenGitBlameCommit,
19081        window: &mut Window,
19082        cx: &mut Context<Self>,
19083    ) {
19084        self.open_git_blame_commit_internal(window, cx);
19085    }
19086
19087    fn open_git_blame_commit_internal(
19088        &mut self,
19089        window: &mut Window,
19090        cx: &mut Context<Self>,
19091    ) -> Option<()> {
19092        let blame = self.blame.as_ref()?;
19093        let snapshot = self.snapshot(window, cx);
19094        let cursor = self.selections.newest::<Point>(cx).head();
19095        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19096        let (_, blame_entry) = blame
19097            .update(cx, |blame, cx| {
19098                blame
19099                    .blame_for_rows(
19100                        &[RowInfo {
19101                            buffer_id: Some(buffer.remote_id()),
19102                            buffer_row: Some(point.row),
19103                            ..Default::default()
19104                        }],
19105                        cx,
19106                    )
19107                    .next()
19108            })
19109            .flatten()?;
19110        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19111        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19112        let workspace = self.workspace()?.downgrade();
19113        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19114        None
19115    }
19116
19117    pub fn git_blame_inline_enabled(&self) -> bool {
19118        self.git_blame_inline_enabled
19119    }
19120
19121    pub fn toggle_selection_menu(
19122        &mut self,
19123        _: &ToggleSelectionMenu,
19124        _: &mut Window,
19125        cx: &mut Context<Self>,
19126    ) {
19127        self.show_selection_menu = self
19128            .show_selection_menu
19129            .map(|show_selections_menu| !show_selections_menu)
19130            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19131
19132        cx.notify();
19133    }
19134
19135    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19136        self.show_selection_menu
19137            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19138    }
19139
19140    fn start_git_blame(
19141        &mut self,
19142        user_triggered: bool,
19143        window: &mut Window,
19144        cx: &mut Context<Self>,
19145    ) {
19146        if let Some(project) = self.project() {
19147            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19148                && buffer.read(cx).file().is_none()
19149            {
19150                return;
19151            }
19152
19153            let focused = self.focus_handle(cx).contains_focused(window, cx);
19154
19155            let project = project.clone();
19156            let blame = cx
19157                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19158            self.blame_subscription =
19159                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19160            self.blame = Some(blame);
19161        }
19162    }
19163
19164    fn toggle_git_blame_inline_internal(
19165        &mut self,
19166        user_triggered: bool,
19167        window: &mut Window,
19168        cx: &mut Context<Self>,
19169    ) {
19170        if self.git_blame_inline_enabled {
19171            self.git_blame_inline_enabled = false;
19172            self.show_git_blame_inline = false;
19173            self.show_git_blame_inline_delay_task.take();
19174        } else {
19175            self.git_blame_inline_enabled = true;
19176            self.start_git_blame_inline(user_triggered, window, cx);
19177        }
19178
19179        cx.notify();
19180    }
19181
19182    fn start_git_blame_inline(
19183        &mut self,
19184        user_triggered: bool,
19185        window: &mut Window,
19186        cx: &mut Context<Self>,
19187    ) {
19188        self.start_git_blame(user_triggered, window, cx);
19189
19190        if ProjectSettings::get_global(cx)
19191            .git
19192            .inline_blame_delay()
19193            .is_some()
19194        {
19195            self.start_inline_blame_timer(window, cx);
19196        } else {
19197            self.show_git_blame_inline = true
19198        }
19199    }
19200
19201    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19202        self.blame.as_ref()
19203    }
19204
19205    pub fn show_git_blame_gutter(&self) -> bool {
19206        self.show_git_blame_gutter
19207    }
19208
19209    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19210        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19211    }
19212
19213    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19214        self.show_git_blame_inline
19215            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19216            && !self.newest_selection_head_on_empty_line(cx)
19217            && self.has_blame_entries(cx)
19218    }
19219
19220    fn has_blame_entries(&self, cx: &App) -> bool {
19221        self.blame()
19222            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19223    }
19224
19225    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19226        let cursor_anchor = self.selections.newest_anchor().head();
19227
19228        let snapshot = self.buffer.read(cx).snapshot(cx);
19229        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19230
19231        snapshot.line_len(buffer_row) == 0
19232    }
19233
19234    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19235        let buffer_and_selection = maybe!({
19236            let selection = self.selections.newest::<Point>(cx);
19237            let selection_range = selection.range();
19238
19239            let multi_buffer = self.buffer().read(cx);
19240            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19241            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19242
19243            let (buffer, range, _) = if selection.reversed {
19244                buffer_ranges.first()
19245            } else {
19246                buffer_ranges.last()
19247            }?;
19248
19249            let selection = text::ToPoint::to_point(&range.start, buffer).row
19250                ..text::ToPoint::to_point(&range.end, buffer).row;
19251            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19252        });
19253
19254        let Some((buffer, selection)) = buffer_and_selection else {
19255            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19256        };
19257
19258        let Some(project) = self.project() else {
19259            return Task::ready(Err(anyhow!("editor does not have project")));
19260        };
19261
19262        project.update(cx, |project, cx| {
19263            project.get_permalink_to_line(&buffer, selection, cx)
19264        })
19265    }
19266
19267    pub fn copy_permalink_to_line(
19268        &mut self,
19269        _: &CopyPermalinkToLine,
19270        window: &mut Window,
19271        cx: &mut Context<Self>,
19272    ) {
19273        let permalink_task = self.get_permalink_to_line(cx);
19274        let workspace = self.workspace();
19275
19276        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19277            Ok(permalink) => {
19278                cx.update(|_, cx| {
19279                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19280                })
19281                .ok();
19282            }
19283            Err(err) => {
19284                let message = format!("Failed to copy permalink: {err}");
19285
19286                anyhow::Result::<()>::Err(err).log_err();
19287
19288                if let Some(workspace) = workspace {
19289                    workspace
19290                        .update_in(cx, |workspace, _, cx| {
19291                            struct CopyPermalinkToLine;
19292
19293                            workspace.show_toast(
19294                                Toast::new(
19295                                    NotificationId::unique::<CopyPermalinkToLine>(),
19296                                    message,
19297                                ),
19298                                cx,
19299                            )
19300                        })
19301                        .ok();
19302                }
19303            }
19304        })
19305        .detach();
19306    }
19307
19308    pub fn copy_file_location(
19309        &mut self,
19310        _: &CopyFileLocation,
19311        _: &mut Window,
19312        cx: &mut Context<Self>,
19313    ) {
19314        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19315        if let Some(file) = self.target_file(cx)
19316            && let Some(path) = file.path().to_str()
19317        {
19318            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19319        }
19320    }
19321
19322    pub fn open_permalink_to_line(
19323        &mut self,
19324        _: &OpenPermalinkToLine,
19325        window: &mut Window,
19326        cx: &mut Context<Self>,
19327    ) {
19328        let permalink_task = self.get_permalink_to_line(cx);
19329        let workspace = self.workspace();
19330
19331        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19332            Ok(permalink) => {
19333                cx.update(|_, cx| {
19334                    cx.open_url(permalink.as_ref());
19335                })
19336                .ok();
19337            }
19338            Err(err) => {
19339                let message = format!("Failed to open permalink: {err}");
19340
19341                anyhow::Result::<()>::Err(err).log_err();
19342
19343                if let Some(workspace) = workspace {
19344                    workspace
19345                        .update(cx, |workspace, cx| {
19346                            struct OpenPermalinkToLine;
19347
19348                            workspace.show_toast(
19349                                Toast::new(
19350                                    NotificationId::unique::<OpenPermalinkToLine>(),
19351                                    message,
19352                                ),
19353                                cx,
19354                            )
19355                        })
19356                        .ok();
19357                }
19358            }
19359        })
19360        .detach();
19361    }
19362
19363    pub fn insert_uuid_v4(
19364        &mut self,
19365        _: &InsertUuidV4,
19366        window: &mut Window,
19367        cx: &mut Context<Self>,
19368    ) {
19369        self.insert_uuid(UuidVersion::V4, window, cx);
19370    }
19371
19372    pub fn insert_uuid_v7(
19373        &mut self,
19374        _: &InsertUuidV7,
19375        window: &mut Window,
19376        cx: &mut Context<Self>,
19377    ) {
19378        self.insert_uuid(UuidVersion::V7, window, cx);
19379    }
19380
19381    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19382        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19383        self.transact(window, cx, |this, window, cx| {
19384            let edits = this
19385                .selections
19386                .all::<Point>(cx)
19387                .into_iter()
19388                .map(|selection| {
19389                    let uuid = match version {
19390                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19391                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19392                    };
19393
19394                    (selection.range(), uuid.to_string())
19395                });
19396            this.edit(edits, cx);
19397            this.refresh_edit_prediction(true, false, window, cx);
19398        });
19399    }
19400
19401    pub fn open_selections_in_multibuffer(
19402        &mut self,
19403        _: &OpenSelectionsInMultibuffer,
19404        window: &mut Window,
19405        cx: &mut Context<Self>,
19406    ) {
19407        let multibuffer = self.buffer.read(cx);
19408
19409        let Some(buffer) = multibuffer.as_singleton() else {
19410            return;
19411        };
19412
19413        let Some(workspace) = self.workspace() else {
19414            return;
19415        };
19416
19417        let title = multibuffer.title(cx).to_string();
19418
19419        let locations = self
19420            .selections
19421            .all_anchors(cx)
19422            .iter()
19423            .map(|selection| Location {
19424                buffer: buffer.clone(),
19425                range: selection.start.text_anchor..selection.end.text_anchor,
19426            })
19427            .collect::<Vec<_>>();
19428
19429        cx.spawn_in(window, async move |_, cx| {
19430            workspace.update_in(cx, |workspace, window, cx| {
19431                Self::open_locations_in_multibuffer(
19432                    workspace,
19433                    locations,
19434                    format!("Selections for '{title}'"),
19435                    false,
19436                    MultibufferSelectionMode::All,
19437                    window,
19438                    cx,
19439                );
19440            })
19441        })
19442        .detach();
19443    }
19444
19445    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19446    /// last highlight added will be used.
19447    ///
19448    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19449    pub fn highlight_rows<T: 'static>(
19450        &mut self,
19451        range: Range<Anchor>,
19452        color: Hsla,
19453        options: RowHighlightOptions,
19454        cx: &mut Context<Self>,
19455    ) {
19456        let snapshot = self.buffer().read(cx).snapshot(cx);
19457        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19458        let ix = row_highlights.binary_search_by(|highlight| {
19459            Ordering::Equal
19460                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19461                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19462        });
19463
19464        if let Err(mut ix) = ix {
19465            let index = post_inc(&mut self.highlight_order);
19466
19467            // If this range intersects with the preceding highlight, then merge it with
19468            // the preceding highlight. Otherwise insert a new highlight.
19469            let mut merged = false;
19470            if ix > 0 {
19471                let prev_highlight = &mut row_highlights[ix - 1];
19472                if prev_highlight
19473                    .range
19474                    .end
19475                    .cmp(&range.start, &snapshot)
19476                    .is_ge()
19477                {
19478                    ix -= 1;
19479                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19480                        prev_highlight.range.end = range.end;
19481                    }
19482                    merged = true;
19483                    prev_highlight.index = index;
19484                    prev_highlight.color = color;
19485                    prev_highlight.options = options;
19486                }
19487            }
19488
19489            if !merged {
19490                row_highlights.insert(
19491                    ix,
19492                    RowHighlight {
19493                        range,
19494                        index,
19495                        color,
19496                        options,
19497                        type_id: TypeId::of::<T>(),
19498                    },
19499                );
19500            }
19501
19502            // If any of the following highlights intersect with this one, merge them.
19503            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19504                let highlight = &row_highlights[ix];
19505                if next_highlight
19506                    .range
19507                    .start
19508                    .cmp(&highlight.range.end, &snapshot)
19509                    .is_le()
19510                {
19511                    if next_highlight
19512                        .range
19513                        .end
19514                        .cmp(&highlight.range.end, &snapshot)
19515                        .is_gt()
19516                    {
19517                        row_highlights[ix].range.end = next_highlight.range.end;
19518                    }
19519                    row_highlights.remove(ix + 1);
19520                } else {
19521                    break;
19522                }
19523            }
19524        }
19525    }
19526
19527    /// Remove any highlighted row ranges of the given type that intersect the
19528    /// given ranges.
19529    pub fn remove_highlighted_rows<T: 'static>(
19530        &mut self,
19531        ranges_to_remove: Vec<Range<Anchor>>,
19532        cx: &mut Context<Self>,
19533    ) {
19534        let snapshot = self.buffer().read(cx).snapshot(cx);
19535        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19536        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19537        row_highlights.retain(|highlight| {
19538            while let Some(range_to_remove) = ranges_to_remove.peek() {
19539                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19540                    Ordering::Less | Ordering::Equal => {
19541                        ranges_to_remove.next();
19542                    }
19543                    Ordering::Greater => {
19544                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19545                            Ordering::Less | Ordering::Equal => {
19546                                return false;
19547                            }
19548                            Ordering::Greater => break,
19549                        }
19550                    }
19551                }
19552            }
19553
19554            true
19555        })
19556    }
19557
19558    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19559    pub fn clear_row_highlights<T: 'static>(&mut self) {
19560        self.highlighted_rows.remove(&TypeId::of::<T>());
19561    }
19562
19563    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19564    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19565        self.highlighted_rows
19566            .get(&TypeId::of::<T>())
19567            .map_or(&[] as &[_], |vec| vec.as_slice())
19568            .iter()
19569            .map(|highlight| (highlight.range.clone(), highlight.color))
19570    }
19571
19572    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19573    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19574    /// Allows to ignore certain kinds of highlights.
19575    pub fn highlighted_display_rows(
19576        &self,
19577        window: &mut Window,
19578        cx: &mut App,
19579    ) -> BTreeMap<DisplayRow, LineHighlight> {
19580        let snapshot = self.snapshot(window, cx);
19581        let mut used_highlight_orders = HashMap::default();
19582        self.highlighted_rows
19583            .iter()
19584            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19585            .fold(
19586                BTreeMap::<DisplayRow, LineHighlight>::new(),
19587                |mut unique_rows, highlight| {
19588                    let start = highlight.range.start.to_display_point(&snapshot);
19589                    let end = highlight.range.end.to_display_point(&snapshot);
19590                    let start_row = start.row().0;
19591                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19592                        && end.column() == 0
19593                    {
19594                        end.row().0.saturating_sub(1)
19595                    } else {
19596                        end.row().0
19597                    };
19598                    for row in start_row..=end_row {
19599                        let used_index =
19600                            used_highlight_orders.entry(row).or_insert(highlight.index);
19601                        if highlight.index >= *used_index {
19602                            *used_index = highlight.index;
19603                            unique_rows.insert(
19604                                DisplayRow(row),
19605                                LineHighlight {
19606                                    include_gutter: highlight.options.include_gutter,
19607                                    border: None,
19608                                    background: highlight.color.into(),
19609                                    type_id: Some(highlight.type_id),
19610                                },
19611                            );
19612                        }
19613                    }
19614                    unique_rows
19615                },
19616            )
19617    }
19618
19619    pub fn highlighted_display_row_for_autoscroll(
19620        &self,
19621        snapshot: &DisplaySnapshot,
19622    ) -> Option<DisplayRow> {
19623        self.highlighted_rows
19624            .values()
19625            .flat_map(|highlighted_rows| highlighted_rows.iter())
19626            .filter_map(|highlight| {
19627                if highlight.options.autoscroll {
19628                    Some(highlight.range.start.to_display_point(snapshot).row())
19629                } else {
19630                    None
19631                }
19632            })
19633            .min()
19634    }
19635
19636    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19637        self.highlight_background::<SearchWithinRange>(
19638            ranges,
19639            |colors| colors.colors().editor_document_highlight_read_background,
19640            cx,
19641        )
19642    }
19643
19644    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19645        self.breadcrumb_header = Some(new_header);
19646    }
19647
19648    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19649        self.clear_background_highlights::<SearchWithinRange>(cx);
19650    }
19651
19652    pub fn highlight_background<T: 'static>(
19653        &mut self,
19654        ranges: &[Range<Anchor>],
19655        color_fetcher: fn(&Theme) -> Hsla,
19656        cx: &mut Context<Self>,
19657    ) {
19658        self.background_highlights.insert(
19659            HighlightKey::Type(TypeId::of::<T>()),
19660            (color_fetcher, Arc::from(ranges)),
19661        );
19662        self.scrollbar_marker_state.dirty = true;
19663        cx.notify();
19664    }
19665
19666    pub fn highlight_background_key<T: 'static>(
19667        &mut self,
19668        key: usize,
19669        ranges: &[Range<Anchor>],
19670        color_fetcher: fn(&Theme) -> Hsla,
19671        cx: &mut Context<Self>,
19672    ) {
19673        self.background_highlights.insert(
19674            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19675            (color_fetcher, Arc::from(ranges)),
19676        );
19677        self.scrollbar_marker_state.dirty = true;
19678        cx.notify();
19679    }
19680
19681    pub fn clear_background_highlights<T: 'static>(
19682        &mut self,
19683        cx: &mut Context<Self>,
19684    ) -> Option<BackgroundHighlight> {
19685        let text_highlights = self
19686            .background_highlights
19687            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19688        if !text_highlights.1.is_empty() {
19689            self.scrollbar_marker_state.dirty = true;
19690            cx.notify();
19691        }
19692        Some(text_highlights)
19693    }
19694
19695    pub fn highlight_gutter<T: 'static>(
19696        &mut self,
19697        ranges: impl Into<Vec<Range<Anchor>>>,
19698        color_fetcher: fn(&App) -> Hsla,
19699        cx: &mut Context<Self>,
19700    ) {
19701        self.gutter_highlights
19702            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19703        cx.notify();
19704    }
19705
19706    pub fn clear_gutter_highlights<T: 'static>(
19707        &mut self,
19708        cx: &mut Context<Self>,
19709    ) -> Option<GutterHighlight> {
19710        cx.notify();
19711        self.gutter_highlights.remove(&TypeId::of::<T>())
19712    }
19713
19714    pub fn insert_gutter_highlight<T: 'static>(
19715        &mut self,
19716        range: Range<Anchor>,
19717        color_fetcher: fn(&App) -> Hsla,
19718        cx: &mut Context<Self>,
19719    ) {
19720        let snapshot = self.buffer().read(cx).snapshot(cx);
19721        let mut highlights = self
19722            .gutter_highlights
19723            .remove(&TypeId::of::<T>())
19724            .map(|(_, highlights)| highlights)
19725            .unwrap_or_default();
19726        let ix = highlights.binary_search_by(|highlight| {
19727            Ordering::Equal
19728                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19729                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19730        });
19731        if let Err(ix) = ix {
19732            highlights.insert(ix, range);
19733        }
19734        self.gutter_highlights
19735            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19736    }
19737
19738    pub fn remove_gutter_highlights<T: 'static>(
19739        &mut self,
19740        ranges_to_remove: Vec<Range<Anchor>>,
19741        cx: &mut Context<Self>,
19742    ) {
19743        let snapshot = self.buffer().read(cx).snapshot(cx);
19744        let Some((color_fetcher, mut gutter_highlights)) =
19745            self.gutter_highlights.remove(&TypeId::of::<T>())
19746        else {
19747            return;
19748        };
19749        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19750        gutter_highlights.retain(|highlight| {
19751            while let Some(range_to_remove) = ranges_to_remove.peek() {
19752                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19753                    Ordering::Less | Ordering::Equal => {
19754                        ranges_to_remove.next();
19755                    }
19756                    Ordering::Greater => {
19757                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19758                            Ordering::Less | Ordering::Equal => {
19759                                return false;
19760                            }
19761                            Ordering::Greater => break,
19762                        }
19763                    }
19764                }
19765            }
19766
19767            true
19768        });
19769        self.gutter_highlights
19770            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19771    }
19772
19773    #[cfg(feature = "test-support")]
19774    pub fn all_text_highlights(
19775        &self,
19776        window: &mut Window,
19777        cx: &mut Context<Self>,
19778    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19779        let snapshot = self.snapshot(window, cx);
19780        self.display_map.update(cx, |display_map, _| {
19781            display_map
19782                .all_text_highlights()
19783                .map(|highlight| {
19784                    let (style, ranges) = highlight.as_ref();
19785                    (
19786                        *style,
19787                        ranges
19788                            .iter()
19789                            .map(|range| range.clone().to_display_points(&snapshot))
19790                            .collect(),
19791                    )
19792                })
19793                .collect()
19794        })
19795    }
19796
19797    #[cfg(feature = "test-support")]
19798    pub fn all_text_background_highlights(
19799        &self,
19800        window: &mut Window,
19801        cx: &mut Context<Self>,
19802    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19803        let snapshot = self.snapshot(window, cx);
19804        let buffer = &snapshot.buffer_snapshot;
19805        let start = buffer.anchor_before(0);
19806        let end = buffer.anchor_after(buffer.len());
19807        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
19808    }
19809
19810    #[cfg(any(test, feature = "test-support"))]
19811    pub fn sorted_background_highlights_in_range(
19812        &self,
19813        search_range: Range<Anchor>,
19814        display_snapshot: &DisplaySnapshot,
19815        theme: &Theme,
19816    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19817        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
19818        res.sort_by(|a, b| {
19819            a.0.start
19820                .cmp(&b.0.start)
19821                .then_with(|| a.0.end.cmp(&b.0.end))
19822                .then_with(|| a.1.cmp(&b.1))
19823        });
19824        res
19825    }
19826
19827    #[cfg(feature = "test-support")]
19828    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19829        let snapshot = self.buffer().read(cx).snapshot(cx);
19830
19831        let highlights = self
19832            .background_highlights
19833            .get(&HighlightKey::Type(TypeId::of::<
19834                items::BufferSearchHighlights,
19835            >()));
19836
19837        if let Some((_color, ranges)) = highlights {
19838            ranges
19839                .iter()
19840                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19841                .collect_vec()
19842        } else {
19843            vec![]
19844        }
19845    }
19846
19847    fn document_highlights_for_position<'a>(
19848        &'a self,
19849        position: Anchor,
19850        buffer: &'a MultiBufferSnapshot,
19851    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19852        let read_highlights = self
19853            .background_highlights
19854            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19855            .map(|h| &h.1);
19856        let write_highlights = self
19857            .background_highlights
19858            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19859            .map(|h| &h.1);
19860        let left_position = position.bias_left(buffer);
19861        let right_position = position.bias_right(buffer);
19862        read_highlights
19863            .into_iter()
19864            .chain(write_highlights)
19865            .flat_map(move |ranges| {
19866                let start_ix = match ranges.binary_search_by(|probe| {
19867                    let cmp = probe.end.cmp(&left_position, buffer);
19868                    if cmp.is_ge() {
19869                        Ordering::Greater
19870                    } else {
19871                        Ordering::Less
19872                    }
19873                }) {
19874                    Ok(i) | Err(i) => i,
19875                };
19876
19877                ranges[start_ix..]
19878                    .iter()
19879                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19880            })
19881    }
19882
19883    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19884        self.background_highlights
19885            .get(&HighlightKey::Type(TypeId::of::<T>()))
19886            .is_some_and(|(_, highlights)| !highlights.is_empty())
19887    }
19888
19889    /// Returns all background highlights for a given range.
19890    ///
19891    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
19892    pub fn background_highlights_in_range(
19893        &self,
19894        search_range: Range<Anchor>,
19895        display_snapshot: &DisplaySnapshot,
19896        theme: &Theme,
19897    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19898        let mut results = Vec::new();
19899        for (color_fetcher, ranges) in self.background_highlights.values() {
19900            let color = color_fetcher(theme);
19901            let start_ix = match ranges.binary_search_by(|probe| {
19902                let cmp = probe
19903                    .end
19904                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19905                if cmp.is_gt() {
19906                    Ordering::Greater
19907                } else {
19908                    Ordering::Less
19909                }
19910            }) {
19911                Ok(i) | Err(i) => i,
19912            };
19913            for range in &ranges[start_ix..] {
19914                if range
19915                    .start
19916                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19917                    .is_ge()
19918                {
19919                    break;
19920                }
19921
19922                let start = range.start.to_display_point(display_snapshot);
19923                let end = range.end.to_display_point(display_snapshot);
19924                results.push((start..end, color))
19925            }
19926        }
19927        results
19928    }
19929
19930    pub fn gutter_highlights_in_range(
19931        &self,
19932        search_range: Range<Anchor>,
19933        display_snapshot: &DisplaySnapshot,
19934        cx: &App,
19935    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19936        let mut results = Vec::new();
19937        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19938            let color = color_fetcher(cx);
19939            let start_ix = match ranges.binary_search_by(|probe| {
19940                let cmp = probe
19941                    .end
19942                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19943                if cmp.is_gt() {
19944                    Ordering::Greater
19945                } else {
19946                    Ordering::Less
19947                }
19948            }) {
19949                Ok(i) | Err(i) => i,
19950            };
19951            for range in &ranges[start_ix..] {
19952                if range
19953                    .start
19954                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19955                    .is_ge()
19956                {
19957                    break;
19958                }
19959
19960                let start = range.start.to_display_point(display_snapshot);
19961                let end = range.end.to_display_point(display_snapshot);
19962                results.push((start..end, color))
19963            }
19964        }
19965        results
19966    }
19967
19968    /// Get the text ranges corresponding to the redaction query
19969    pub fn redacted_ranges(
19970        &self,
19971        search_range: Range<Anchor>,
19972        display_snapshot: &DisplaySnapshot,
19973        cx: &App,
19974    ) -> Vec<Range<DisplayPoint>> {
19975        display_snapshot
19976            .buffer_snapshot
19977            .redacted_ranges(search_range, |file| {
19978                if let Some(file) = file {
19979                    file.is_private()
19980                        && EditorSettings::get(
19981                            Some(SettingsLocation {
19982                                worktree_id: file.worktree_id(cx),
19983                                path: file.path().as_ref(),
19984                            }),
19985                            cx,
19986                        )
19987                        .redact_private_values
19988                } else {
19989                    false
19990                }
19991            })
19992            .map(|range| {
19993                range.start.to_display_point(display_snapshot)
19994                    ..range.end.to_display_point(display_snapshot)
19995            })
19996            .collect()
19997    }
19998
19999    pub fn highlight_text_key<T: 'static>(
20000        &mut self,
20001        key: usize,
20002        ranges: Vec<Range<Anchor>>,
20003        style: HighlightStyle,
20004        cx: &mut Context<Self>,
20005    ) {
20006        self.display_map.update(cx, |map, _| {
20007            map.highlight_text(
20008                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20009                ranges,
20010                style,
20011            );
20012        });
20013        cx.notify();
20014    }
20015
20016    pub fn highlight_text<T: 'static>(
20017        &mut self,
20018        ranges: Vec<Range<Anchor>>,
20019        style: HighlightStyle,
20020        cx: &mut Context<Self>,
20021    ) {
20022        self.display_map.update(cx, |map, _| {
20023            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20024        });
20025        cx.notify();
20026    }
20027
20028    pub(crate) fn highlight_inlays<T: 'static>(
20029        &mut self,
20030        highlights: Vec<InlayHighlight>,
20031        style: HighlightStyle,
20032        cx: &mut Context<Self>,
20033    ) {
20034        self.display_map.update(cx, |map, _| {
20035            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20036        });
20037        cx.notify();
20038    }
20039
20040    pub fn text_highlights<'a, T: 'static>(
20041        &'a self,
20042        cx: &'a App,
20043    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20044        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20045    }
20046
20047    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20048        let cleared = self
20049            .display_map
20050            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20051        if cleared {
20052            cx.notify();
20053        }
20054    }
20055
20056    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20057        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20058            && self.focus_handle.is_focused(window)
20059    }
20060
20061    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20062        self.show_cursor_when_unfocused = is_enabled;
20063        cx.notify();
20064    }
20065
20066    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20067        cx.notify();
20068    }
20069
20070    fn on_debug_session_event(
20071        &mut self,
20072        _session: Entity<Session>,
20073        event: &SessionEvent,
20074        cx: &mut Context<Self>,
20075    ) {
20076        if let SessionEvent::InvalidateInlineValue = event {
20077            self.refresh_inline_values(cx);
20078        }
20079    }
20080
20081    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20082        let Some(project) = self.project.clone() else {
20083            return;
20084        };
20085
20086        if !self.inline_value_cache.enabled {
20087            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20088            self.splice_inlays(&inlays, Vec::new(), cx);
20089            return;
20090        }
20091
20092        let current_execution_position = self
20093            .highlighted_rows
20094            .get(&TypeId::of::<ActiveDebugLine>())
20095            .and_then(|lines| lines.last().map(|line| line.range.end));
20096
20097        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20098            let inline_values = editor
20099                .update(cx, |editor, cx| {
20100                    let Some(current_execution_position) = current_execution_position else {
20101                        return Some(Task::ready(Ok(Vec::new())));
20102                    };
20103
20104                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20105                        let snapshot = buffer.snapshot(cx);
20106
20107                        let excerpt = snapshot.excerpt_containing(
20108                            current_execution_position..current_execution_position,
20109                        )?;
20110
20111                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20112                    })?;
20113
20114                    let range =
20115                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20116
20117                    project.inline_values(buffer, range, cx)
20118                })
20119                .ok()
20120                .flatten()?
20121                .await
20122                .context("refreshing debugger inlays")
20123                .log_err()?;
20124
20125            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20126
20127            for (buffer_id, inline_value) in inline_values
20128                .into_iter()
20129                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20130            {
20131                buffer_inline_values
20132                    .entry(buffer_id)
20133                    .or_default()
20134                    .push(inline_value);
20135            }
20136
20137            editor
20138                .update(cx, |editor, cx| {
20139                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20140                    let mut new_inlays = Vec::default();
20141
20142                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20143                        let buffer_id = buffer_snapshot.remote_id();
20144                        buffer_inline_values
20145                            .get(&buffer_id)
20146                            .into_iter()
20147                            .flatten()
20148                            .for_each(|hint| {
20149                                let inlay = Inlay::debugger(
20150                                    post_inc(&mut editor.next_inlay_id),
20151                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20152                                    hint.text(),
20153                                );
20154                                if !inlay.text.chars().contains(&'\n') {
20155                                    new_inlays.push(inlay);
20156                                }
20157                            });
20158                    }
20159
20160                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20161                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20162
20163                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20164                })
20165                .ok()?;
20166            Some(())
20167        });
20168    }
20169
20170    fn on_buffer_event(
20171        &mut self,
20172        multibuffer: &Entity<MultiBuffer>,
20173        event: &multi_buffer::Event,
20174        window: &mut Window,
20175        cx: &mut Context<Self>,
20176    ) {
20177        match event {
20178            multi_buffer::Event::Edited {
20179                singleton_buffer_edited,
20180                edited_buffer,
20181            } => {
20182                self.scrollbar_marker_state.dirty = true;
20183                self.active_indent_guides_state.dirty = true;
20184                self.refresh_active_diagnostics(cx);
20185                self.refresh_code_actions(window, cx);
20186                self.refresh_selected_text_highlights(true, window, cx);
20187                self.refresh_single_line_folds(window, cx);
20188                refresh_matching_bracket_highlights(self, window, cx);
20189                if self.has_active_edit_prediction() {
20190                    self.update_visible_edit_prediction(window, cx);
20191                }
20192                if let Some(project) = self.project.as_ref()
20193                    && let Some(edited_buffer) = edited_buffer
20194                {
20195                    project.update(cx, |project, cx| {
20196                        self.registered_buffers
20197                            .entry(edited_buffer.read(cx).remote_id())
20198                            .or_insert_with(|| {
20199                                project.register_buffer_with_language_servers(edited_buffer, cx)
20200                            });
20201                    });
20202                }
20203                cx.emit(EditorEvent::BufferEdited);
20204                cx.emit(SearchEvent::MatchesInvalidated);
20205
20206                if let Some(buffer) = edited_buffer {
20207                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20208                }
20209
20210                if *singleton_buffer_edited {
20211                    if let Some(buffer) = edited_buffer
20212                        && buffer.read(cx).file().is_none()
20213                    {
20214                        cx.emit(EditorEvent::TitleChanged);
20215                    }
20216                    if let Some(project) = &self.project {
20217                        #[allow(clippy::mutable_key_type)]
20218                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20219                            multibuffer
20220                                .all_buffers()
20221                                .into_iter()
20222                                .filter_map(|buffer| {
20223                                    buffer.update(cx, |buffer, cx| {
20224                                        let language = buffer.language()?;
20225                                        let should_discard = project.update(cx, |project, cx| {
20226                                            project.is_local()
20227                                                && !project.has_language_servers_for(buffer, cx)
20228                                        });
20229                                        should_discard.not().then_some(language.clone())
20230                                    })
20231                                })
20232                                .collect::<HashSet<_>>()
20233                        });
20234                        if !languages_affected.is_empty() {
20235                            self.refresh_inlay_hints(
20236                                InlayHintRefreshReason::BufferEdited(languages_affected),
20237                                cx,
20238                            );
20239                        }
20240                    }
20241                }
20242
20243                let Some(project) = &self.project else { return };
20244                let (telemetry, is_via_ssh) = {
20245                    let project = project.read(cx);
20246                    let telemetry = project.client().telemetry().clone();
20247                    let is_via_ssh = project.is_via_remote_server();
20248                    (telemetry, is_via_ssh)
20249                };
20250                refresh_linked_ranges(self, window, cx);
20251                telemetry.log_edit_event("editor", is_via_ssh);
20252            }
20253            multi_buffer::Event::ExcerptsAdded {
20254                buffer,
20255                predecessor,
20256                excerpts,
20257            } => {
20258                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20259                let buffer_id = buffer.read(cx).remote_id();
20260                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20261                    && let Some(project) = &self.project
20262                {
20263                    update_uncommitted_diff_for_buffer(
20264                        cx.entity(),
20265                        project,
20266                        [buffer.clone()],
20267                        self.buffer.clone(),
20268                        cx,
20269                    )
20270                    .detach();
20271                }
20272                self.update_lsp_data(false, Some(buffer_id), window, cx);
20273                cx.emit(EditorEvent::ExcerptsAdded {
20274                    buffer: buffer.clone(),
20275                    predecessor: *predecessor,
20276                    excerpts: excerpts.clone(),
20277                });
20278                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20279            }
20280            multi_buffer::Event::ExcerptsRemoved {
20281                ids,
20282                removed_buffer_ids,
20283            } => {
20284                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20285                let buffer = self.buffer.read(cx);
20286                self.registered_buffers
20287                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20288                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20289                cx.emit(EditorEvent::ExcerptsRemoved {
20290                    ids: ids.clone(),
20291                    removed_buffer_ids: removed_buffer_ids.clone(),
20292                });
20293            }
20294            multi_buffer::Event::ExcerptsEdited {
20295                excerpt_ids,
20296                buffer_ids,
20297            } => {
20298                self.display_map.update(cx, |map, cx| {
20299                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20300                });
20301                cx.emit(EditorEvent::ExcerptsEdited {
20302                    ids: excerpt_ids.clone(),
20303                });
20304            }
20305            multi_buffer::Event::ExcerptsExpanded { ids } => {
20306                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20307                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20308            }
20309            multi_buffer::Event::Reparsed(buffer_id) => {
20310                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20311                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20312
20313                cx.emit(EditorEvent::Reparsed(*buffer_id));
20314            }
20315            multi_buffer::Event::DiffHunksToggled => {
20316                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20317            }
20318            multi_buffer::Event::LanguageChanged(buffer_id) => {
20319                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20320                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20321                cx.emit(EditorEvent::Reparsed(*buffer_id));
20322                cx.notify();
20323            }
20324            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20325            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20326            multi_buffer::Event::FileHandleChanged
20327            | multi_buffer::Event::Reloaded
20328            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20329            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20330            multi_buffer::Event::DiagnosticsUpdated => {
20331                self.update_diagnostics_state(window, cx);
20332            }
20333            _ => {}
20334        };
20335    }
20336
20337    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20338        if !self.diagnostics_enabled() {
20339            return;
20340        }
20341        self.refresh_active_diagnostics(cx);
20342        self.refresh_inline_diagnostics(true, window, cx);
20343        self.scrollbar_marker_state.dirty = true;
20344        cx.notify();
20345    }
20346
20347    pub fn start_temporary_diff_override(&mut self) {
20348        self.load_diff_task.take();
20349        self.temporary_diff_override = true;
20350    }
20351
20352    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20353        self.temporary_diff_override = false;
20354        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20355        self.buffer.update(cx, |buffer, cx| {
20356            buffer.set_all_diff_hunks_collapsed(cx);
20357        });
20358
20359        if let Some(project) = self.project.clone() {
20360            self.load_diff_task = Some(
20361                update_uncommitted_diff_for_buffer(
20362                    cx.entity(),
20363                    &project,
20364                    self.buffer.read(cx).all_buffers(),
20365                    self.buffer.clone(),
20366                    cx,
20367                )
20368                .shared(),
20369            );
20370        }
20371    }
20372
20373    fn on_display_map_changed(
20374        &mut self,
20375        _: Entity<DisplayMap>,
20376        _: &mut Window,
20377        cx: &mut Context<Self>,
20378    ) {
20379        cx.notify();
20380    }
20381
20382    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20383        if self.diagnostics_enabled() {
20384            let new_severity = EditorSettings::get_global(cx)
20385                .diagnostics_max_severity
20386                .unwrap_or(DiagnosticSeverity::Hint);
20387            self.set_max_diagnostics_severity(new_severity, cx);
20388        }
20389        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20390        self.update_edit_prediction_settings(cx);
20391        self.refresh_edit_prediction(true, false, window, cx);
20392        self.refresh_inline_values(cx);
20393        self.refresh_inlay_hints(
20394            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20395                self.selections.newest_anchor().head(),
20396                &self.buffer.read(cx).snapshot(cx),
20397                cx,
20398            )),
20399            cx,
20400        );
20401
20402        let old_cursor_shape = self.cursor_shape;
20403        let old_show_breadcrumbs = self.show_breadcrumbs;
20404
20405        {
20406            let editor_settings = EditorSettings::get_global(cx);
20407            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20408            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20409            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20410            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20411        }
20412
20413        if old_cursor_shape != self.cursor_shape {
20414            cx.emit(EditorEvent::CursorShapeChanged);
20415        }
20416
20417        if old_show_breadcrumbs != self.show_breadcrumbs {
20418            cx.emit(EditorEvent::BreadcrumbsChanged);
20419        }
20420
20421        let project_settings = ProjectSettings::get_global(cx);
20422        self.serialize_dirty_buffers =
20423            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20424
20425        if self.mode.is_full() {
20426            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20427            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20428            if self.show_inline_diagnostics != show_inline_diagnostics {
20429                self.show_inline_diagnostics = show_inline_diagnostics;
20430                self.refresh_inline_diagnostics(false, window, cx);
20431            }
20432
20433            if self.git_blame_inline_enabled != inline_blame_enabled {
20434                self.toggle_git_blame_inline_internal(false, window, cx);
20435            }
20436
20437            let minimap_settings = EditorSettings::get_global(cx).minimap;
20438            if self.minimap_visibility != MinimapVisibility::Disabled {
20439                if self.minimap_visibility.settings_visibility()
20440                    != minimap_settings.minimap_enabled()
20441                {
20442                    self.set_minimap_visibility(
20443                        MinimapVisibility::for_mode(self.mode(), cx),
20444                        window,
20445                        cx,
20446                    );
20447                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20448                    minimap_entity.update(cx, |minimap_editor, cx| {
20449                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20450                    })
20451                }
20452            }
20453        }
20454
20455        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20456            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20457        }) {
20458            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20459                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20460            }
20461            self.refresh_colors(false, None, window, cx);
20462        }
20463
20464        cx.notify();
20465    }
20466
20467    pub fn set_searchable(&mut self, searchable: bool) {
20468        self.searchable = searchable;
20469    }
20470
20471    pub fn searchable(&self) -> bool {
20472        self.searchable
20473    }
20474
20475    fn open_proposed_changes_editor(
20476        &mut self,
20477        _: &OpenProposedChangesEditor,
20478        window: &mut Window,
20479        cx: &mut Context<Self>,
20480    ) {
20481        let Some(workspace) = self.workspace() else {
20482            cx.propagate();
20483            return;
20484        };
20485
20486        let selections = self.selections.all::<usize>(cx);
20487        let multi_buffer = self.buffer.read(cx);
20488        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20489        let mut new_selections_by_buffer = HashMap::default();
20490        for selection in selections {
20491            for (buffer, range, _) in
20492                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20493            {
20494                let mut range = range.to_point(buffer);
20495                range.start.column = 0;
20496                range.end.column = buffer.line_len(range.end.row);
20497                new_selections_by_buffer
20498                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20499                    .or_insert(Vec::new())
20500                    .push(range)
20501            }
20502        }
20503
20504        let proposed_changes_buffers = new_selections_by_buffer
20505            .into_iter()
20506            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20507            .collect::<Vec<_>>();
20508        let proposed_changes_editor = cx.new(|cx| {
20509            ProposedChangesEditor::new(
20510                "Proposed changes",
20511                proposed_changes_buffers,
20512                self.project.clone(),
20513                window,
20514                cx,
20515            )
20516        });
20517
20518        window.defer(cx, move |window, cx| {
20519            workspace.update(cx, |workspace, cx| {
20520                workspace.active_pane().update(cx, |pane, cx| {
20521                    pane.add_item(
20522                        Box::new(proposed_changes_editor),
20523                        true,
20524                        true,
20525                        None,
20526                        window,
20527                        cx,
20528                    );
20529                });
20530            });
20531        });
20532    }
20533
20534    pub fn open_excerpts_in_split(
20535        &mut self,
20536        _: &OpenExcerptsSplit,
20537        window: &mut Window,
20538        cx: &mut Context<Self>,
20539    ) {
20540        self.open_excerpts_common(None, true, window, cx)
20541    }
20542
20543    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20544        self.open_excerpts_common(None, false, window, cx)
20545    }
20546
20547    fn open_excerpts_common(
20548        &mut self,
20549        jump_data: Option<JumpData>,
20550        split: bool,
20551        window: &mut Window,
20552        cx: &mut Context<Self>,
20553    ) {
20554        let Some(workspace) = self.workspace() else {
20555            cx.propagate();
20556            return;
20557        };
20558
20559        if self.buffer.read(cx).is_singleton() {
20560            cx.propagate();
20561            return;
20562        }
20563
20564        let mut new_selections_by_buffer = HashMap::default();
20565        match &jump_data {
20566            Some(JumpData::MultiBufferPoint {
20567                excerpt_id,
20568                position,
20569                anchor,
20570                line_offset_from_top,
20571            }) => {
20572                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20573                if let Some(buffer) = multi_buffer_snapshot
20574                    .buffer_id_for_excerpt(*excerpt_id)
20575                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20576                {
20577                    let buffer_snapshot = buffer.read(cx).snapshot();
20578                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20579                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20580                    } else {
20581                        buffer_snapshot.clip_point(*position, Bias::Left)
20582                    };
20583                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20584                    new_selections_by_buffer.insert(
20585                        buffer,
20586                        (
20587                            vec![jump_to_offset..jump_to_offset],
20588                            Some(*line_offset_from_top),
20589                        ),
20590                    );
20591                }
20592            }
20593            Some(JumpData::MultiBufferRow {
20594                row,
20595                line_offset_from_top,
20596            }) => {
20597                let point = MultiBufferPoint::new(row.0, 0);
20598                if let Some((buffer, buffer_point, _)) =
20599                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20600                {
20601                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20602                    new_selections_by_buffer
20603                        .entry(buffer)
20604                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20605                        .0
20606                        .push(buffer_offset..buffer_offset)
20607                }
20608            }
20609            None => {
20610                let selections = self.selections.all::<usize>(cx);
20611                let multi_buffer = self.buffer.read(cx);
20612                for selection in selections {
20613                    for (snapshot, range, _, anchor) in multi_buffer
20614                        .snapshot(cx)
20615                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20616                    {
20617                        if let Some(anchor) = anchor {
20618                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20619                            else {
20620                                continue;
20621                            };
20622                            let offset = text::ToOffset::to_offset(
20623                                &anchor.text_anchor,
20624                                &buffer_handle.read(cx).snapshot(),
20625                            );
20626                            let range = offset..offset;
20627                            new_selections_by_buffer
20628                                .entry(buffer_handle)
20629                                .or_insert((Vec::new(), None))
20630                                .0
20631                                .push(range)
20632                        } else {
20633                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20634                            else {
20635                                continue;
20636                            };
20637                            new_selections_by_buffer
20638                                .entry(buffer_handle)
20639                                .or_insert((Vec::new(), None))
20640                                .0
20641                                .push(range)
20642                        }
20643                    }
20644                }
20645            }
20646        }
20647
20648        new_selections_by_buffer
20649            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20650
20651        if new_selections_by_buffer.is_empty() {
20652            return;
20653        }
20654
20655        // We defer the pane interaction because we ourselves are a workspace item
20656        // and activating a new item causes the pane to call a method on us reentrantly,
20657        // which panics if we're on the stack.
20658        window.defer(cx, move |window, cx| {
20659            workspace.update(cx, |workspace, cx| {
20660                let pane = if split {
20661                    workspace.adjacent_pane(window, cx)
20662                } else {
20663                    workspace.active_pane().clone()
20664                };
20665
20666                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20667                    let editor = buffer
20668                        .read(cx)
20669                        .file()
20670                        .is_none()
20671                        .then(|| {
20672                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20673                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20674                            // Instead, we try to activate the existing editor in the pane first.
20675                            let (editor, pane_item_index) =
20676                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20677                                    let editor = item.downcast::<Editor>()?;
20678                                    let singleton_buffer =
20679                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20680                                    if singleton_buffer == buffer {
20681                                        Some((editor, i))
20682                                    } else {
20683                                        None
20684                                    }
20685                                })?;
20686                            pane.update(cx, |pane, cx| {
20687                                pane.activate_item(pane_item_index, true, true, window, cx)
20688                            });
20689                            Some(editor)
20690                        })
20691                        .flatten()
20692                        .unwrap_or_else(|| {
20693                            workspace.open_project_item::<Self>(
20694                                pane.clone(),
20695                                buffer,
20696                                true,
20697                                true,
20698                                window,
20699                                cx,
20700                            )
20701                        });
20702
20703                    editor.update(cx, |editor, cx| {
20704                        let autoscroll = match scroll_offset {
20705                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20706                            None => Autoscroll::newest(),
20707                        };
20708                        let nav_history = editor.nav_history.take();
20709                        editor.change_selections(
20710                            SelectionEffects::scroll(autoscroll),
20711                            window,
20712                            cx,
20713                            |s| {
20714                                s.select_ranges(ranges);
20715                            },
20716                        );
20717                        editor.nav_history = nav_history;
20718                    });
20719                }
20720            })
20721        });
20722    }
20723
20724    // For now, don't allow opening excerpts in buffers that aren't backed by
20725    // regular project files.
20726    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20727        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20728    }
20729
20730    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20731        let snapshot = self.buffer.read(cx).read(cx);
20732        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20733        Some(
20734            ranges
20735                .iter()
20736                .map(move |range| {
20737                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20738                })
20739                .collect(),
20740        )
20741    }
20742
20743    fn selection_replacement_ranges(
20744        &self,
20745        range: Range<OffsetUtf16>,
20746        cx: &mut App,
20747    ) -> Vec<Range<OffsetUtf16>> {
20748        let selections = self.selections.all::<OffsetUtf16>(cx);
20749        let newest_selection = selections
20750            .iter()
20751            .max_by_key(|selection| selection.id)
20752            .unwrap();
20753        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20754        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20755        let snapshot = self.buffer.read(cx).read(cx);
20756        selections
20757            .into_iter()
20758            .map(|mut selection| {
20759                selection.start.0 =
20760                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20761                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20762                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20763                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20764            })
20765            .collect()
20766    }
20767
20768    fn report_editor_event(
20769        &self,
20770        reported_event: ReportEditorEvent,
20771        file_extension: Option<String>,
20772        cx: &App,
20773    ) {
20774        if cfg!(any(test, feature = "test-support")) {
20775            return;
20776        }
20777
20778        let Some(project) = &self.project else { return };
20779
20780        // If None, we are in a file without an extension
20781        let file = self
20782            .buffer
20783            .read(cx)
20784            .as_singleton()
20785            .and_then(|b| b.read(cx).file());
20786        let file_extension = file_extension.or(file
20787            .as_ref()
20788            .and_then(|file| Path::new(file.file_name(cx)).extension())
20789            .and_then(|e| e.to_str())
20790            .map(|a| a.to_string()));
20791
20792        let vim_mode = vim_enabled(cx);
20793
20794        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20795        let copilot_enabled = edit_predictions_provider
20796            == language::language_settings::EditPredictionProvider::Copilot;
20797        let copilot_enabled_for_language = self
20798            .buffer
20799            .read(cx)
20800            .language_settings(cx)
20801            .show_edit_predictions;
20802
20803        let project = project.read(cx);
20804        let event_type = reported_event.event_type();
20805
20806        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20807            telemetry::event!(
20808                event_type,
20809                type = if auto_saved {"autosave"} else {"manual"},
20810                file_extension,
20811                vim_mode,
20812                copilot_enabled,
20813                copilot_enabled_for_language,
20814                edit_predictions_provider,
20815                is_via_ssh = project.is_via_remote_server(),
20816            );
20817        } else {
20818            telemetry::event!(
20819                event_type,
20820                file_extension,
20821                vim_mode,
20822                copilot_enabled,
20823                copilot_enabled_for_language,
20824                edit_predictions_provider,
20825                is_via_ssh = project.is_via_remote_server(),
20826            );
20827        };
20828    }
20829
20830    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20831    /// with each line being an array of {text, highlight} objects.
20832    fn copy_highlight_json(
20833        &mut self,
20834        _: &CopyHighlightJson,
20835        window: &mut Window,
20836        cx: &mut Context<Self>,
20837    ) {
20838        #[derive(Serialize)]
20839        struct Chunk<'a> {
20840            text: String,
20841            highlight: Option<&'a str>,
20842        }
20843
20844        let snapshot = self.buffer.read(cx).snapshot(cx);
20845        let range = self
20846            .selected_text_range(false, window, cx)
20847            .and_then(|selection| {
20848                if selection.range.is_empty() {
20849                    None
20850                } else {
20851                    Some(selection.range)
20852                }
20853            })
20854            .unwrap_or_else(|| 0..snapshot.len());
20855
20856        let chunks = snapshot.chunks(range, true);
20857        let mut lines = Vec::new();
20858        let mut line: VecDeque<Chunk> = VecDeque::new();
20859
20860        let Some(style) = self.style.as_ref() else {
20861            return;
20862        };
20863
20864        for chunk in chunks {
20865            let highlight = chunk
20866                .syntax_highlight_id
20867                .and_then(|id| id.name(&style.syntax));
20868            let mut chunk_lines = chunk.text.split('\n').peekable();
20869            while let Some(text) = chunk_lines.next() {
20870                let mut merged_with_last_token = false;
20871                if let Some(last_token) = line.back_mut()
20872                    && last_token.highlight == highlight
20873                {
20874                    last_token.text.push_str(text);
20875                    merged_with_last_token = true;
20876                }
20877
20878                if !merged_with_last_token {
20879                    line.push_back(Chunk {
20880                        text: text.into(),
20881                        highlight,
20882                    });
20883                }
20884
20885                if chunk_lines.peek().is_some() {
20886                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20887                        line.pop_front();
20888                    }
20889                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20890                        line.pop_back();
20891                    }
20892
20893                    lines.push(mem::take(&mut line));
20894                }
20895            }
20896        }
20897
20898        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20899            return;
20900        };
20901        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20902    }
20903
20904    pub fn open_context_menu(
20905        &mut self,
20906        _: &OpenContextMenu,
20907        window: &mut Window,
20908        cx: &mut Context<Self>,
20909    ) {
20910        self.request_autoscroll(Autoscroll::newest(), cx);
20911        let position = self.selections.newest_display(cx).start;
20912        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20913    }
20914
20915    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20916        &self.inlay_hint_cache
20917    }
20918
20919    pub fn replay_insert_event(
20920        &mut self,
20921        text: &str,
20922        relative_utf16_range: Option<Range<isize>>,
20923        window: &mut Window,
20924        cx: &mut Context<Self>,
20925    ) {
20926        if !self.input_enabled {
20927            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20928            return;
20929        }
20930        if let Some(relative_utf16_range) = relative_utf16_range {
20931            let selections = self.selections.all::<OffsetUtf16>(cx);
20932            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20933                let new_ranges = selections.into_iter().map(|range| {
20934                    let start = OffsetUtf16(
20935                        range
20936                            .head()
20937                            .0
20938                            .saturating_add_signed(relative_utf16_range.start),
20939                    );
20940                    let end = OffsetUtf16(
20941                        range
20942                            .head()
20943                            .0
20944                            .saturating_add_signed(relative_utf16_range.end),
20945                    );
20946                    start..end
20947                });
20948                s.select_ranges(new_ranges);
20949            });
20950        }
20951
20952        self.handle_input(text, window, cx);
20953    }
20954
20955    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20956        let Some(provider) = self.semantics_provider.as_ref() else {
20957            return false;
20958        };
20959
20960        let mut supports = false;
20961        self.buffer().update(cx, |this, cx| {
20962            this.for_each_buffer(|buffer| {
20963                supports |= provider.supports_inlay_hints(buffer, cx);
20964            });
20965        });
20966
20967        supports
20968    }
20969
20970    pub fn is_focused(&self, window: &Window) -> bool {
20971        self.focus_handle.is_focused(window)
20972    }
20973
20974    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20975        cx.emit(EditorEvent::Focused);
20976
20977        if let Some(descendant) = self
20978            .last_focused_descendant
20979            .take()
20980            .and_then(|descendant| descendant.upgrade())
20981        {
20982            window.focus(&descendant);
20983        } else {
20984            if let Some(blame) = self.blame.as_ref() {
20985                blame.update(cx, GitBlame::focus)
20986            }
20987
20988            self.blink_manager.update(cx, BlinkManager::enable);
20989            self.show_cursor_names(window, cx);
20990            self.buffer.update(cx, |buffer, cx| {
20991                buffer.finalize_last_transaction(cx);
20992                if self.leader_id.is_none() {
20993                    buffer.set_active_selections(
20994                        &self.selections.disjoint_anchors(),
20995                        self.selections.line_mode,
20996                        self.cursor_shape,
20997                        cx,
20998                    );
20999                }
21000            });
21001        }
21002    }
21003
21004    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21005        cx.emit(EditorEvent::FocusedIn)
21006    }
21007
21008    fn handle_focus_out(
21009        &mut self,
21010        event: FocusOutEvent,
21011        _window: &mut Window,
21012        cx: &mut Context<Self>,
21013    ) {
21014        if event.blurred != self.focus_handle {
21015            self.last_focused_descendant = Some(event.blurred);
21016        }
21017        self.selection_drag_state = SelectionDragState::None;
21018        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21019    }
21020
21021    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21022        self.blink_manager.update(cx, BlinkManager::disable);
21023        self.buffer
21024            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21025
21026        if let Some(blame) = self.blame.as_ref() {
21027            blame.update(cx, GitBlame::blur)
21028        }
21029        if !self.hover_state.focused(window, cx) {
21030            hide_hover(self, cx);
21031        }
21032        if !self
21033            .context_menu
21034            .borrow()
21035            .as_ref()
21036            .is_some_and(|context_menu| context_menu.focused(window, cx))
21037        {
21038            self.hide_context_menu(window, cx);
21039        }
21040        self.discard_edit_prediction(false, cx);
21041        cx.emit(EditorEvent::Blurred);
21042        cx.notify();
21043    }
21044
21045    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21046        let mut pending: String = window
21047            .pending_input_keystrokes()
21048            .into_iter()
21049            .flatten()
21050            .filter_map(|keystroke| {
21051                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21052                    keystroke.key_char.clone()
21053                } else {
21054                    None
21055                }
21056            })
21057            .collect();
21058
21059        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21060            pending = "".to_string();
21061        }
21062
21063        let existing_pending = self
21064            .text_highlights::<PendingInput>(cx)
21065            .map(|(_, ranges)| ranges.to_vec());
21066        if existing_pending.is_none() && pending.is_empty() {
21067            return;
21068        }
21069        let transaction =
21070            self.transact(window, cx, |this, window, cx| {
21071                let selections = this.selections.all::<usize>(cx);
21072                let edits = selections
21073                    .iter()
21074                    .map(|selection| (selection.end..selection.end, pending.clone()));
21075                this.edit(edits, cx);
21076                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21077                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21078                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21079                    }));
21080                });
21081                if let Some(existing_ranges) = existing_pending {
21082                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21083                    this.edit(edits, cx);
21084                }
21085            });
21086
21087        let snapshot = self.snapshot(window, cx);
21088        let ranges = self
21089            .selections
21090            .all::<usize>(cx)
21091            .into_iter()
21092            .map(|selection| {
21093                snapshot.buffer_snapshot.anchor_after(selection.end)
21094                    ..snapshot
21095                        .buffer_snapshot
21096                        .anchor_before(selection.end + pending.len())
21097            })
21098            .collect();
21099
21100        if pending.is_empty() {
21101            self.clear_highlights::<PendingInput>(cx);
21102        } else {
21103            self.highlight_text::<PendingInput>(
21104                ranges,
21105                HighlightStyle {
21106                    underline: Some(UnderlineStyle {
21107                        thickness: px(1.),
21108                        color: None,
21109                        wavy: false,
21110                    }),
21111                    ..Default::default()
21112                },
21113                cx,
21114            );
21115        }
21116
21117        self.ime_transaction = self.ime_transaction.or(transaction);
21118        if let Some(transaction) = self.ime_transaction {
21119            self.buffer.update(cx, |buffer, cx| {
21120                buffer.group_until_transaction(transaction, cx);
21121            });
21122        }
21123
21124        if self.text_highlights::<PendingInput>(cx).is_none() {
21125            self.ime_transaction.take();
21126        }
21127    }
21128
21129    pub fn register_action_renderer(
21130        &mut self,
21131        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21132    ) -> Subscription {
21133        let id = self.next_editor_action_id.post_inc();
21134        self.editor_actions
21135            .borrow_mut()
21136            .insert(id, Box::new(listener));
21137
21138        let editor_actions = self.editor_actions.clone();
21139        Subscription::new(move || {
21140            editor_actions.borrow_mut().remove(&id);
21141        })
21142    }
21143
21144    pub fn register_action<A: Action>(
21145        &mut self,
21146        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21147    ) -> Subscription {
21148        let id = self.next_editor_action_id.post_inc();
21149        let listener = Arc::new(listener);
21150        self.editor_actions.borrow_mut().insert(
21151            id,
21152            Box::new(move |_, window, _| {
21153                let listener = listener.clone();
21154                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21155                    let action = action.downcast_ref().unwrap();
21156                    if phase == DispatchPhase::Bubble {
21157                        listener(action, window, cx)
21158                    }
21159                })
21160            }),
21161        );
21162
21163        let editor_actions = self.editor_actions.clone();
21164        Subscription::new(move || {
21165            editor_actions.borrow_mut().remove(&id);
21166        })
21167    }
21168
21169    pub fn file_header_size(&self) -> u32 {
21170        FILE_HEADER_HEIGHT
21171    }
21172
21173    pub fn restore(
21174        &mut self,
21175        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21176        window: &mut Window,
21177        cx: &mut Context<Self>,
21178    ) {
21179        let workspace = self.workspace();
21180        let project = self.project();
21181        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21182            let mut tasks = Vec::new();
21183            for (buffer_id, changes) in revert_changes {
21184                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21185                    buffer.update(cx, |buffer, cx| {
21186                        buffer.edit(
21187                            changes
21188                                .into_iter()
21189                                .map(|(range, text)| (range, text.to_string())),
21190                            None,
21191                            cx,
21192                        );
21193                    });
21194
21195                    if let Some(project) =
21196                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21197                    {
21198                        project.update(cx, |project, cx| {
21199                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21200                        })
21201                    }
21202                }
21203            }
21204            tasks
21205        });
21206        cx.spawn_in(window, async move |_, cx| {
21207            for (buffer, task) in save_tasks {
21208                let result = task.await;
21209                if result.is_err() {
21210                    let Some(path) = buffer
21211                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21212                        .ok()
21213                    else {
21214                        continue;
21215                    };
21216                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21217                        let Some(task) = cx
21218                            .update_window_entity(workspace, |workspace, window, cx| {
21219                                workspace
21220                                    .open_path_preview(path, None, false, false, false, window, cx)
21221                            })
21222                            .ok()
21223                        else {
21224                            continue;
21225                        };
21226                        task.await.log_err();
21227                    }
21228                }
21229            }
21230        })
21231        .detach();
21232        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21233            selections.refresh()
21234        });
21235    }
21236
21237    pub fn to_pixel_point(
21238        &self,
21239        source: multi_buffer::Anchor,
21240        editor_snapshot: &EditorSnapshot,
21241        window: &mut Window,
21242    ) -> Option<gpui::Point<Pixels>> {
21243        let source_point = source.to_display_point(editor_snapshot);
21244        self.display_to_pixel_point(source_point, editor_snapshot, window)
21245    }
21246
21247    pub fn display_to_pixel_point(
21248        &self,
21249        source: DisplayPoint,
21250        editor_snapshot: &EditorSnapshot,
21251        window: &mut Window,
21252    ) -> Option<gpui::Point<Pixels>> {
21253        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21254        let text_layout_details = self.text_layout_details(window);
21255        let scroll_top = text_layout_details
21256            .scroll_anchor
21257            .scroll_position(editor_snapshot)
21258            .y;
21259
21260        if source.row().as_f32() < scroll_top.floor() {
21261            return None;
21262        }
21263        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21264        let source_y = line_height * (source.row().as_f32() - scroll_top);
21265        Some(gpui::Point::new(source_x, source_y))
21266    }
21267
21268    pub fn has_visible_completions_menu(&self) -> bool {
21269        !self.edit_prediction_preview_is_active()
21270            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21271                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21272            })
21273    }
21274
21275    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21276        if self.mode.is_minimap() {
21277            return;
21278        }
21279        self.addons
21280            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21281    }
21282
21283    pub fn unregister_addon<T: Addon>(&mut self) {
21284        self.addons.remove(&std::any::TypeId::of::<T>());
21285    }
21286
21287    pub fn addon<T: Addon>(&self) -> Option<&T> {
21288        let type_id = std::any::TypeId::of::<T>();
21289        self.addons
21290            .get(&type_id)
21291            .and_then(|item| item.to_any().downcast_ref::<T>())
21292    }
21293
21294    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21295        let type_id = std::any::TypeId::of::<T>();
21296        self.addons
21297            .get_mut(&type_id)
21298            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21299    }
21300
21301    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21302        let text_layout_details = self.text_layout_details(window);
21303        let style = &text_layout_details.editor_style;
21304        let font_id = window.text_system().resolve_font(&style.text.font());
21305        let font_size = style.text.font_size.to_pixels(window.rem_size());
21306        let line_height = style.text.line_height_in_pixels(window.rem_size());
21307        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21308        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21309
21310        CharacterDimensions {
21311            em_width,
21312            em_advance,
21313            line_height,
21314        }
21315    }
21316
21317    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21318        self.load_diff_task.clone()
21319    }
21320
21321    fn read_metadata_from_db(
21322        &mut self,
21323        item_id: u64,
21324        workspace_id: WorkspaceId,
21325        window: &mut Window,
21326        cx: &mut Context<Editor>,
21327    ) {
21328        if self.is_singleton(cx)
21329            && !self.mode.is_minimap()
21330            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21331        {
21332            let buffer_snapshot = OnceCell::new();
21333
21334            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21335                && !folds.is_empty()
21336            {
21337                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21338                self.fold_ranges(
21339                    folds
21340                        .into_iter()
21341                        .map(|(start, end)| {
21342                            snapshot.clip_offset(start, Bias::Left)
21343                                ..snapshot.clip_offset(end, Bias::Right)
21344                        })
21345                        .collect(),
21346                    false,
21347                    window,
21348                    cx,
21349                );
21350            }
21351
21352            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21353                && !selections.is_empty()
21354            {
21355                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21356                // skip adding the initial selection to selection history
21357                self.selection_history.mode = SelectionHistoryMode::Skipping;
21358                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21359                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21360                        snapshot.clip_offset(start, Bias::Left)
21361                            ..snapshot.clip_offset(end, Bias::Right)
21362                    }));
21363                });
21364                self.selection_history.mode = SelectionHistoryMode::Normal;
21365            };
21366        }
21367
21368        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21369    }
21370
21371    fn update_lsp_data(
21372        &mut self,
21373        ignore_cache: bool,
21374        for_buffer: Option<BufferId>,
21375        window: &mut Window,
21376        cx: &mut Context<'_, Self>,
21377    ) {
21378        self.pull_diagnostics(for_buffer, window, cx);
21379        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21380    }
21381}
21382
21383fn vim_enabled(cx: &App) -> bool {
21384    cx.global::<SettingsStore>()
21385        .raw_user_settings()
21386        .get("vim_mode")
21387        == Some(&serde_json::Value::Bool(true))
21388}
21389
21390fn process_completion_for_edit(
21391    completion: &Completion,
21392    intent: CompletionIntent,
21393    buffer: &Entity<Buffer>,
21394    cursor_position: &text::Anchor,
21395    cx: &mut Context<Editor>,
21396) -> CompletionEdit {
21397    let buffer = buffer.read(cx);
21398    let buffer_snapshot = buffer.snapshot();
21399    let (snippet, new_text) = if completion.is_snippet() {
21400        // Workaround for typescript language server issues so that methods don't expand within
21401        // strings and functions with type expressions. The previous point is used because the query
21402        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21403        let mut snippet_source = completion.new_text.clone();
21404        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21405        previous_point.column = previous_point.column.saturating_sub(1);
21406        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21407            && scope.prefers_label_for_snippet_in_completion()
21408            && let Some(label) = completion.label()
21409            && matches!(
21410                completion.kind(),
21411                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21412            )
21413        {
21414            snippet_source = label;
21415        }
21416        match Snippet::parse(&snippet_source).log_err() {
21417            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21418            None => (None, completion.new_text.clone()),
21419        }
21420    } else {
21421        (None, completion.new_text.clone())
21422    };
21423
21424    let mut range_to_replace = {
21425        let replace_range = &completion.replace_range;
21426        if let CompletionSource::Lsp {
21427            insert_range: Some(insert_range),
21428            ..
21429        } = &completion.source
21430        {
21431            debug_assert_eq!(
21432                insert_range.start, replace_range.start,
21433                "insert_range and replace_range should start at the same position"
21434            );
21435            debug_assert!(
21436                insert_range
21437                    .start
21438                    .cmp(cursor_position, &buffer_snapshot)
21439                    .is_le(),
21440                "insert_range should start before or at cursor position"
21441            );
21442            debug_assert!(
21443                replace_range
21444                    .start
21445                    .cmp(cursor_position, &buffer_snapshot)
21446                    .is_le(),
21447                "replace_range should start before or at cursor position"
21448            );
21449
21450            let should_replace = match intent {
21451                CompletionIntent::CompleteWithInsert => false,
21452                CompletionIntent::CompleteWithReplace => true,
21453                CompletionIntent::Complete | CompletionIntent::Compose => {
21454                    let insert_mode =
21455                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21456                            .completions
21457                            .lsp_insert_mode;
21458                    match insert_mode {
21459                        LspInsertMode::Insert => false,
21460                        LspInsertMode::Replace => true,
21461                        LspInsertMode::ReplaceSubsequence => {
21462                            let mut text_to_replace = buffer.chars_for_range(
21463                                buffer.anchor_before(replace_range.start)
21464                                    ..buffer.anchor_after(replace_range.end),
21465                            );
21466                            let mut current_needle = text_to_replace.next();
21467                            for haystack_ch in completion.label.text.chars() {
21468                                if let Some(needle_ch) = current_needle
21469                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21470                                {
21471                                    current_needle = text_to_replace.next();
21472                                }
21473                            }
21474                            current_needle.is_none()
21475                        }
21476                        LspInsertMode::ReplaceSuffix => {
21477                            if replace_range
21478                                .end
21479                                .cmp(cursor_position, &buffer_snapshot)
21480                                .is_gt()
21481                            {
21482                                let range_after_cursor = *cursor_position..replace_range.end;
21483                                let text_after_cursor = buffer
21484                                    .text_for_range(
21485                                        buffer.anchor_before(range_after_cursor.start)
21486                                            ..buffer.anchor_after(range_after_cursor.end),
21487                                    )
21488                                    .collect::<String>()
21489                                    .to_ascii_lowercase();
21490                                completion
21491                                    .label
21492                                    .text
21493                                    .to_ascii_lowercase()
21494                                    .ends_with(&text_after_cursor)
21495                            } else {
21496                                true
21497                            }
21498                        }
21499                    }
21500                }
21501            };
21502
21503            if should_replace {
21504                replace_range.clone()
21505            } else {
21506                insert_range.clone()
21507            }
21508        } else {
21509            replace_range.clone()
21510        }
21511    };
21512
21513    if range_to_replace
21514        .end
21515        .cmp(cursor_position, &buffer_snapshot)
21516        .is_lt()
21517    {
21518        range_to_replace.end = *cursor_position;
21519    }
21520
21521    CompletionEdit {
21522        new_text,
21523        replace_range: range_to_replace.to_offset(buffer),
21524        snippet,
21525    }
21526}
21527
21528struct CompletionEdit {
21529    new_text: String,
21530    replace_range: Range<usize>,
21531    snippet: Option<Snippet>,
21532}
21533
21534fn insert_extra_newline_brackets(
21535    buffer: &MultiBufferSnapshot,
21536    range: Range<usize>,
21537    language: &language::LanguageScope,
21538) -> bool {
21539    let leading_whitespace_len = buffer
21540        .reversed_chars_at(range.start)
21541        .take_while(|c| c.is_whitespace() && *c != '\n')
21542        .map(|c| c.len_utf8())
21543        .sum::<usize>();
21544    let trailing_whitespace_len = buffer
21545        .chars_at(range.end)
21546        .take_while(|c| c.is_whitespace() && *c != '\n')
21547        .map(|c| c.len_utf8())
21548        .sum::<usize>();
21549    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21550
21551    language.brackets().any(|(pair, enabled)| {
21552        let pair_start = pair.start.trim_end();
21553        let pair_end = pair.end.trim_start();
21554
21555        enabled
21556            && pair.newline
21557            && buffer.contains_str_at(range.end, pair_end)
21558            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21559    })
21560}
21561
21562fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21563    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21564        [(buffer, range, _)] => (*buffer, range.clone()),
21565        _ => return false,
21566    };
21567    let pair = {
21568        let mut result: Option<BracketMatch> = None;
21569
21570        for pair in buffer
21571            .all_bracket_ranges(range.clone())
21572            .filter(move |pair| {
21573                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21574            })
21575        {
21576            let len = pair.close_range.end - pair.open_range.start;
21577
21578            if let Some(existing) = &result {
21579                let existing_len = existing.close_range.end - existing.open_range.start;
21580                if len > existing_len {
21581                    continue;
21582                }
21583            }
21584
21585            result = Some(pair);
21586        }
21587
21588        result
21589    };
21590    let Some(pair) = pair else {
21591        return false;
21592    };
21593    pair.newline_only
21594        && buffer
21595            .chars_for_range(pair.open_range.end..range.start)
21596            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21597            .all(|c| c.is_whitespace() && c != '\n')
21598}
21599
21600fn update_uncommitted_diff_for_buffer(
21601    editor: Entity<Editor>,
21602    project: &Entity<Project>,
21603    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21604    buffer: Entity<MultiBuffer>,
21605    cx: &mut App,
21606) -> Task<()> {
21607    let mut tasks = Vec::new();
21608    project.update(cx, |project, cx| {
21609        for buffer in buffers {
21610            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21611                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21612            }
21613        }
21614    });
21615    cx.spawn(async move |cx| {
21616        let diffs = future::join_all(tasks).await;
21617        if editor
21618            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21619            .unwrap_or(false)
21620        {
21621            return;
21622        }
21623
21624        buffer
21625            .update(cx, |buffer, cx| {
21626                for diff in diffs.into_iter().flatten() {
21627                    buffer.add_diff(diff, cx);
21628                }
21629            })
21630            .ok();
21631    })
21632}
21633
21634fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21635    let tab_size = tab_size.get() as usize;
21636    let mut width = offset;
21637
21638    for ch in text.chars() {
21639        width += if ch == '\t' {
21640            tab_size - (width % tab_size)
21641        } else {
21642            1
21643        };
21644    }
21645
21646    width - offset
21647}
21648
21649#[cfg(test)]
21650mod tests {
21651    use super::*;
21652
21653    #[test]
21654    fn test_string_size_with_expanded_tabs() {
21655        let nz = |val| NonZeroU32::new(val).unwrap();
21656        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21657        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21658        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21659        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21660        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21661        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21662        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21663        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21664    }
21665}
21666
21667/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21668struct WordBreakingTokenizer<'a> {
21669    input: &'a str,
21670}
21671
21672impl<'a> WordBreakingTokenizer<'a> {
21673    fn new(input: &'a str) -> Self {
21674        Self { input }
21675    }
21676}
21677
21678fn is_char_ideographic(ch: char) -> bool {
21679    use unicode_script::Script::*;
21680    use unicode_script::UnicodeScript;
21681    matches!(ch.script(), Han | Tangut | Yi)
21682}
21683
21684fn is_grapheme_ideographic(text: &str) -> bool {
21685    text.chars().any(is_char_ideographic)
21686}
21687
21688fn is_grapheme_whitespace(text: &str) -> bool {
21689    text.chars().any(|x| x.is_whitespace())
21690}
21691
21692fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21693    text.chars()
21694        .next()
21695        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21696}
21697
21698#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21699enum WordBreakToken<'a> {
21700    Word { token: &'a str, grapheme_len: usize },
21701    InlineWhitespace { token: &'a str, grapheme_len: usize },
21702    Newline,
21703}
21704
21705impl<'a> Iterator for WordBreakingTokenizer<'a> {
21706    /// Yields a span, the count of graphemes in the token, and whether it was
21707    /// whitespace. Note that it also breaks at word boundaries.
21708    type Item = WordBreakToken<'a>;
21709
21710    fn next(&mut self) -> Option<Self::Item> {
21711        use unicode_segmentation::UnicodeSegmentation;
21712        if self.input.is_empty() {
21713            return None;
21714        }
21715
21716        let mut iter = self.input.graphemes(true).peekable();
21717        let mut offset = 0;
21718        let mut grapheme_len = 0;
21719        if let Some(first_grapheme) = iter.next() {
21720            let is_newline = first_grapheme == "\n";
21721            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21722            offset += first_grapheme.len();
21723            grapheme_len += 1;
21724            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21725                if let Some(grapheme) = iter.peek().copied()
21726                    && should_stay_with_preceding_ideograph(grapheme)
21727                {
21728                    offset += grapheme.len();
21729                    grapheme_len += 1;
21730                }
21731            } else {
21732                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21733                let mut next_word_bound = words.peek().copied();
21734                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21735                    next_word_bound = words.next();
21736                }
21737                while let Some(grapheme) = iter.peek().copied() {
21738                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21739                        break;
21740                    };
21741                    if is_grapheme_whitespace(grapheme) != is_whitespace
21742                        || (grapheme == "\n") != is_newline
21743                    {
21744                        break;
21745                    };
21746                    offset += grapheme.len();
21747                    grapheme_len += 1;
21748                    iter.next();
21749                }
21750            }
21751            let token = &self.input[..offset];
21752            self.input = &self.input[offset..];
21753            if token == "\n" {
21754                Some(WordBreakToken::Newline)
21755            } else if is_whitespace {
21756                Some(WordBreakToken::InlineWhitespace {
21757                    token,
21758                    grapheme_len,
21759                })
21760            } else {
21761                Some(WordBreakToken::Word {
21762                    token,
21763                    grapheme_len,
21764                })
21765            }
21766        } else {
21767            None
21768        }
21769    }
21770}
21771
21772#[test]
21773fn test_word_breaking_tokenizer() {
21774    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21775        ("", &[]),
21776        ("  ", &[whitespace("  ", 2)]),
21777        ("Ʒ", &[word("Ʒ", 1)]),
21778        ("Ǽ", &[word("Ǽ", 1)]),
21779        ("", &[word("", 1)]),
21780        ("⋑⋑", &[word("⋑⋑", 2)]),
21781        (
21782            "原理,进而",
21783            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21784        ),
21785        (
21786            "hello world",
21787            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21788        ),
21789        (
21790            "hello, world",
21791            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21792        ),
21793        (
21794            "  hello world",
21795            &[
21796                whitespace("  ", 2),
21797                word("hello", 5),
21798                whitespace(" ", 1),
21799                word("world", 5),
21800            ],
21801        ),
21802        (
21803            "这是什么 \n 钢笔",
21804            &[
21805                word("", 1),
21806                word("", 1),
21807                word("", 1),
21808                word("", 1),
21809                whitespace(" ", 1),
21810                newline(),
21811                whitespace(" ", 1),
21812                word("", 1),
21813                word("", 1),
21814            ],
21815        ),
21816        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21817    ];
21818
21819    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21820        WordBreakToken::Word {
21821            token,
21822            grapheme_len,
21823        }
21824    }
21825
21826    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21827        WordBreakToken::InlineWhitespace {
21828            token,
21829            grapheme_len,
21830        }
21831    }
21832
21833    fn newline() -> WordBreakToken<'static> {
21834        WordBreakToken::Newline
21835    }
21836
21837    for (input, result) in tests {
21838        assert_eq!(
21839            WordBreakingTokenizer::new(input)
21840                .collect::<Vec<_>>()
21841                .as_slice(),
21842            *result,
21843        );
21844    }
21845}
21846
21847fn wrap_with_prefix(
21848    first_line_prefix: String,
21849    subsequent_lines_prefix: String,
21850    unwrapped_text: String,
21851    wrap_column: usize,
21852    tab_size: NonZeroU32,
21853    preserve_existing_whitespace: bool,
21854) -> String {
21855    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21856    let subsequent_lines_prefix_len =
21857        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21858    let mut wrapped_text = String::new();
21859    let mut current_line = first_line_prefix;
21860    let mut is_first_line = true;
21861
21862    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21863    let mut current_line_len = first_line_prefix_len;
21864    let mut in_whitespace = false;
21865    for token in tokenizer {
21866        let have_preceding_whitespace = in_whitespace;
21867        match token {
21868            WordBreakToken::Word {
21869                token,
21870                grapheme_len,
21871            } => {
21872                in_whitespace = false;
21873                let current_prefix_len = if is_first_line {
21874                    first_line_prefix_len
21875                } else {
21876                    subsequent_lines_prefix_len
21877                };
21878                if current_line_len + grapheme_len > wrap_column
21879                    && current_line_len != current_prefix_len
21880                {
21881                    wrapped_text.push_str(current_line.trim_end());
21882                    wrapped_text.push('\n');
21883                    is_first_line = false;
21884                    current_line = subsequent_lines_prefix.clone();
21885                    current_line_len = subsequent_lines_prefix_len;
21886                }
21887                current_line.push_str(token);
21888                current_line_len += grapheme_len;
21889            }
21890            WordBreakToken::InlineWhitespace {
21891                mut token,
21892                mut grapheme_len,
21893            } => {
21894                in_whitespace = true;
21895                if have_preceding_whitespace && !preserve_existing_whitespace {
21896                    continue;
21897                }
21898                if !preserve_existing_whitespace {
21899                    token = " ";
21900                    grapheme_len = 1;
21901                }
21902                let current_prefix_len = if is_first_line {
21903                    first_line_prefix_len
21904                } else {
21905                    subsequent_lines_prefix_len
21906                };
21907                if current_line_len + grapheme_len > wrap_column {
21908                    wrapped_text.push_str(current_line.trim_end());
21909                    wrapped_text.push('\n');
21910                    is_first_line = false;
21911                    current_line = subsequent_lines_prefix.clone();
21912                    current_line_len = subsequent_lines_prefix_len;
21913                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21914                    current_line.push_str(token);
21915                    current_line_len += grapheme_len;
21916                }
21917            }
21918            WordBreakToken::Newline => {
21919                in_whitespace = true;
21920                let current_prefix_len = if is_first_line {
21921                    first_line_prefix_len
21922                } else {
21923                    subsequent_lines_prefix_len
21924                };
21925                if preserve_existing_whitespace {
21926                    wrapped_text.push_str(current_line.trim_end());
21927                    wrapped_text.push('\n');
21928                    is_first_line = false;
21929                    current_line = subsequent_lines_prefix.clone();
21930                    current_line_len = subsequent_lines_prefix_len;
21931                } else if have_preceding_whitespace {
21932                    continue;
21933                } else if current_line_len + 1 > wrap_column
21934                    && current_line_len != current_prefix_len
21935                {
21936                    wrapped_text.push_str(current_line.trim_end());
21937                    wrapped_text.push('\n');
21938                    is_first_line = false;
21939                    current_line = subsequent_lines_prefix.clone();
21940                    current_line_len = subsequent_lines_prefix_len;
21941                } else if current_line_len != current_prefix_len {
21942                    current_line.push(' ');
21943                    current_line_len += 1;
21944                }
21945            }
21946        }
21947    }
21948
21949    if !current_line.is_empty() {
21950        wrapped_text.push_str(&current_line);
21951    }
21952    wrapped_text
21953}
21954
21955#[test]
21956fn test_wrap_with_prefix() {
21957    assert_eq!(
21958        wrap_with_prefix(
21959            "# ".to_string(),
21960            "# ".to_string(),
21961            "abcdefg".to_string(),
21962            4,
21963            NonZeroU32::new(4).unwrap(),
21964            false,
21965        ),
21966        "# abcdefg"
21967    );
21968    assert_eq!(
21969        wrap_with_prefix(
21970            "".to_string(),
21971            "".to_string(),
21972            "\thello world".to_string(),
21973            8,
21974            NonZeroU32::new(4).unwrap(),
21975            false,
21976        ),
21977        "hello\nworld"
21978    );
21979    assert_eq!(
21980        wrap_with_prefix(
21981            "// ".to_string(),
21982            "// ".to_string(),
21983            "xx \nyy zz aa bb cc".to_string(),
21984            12,
21985            NonZeroU32::new(4).unwrap(),
21986            false,
21987        ),
21988        "// xx yy zz\n// aa bb cc"
21989    );
21990    assert_eq!(
21991        wrap_with_prefix(
21992            String::new(),
21993            String::new(),
21994            "这是什么 \n 钢笔".to_string(),
21995            3,
21996            NonZeroU32::new(4).unwrap(),
21997            false,
21998        ),
21999        "这是什\n么 钢\n"
22000    );
22001}
22002
22003pub trait CollaborationHub {
22004    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22005    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22006    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22007}
22008
22009impl CollaborationHub for Entity<Project> {
22010    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22011        self.read(cx).collaborators()
22012    }
22013
22014    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22015        self.read(cx).user_store().read(cx).participant_indices()
22016    }
22017
22018    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22019        let this = self.read(cx);
22020        let user_ids = this.collaborators().values().map(|c| c.user_id);
22021        this.user_store().read(cx).participant_names(user_ids, cx)
22022    }
22023}
22024
22025pub trait SemanticsProvider {
22026    fn hover(
22027        &self,
22028        buffer: &Entity<Buffer>,
22029        position: text::Anchor,
22030        cx: &mut App,
22031    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22032
22033    fn inline_values(
22034        &self,
22035        buffer_handle: Entity<Buffer>,
22036        range: Range<text::Anchor>,
22037        cx: &mut App,
22038    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22039
22040    fn inlay_hints(
22041        &self,
22042        buffer_handle: Entity<Buffer>,
22043        range: Range<text::Anchor>,
22044        cx: &mut App,
22045    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22046
22047    fn resolve_inlay_hint(
22048        &self,
22049        hint: InlayHint,
22050        buffer_handle: Entity<Buffer>,
22051        server_id: LanguageServerId,
22052        cx: &mut App,
22053    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22054
22055    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22056
22057    fn document_highlights(
22058        &self,
22059        buffer: &Entity<Buffer>,
22060        position: text::Anchor,
22061        cx: &mut App,
22062    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22063
22064    fn definitions(
22065        &self,
22066        buffer: &Entity<Buffer>,
22067        position: text::Anchor,
22068        kind: GotoDefinitionKind,
22069        cx: &mut App,
22070    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22071
22072    fn range_for_rename(
22073        &self,
22074        buffer: &Entity<Buffer>,
22075        position: text::Anchor,
22076        cx: &mut App,
22077    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22078
22079    fn perform_rename(
22080        &self,
22081        buffer: &Entity<Buffer>,
22082        position: text::Anchor,
22083        new_name: String,
22084        cx: &mut App,
22085    ) -> Option<Task<Result<ProjectTransaction>>>;
22086}
22087
22088pub trait CompletionProvider {
22089    fn completions(
22090        &self,
22091        excerpt_id: ExcerptId,
22092        buffer: &Entity<Buffer>,
22093        buffer_position: text::Anchor,
22094        trigger: CompletionContext,
22095        window: &mut Window,
22096        cx: &mut Context<Editor>,
22097    ) -> Task<Result<Vec<CompletionResponse>>>;
22098
22099    fn resolve_completions(
22100        &self,
22101        _buffer: Entity<Buffer>,
22102        _completion_indices: Vec<usize>,
22103        _completions: Rc<RefCell<Box<[Completion]>>>,
22104        _cx: &mut Context<Editor>,
22105    ) -> Task<Result<bool>> {
22106        Task::ready(Ok(false))
22107    }
22108
22109    fn apply_additional_edits_for_completion(
22110        &self,
22111        _buffer: Entity<Buffer>,
22112        _completions: Rc<RefCell<Box<[Completion]>>>,
22113        _completion_index: usize,
22114        _push_to_history: bool,
22115        _cx: &mut Context<Editor>,
22116    ) -> Task<Result<Option<language::Transaction>>> {
22117        Task::ready(Ok(None))
22118    }
22119
22120    fn is_completion_trigger(
22121        &self,
22122        buffer: &Entity<Buffer>,
22123        position: language::Anchor,
22124        text: &str,
22125        trigger_in_words: bool,
22126        menu_is_open: bool,
22127        cx: &mut Context<Editor>,
22128    ) -> bool;
22129
22130    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22131
22132    fn sort_completions(&self) -> bool {
22133        true
22134    }
22135
22136    fn filter_completions(&self) -> bool {
22137        true
22138    }
22139}
22140
22141pub trait CodeActionProvider {
22142    fn id(&self) -> Arc<str>;
22143
22144    fn code_actions(
22145        &self,
22146        buffer: &Entity<Buffer>,
22147        range: Range<text::Anchor>,
22148        window: &mut Window,
22149        cx: &mut App,
22150    ) -> Task<Result<Vec<CodeAction>>>;
22151
22152    fn apply_code_action(
22153        &self,
22154        buffer_handle: Entity<Buffer>,
22155        action: CodeAction,
22156        excerpt_id: ExcerptId,
22157        push_to_history: bool,
22158        window: &mut Window,
22159        cx: &mut App,
22160    ) -> Task<Result<ProjectTransaction>>;
22161}
22162
22163impl CodeActionProvider for Entity<Project> {
22164    fn id(&self) -> Arc<str> {
22165        "project".into()
22166    }
22167
22168    fn code_actions(
22169        &self,
22170        buffer: &Entity<Buffer>,
22171        range: Range<text::Anchor>,
22172        _window: &mut Window,
22173        cx: &mut App,
22174    ) -> Task<Result<Vec<CodeAction>>> {
22175        self.update(cx, |project, cx| {
22176            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22177            let code_actions = project.code_actions(buffer, range, None, cx);
22178            cx.background_spawn(async move {
22179                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22180                Ok(code_lens_actions
22181                    .context("code lens fetch")?
22182                    .into_iter()
22183                    .flatten()
22184                    .chain(
22185                        code_actions
22186                            .context("code action fetch")?
22187                            .into_iter()
22188                            .flatten(),
22189                    )
22190                    .collect())
22191            })
22192        })
22193    }
22194
22195    fn apply_code_action(
22196        &self,
22197        buffer_handle: Entity<Buffer>,
22198        action: CodeAction,
22199        _excerpt_id: ExcerptId,
22200        push_to_history: bool,
22201        _window: &mut Window,
22202        cx: &mut App,
22203    ) -> Task<Result<ProjectTransaction>> {
22204        self.update(cx, |project, cx| {
22205            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22206        })
22207    }
22208}
22209
22210fn snippet_completions(
22211    project: &Project,
22212    buffer: &Entity<Buffer>,
22213    buffer_position: text::Anchor,
22214    cx: &mut App,
22215) -> Task<Result<CompletionResponse>> {
22216    let languages = buffer.read(cx).languages_at(buffer_position);
22217    let snippet_store = project.snippets().read(cx);
22218
22219    let scopes: Vec<_> = languages
22220        .iter()
22221        .filter_map(|language| {
22222            let language_name = language.lsp_id();
22223            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22224
22225            if snippets.is_empty() {
22226                None
22227            } else {
22228                Some((language.default_scope(), snippets))
22229            }
22230        })
22231        .collect();
22232
22233    if scopes.is_empty() {
22234        return Task::ready(Ok(CompletionResponse {
22235            completions: vec![],
22236            display_options: CompletionDisplayOptions::default(),
22237            is_incomplete: false,
22238        }));
22239    }
22240
22241    let snapshot = buffer.read(cx).text_snapshot();
22242    let chars: String = snapshot
22243        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22244        .collect();
22245    let executor = cx.background_executor().clone();
22246
22247    cx.background_spawn(async move {
22248        let mut is_incomplete = false;
22249        let mut completions: Vec<Completion> = Vec::new();
22250        for (scope, snippets) in scopes.into_iter() {
22251            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22252            let mut last_word = chars
22253                .chars()
22254                .take_while(|c| classifier.is_word(*c))
22255                .collect::<String>();
22256            last_word = last_word.chars().rev().collect();
22257
22258            if last_word.is_empty() {
22259                return Ok(CompletionResponse {
22260                    completions: vec![],
22261                    display_options: CompletionDisplayOptions::default(),
22262                    is_incomplete: true,
22263                });
22264            }
22265
22266            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22267            let to_lsp = |point: &text::Anchor| {
22268                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22269                point_to_lsp(end)
22270            };
22271            let lsp_end = to_lsp(&buffer_position);
22272
22273            let candidates = snippets
22274                .iter()
22275                .enumerate()
22276                .flat_map(|(ix, snippet)| {
22277                    snippet
22278                        .prefix
22279                        .iter()
22280                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22281                })
22282                .collect::<Vec<StringMatchCandidate>>();
22283
22284            const MAX_RESULTS: usize = 100;
22285            let mut matches = fuzzy::match_strings(
22286                &candidates,
22287                &last_word,
22288                last_word.chars().any(|c| c.is_uppercase()),
22289                true,
22290                MAX_RESULTS,
22291                &Default::default(),
22292                executor.clone(),
22293            )
22294            .await;
22295
22296            if matches.len() >= MAX_RESULTS {
22297                is_incomplete = true;
22298            }
22299
22300            // Remove all candidates where the query's start does not match the start of any word in the candidate
22301            if let Some(query_start) = last_word.chars().next() {
22302                matches.retain(|string_match| {
22303                    split_words(&string_match.string).any(|word| {
22304                        // Check that the first codepoint of the word as lowercase matches the first
22305                        // codepoint of the query as lowercase
22306                        word.chars()
22307                            .flat_map(|codepoint| codepoint.to_lowercase())
22308                            .zip(query_start.to_lowercase())
22309                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22310                    })
22311                });
22312            }
22313
22314            let matched_strings = matches
22315                .into_iter()
22316                .map(|m| m.string)
22317                .collect::<HashSet<_>>();
22318
22319            completions.extend(snippets.iter().filter_map(|snippet| {
22320                let matching_prefix = snippet
22321                    .prefix
22322                    .iter()
22323                    .find(|prefix| matched_strings.contains(*prefix))?;
22324                let start = as_offset - last_word.len();
22325                let start = snapshot.anchor_before(start);
22326                let range = start..buffer_position;
22327                let lsp_start = to_lsp(&start);
22328                let lsp_range = lsp::Range {
22329                    start: lsp_start,
22330                    end: lsp_end,
22331                };
22332                Some(Completion {
22333                    replace_range: range,
22334                    new_text: snippet.body.clone(),
22335                    source: CompletionSource::Lsp {
22336                        insert_range: None,
22337                        server_id: LanguageServerId(usize::MAX),
22338                        resolved: true,
22339                        lsp_completion: Box::new(lsp::CompletionItem {
22340                            label: snippet.prefix.first().unwrap().clone(),
22341                            kind: Some(CompletionItemKind::SNIPPET),
22342                            label_details: snippet.description.as_ref().map(|description| {
22343                                lsp::CompletionItemLabelDetails {
22344                                    detail: Some(description.clone()),
22345                                    description: None,
22346                                }
22347                            }),
22348                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22349                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22350                                lsp::InsertReplaceEdit {
22351                                    new_text: snippet.body.clone(),
22352                                    insert: lsp_range,
22353                                    replace: lsp_range,
22354                                },
22355                            )),
22356                            filter_text: Some(snippet.body.clone()),
22357                            sort_text: Some(char::MAX.to_string()),
22358                            ..lsp::CompletionItem::default()
22359                        }),
22360                        lsp_defaults: None,
22361                    },
22362                    label: CodeLabel {
22363                        text: matching_prefix.clone(),
22364                        runs: Vec::new(),
22365                        filter_range: 0..matching_prefix.len(),
22366                    },
22367                    icon_path: None,
22368                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22369                        single_line: snippet.name.clone().into(),
22370                        plain_text: snippet
22371                            .description
22372                            .clone()
22373                            .map(|description| description.into()),
22374                    }),
22375                    insert_text_mode: None,
22376                    confirm: None,
22377                })
22378            }))
22379        }
22380
22381        Ok(CompletionResponse {
22382            completions,
22383            display_options: CompletionDisplayOptions::default(),
22384            is_incomplete,
22385        })
22386    })
22387}
22388
22389impl CompletionProvider for Entity<Project> {
22390    fn completions(
22391        &self,
22392        _excerpt_id: ExcerptId,
22393        buffer: &Entity<Buffer>,
22394        buffer_position: text::Anchor,
22395        options: CompletionContext,
22396        _window: &mut Window,
22397        cx: &mut Context<Editor>,
22398    ) -> Task<Result<Vec<CompletionResponse>>> {
22399        self.update(cx, |project, cx| {
22400            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22401            let project_completions = project.completions(buffer, buffer_position, options, cx);
22402            cx.background_spawn(async move {
22403                let mut responses = project_completions.await?;
22404                let snippets = snippets.await?;
22405                if !snippets.completions.is_empty() {
22406                    responses.push(snippets);
22407                }
22408                Ok(responses)
22409            })
22410        })
22411    }
22412
22413    fn resolve_completions(
22414        &self,
22415        buffer: Entity<Buffer>,
22416        completion_indices: Vec<usize>,
22417        completions: Rc<RefCell<Box<[Completion]>>>,
22418        cx: &mut Context<Editor>,
22419    ) -> Task<Result<bool>> {
22420        self.update(cx, |project, cx| {
22421            project.lsp_store().update(cx, |lsp_store, cx| {
22422                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22423            })
22424        })
22425    }
22426
22427    fn apply_additional_edits_for_completion(
22428        &self,
22429        buffer: Entity<Buffer>,
22430        completions: Rc<RefCell<Box<[Completion]>>>,
22431        completion_index: usize,
22432        push_to_history: bool,
22433        cx: &mut Context<Editor>,
22434    ) -> Task<Result<Option<language::Transaction>>> {
22435        self.update(cx, |project, cx| {
22436            project.lsp_store().update(cx, |lsp_store, cx| {
22437                lsp_store.apply_additional_edits_for_completion(
22438                    buffer,
22439                    completions,
22440                    completion_index,
22441                    push_to_history,
22442                    cx,
22443                )
22444            })
22445        })
22446    }
22447
22448    fn is_completion_trigger(
22449        &self,
22450        buffer: &Entity<Buffer>,
22451        position: language::Anchor,
22452        text: &str,
22453        trigger_in_words: bool,
22454        menu_is_open: bool,
22455        cx: &mut Context<Editor>,
22456    ) -> bool {
22457        let mut chars = text.chars();
22458        let char = if let Some(char) = chars.next() {
22459            char
22460        } else {
22461            return false;
22462        };
22463        if chars.next().is_some() {
22464            return false;
22465        }
22466
22467        let buffer = buffer.read(cx);
22468        let snapshot = buffer.snapshot();
22469        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22470            return false;
22471        }
22472        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22473        if trigger_in_words && classifier.is_word(char) {
22474            return true;
22475        }
22476
22477        buffer.completion_triggers().contains(text)
22478    }
22479}
22480
22481impl SemanticsProvider for Entity<Project> {
22482    fn hover(
22483        &self,
22484        buffer: &Entity<Buffer>,
22485        position: text::Anchor,
22486        cx: &mut App,
22487    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22488        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22489    }
22490
22491    fn document_highlights(
22492        &self,
22493        buffer: &Entity<Buffer>,
22494        position: text::Anchor,
22495        cx: &mut App,
22496    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22497        Some(self.update(cx, |project, cx| {
22498            project.document_highlights(buffer, position, cx)
22499        }))
22500    }
22501
22502    fn definitions(
22503        &self,
22504        buffer: &Entity<Buffer>,
22505        position: text::Anchor,
22506        kind: GotoDefinitionKind,
22507        cx: &mut App,
22508    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22509        Some(self.update(cx, |project, cx| match kind {
22510            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22511            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22512            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22513            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22514        }))
22515    }
22516
22517    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22518        self.update(cx, |project, cx| {
22519            if project
22520                .active_debug_session(cx)
22521                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22522            {
22523                return true;
22524            }
22525
22526            buffer.update(cx, |buffer, cx| {
22527                project.any_language_server_supports_inlay_hints(buffer, cx)
22528            })
22529        })
22530    }
22531
22532    fn inline_values(
22533        &self,
22534        buffer_handle: Entity<Buffer>,
22535        range: Range<text::Anchor>,
22536        cx: &mut App,
22537    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22538        self.update(cx, |project, cx| {
22539            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22540
22541            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22542        })
22543    }
22544
22545    fn inlay_hints(
22546        &self,
22547        buffer_handle: Entity<Buffer>,
22548        range: Range<text::Anchor>,
22549        cx: &mut App,
22550    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22551        Some(self.update(cx, |project, cx| {
22552            project.inlay_hints(buffer_handle, range, cx)
22553        }))
22554    }
22555
22556    fn resolve_inlay_hint(
22557        &self,
22558        hint: InlayHint,
22559        buffer_handle: Entity<Buffer>,
22560        server_id: LanguageServerId,
22561        cx: &mut App,
22562    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22563        Some(self.update(cx, |project, cx| {
22564            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22565        }))
22566    }
22567
22568    fn range_for_rename(
22569        &self,
22570        buffer: &Entity<Buffer>,
22571        position: text::Anchor,
22572        cx: &mut App,
22573    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22574        Some(self.update(cx, |project, cx| {
22575            let buffer = buffer.clone();
22576            let task = project.prepare_rename(buffer.clone(), position, cx);
22577            cx.spawn(async move |_, cx| {
22578                Ok(match task.await? {
22579                    PrepareRenameResponse::Success(range) => Some(range),
22580                    PrepareRenameResponse::InvalidPosition => None,
22581                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22582                        // Fallback on using TreeSitter info to determine identifier range
22583                        buffer.read_with(cx, |buffer, _| {
22584                            let snapshot = buffer.snapshot();
22585                            let (range, kind) = snapshot.surrounding_word(position, false);
22586                            if kind != Some(CharKind::Word) {
22587                                return None;
22588                            }
22589                            Some(
22590                                snapshot.anchor_before(range.start)
22591                                    ..snapshot.anchor_after(range.end),
22592                            )
22593                        })?
22594                    }
22595                })
22596            })
22597        }))
22598    }
22599
22600    fn perform_rename(
22601        &self,
22602        buffer: &Entity<Buffer>,
22603        position: text::Anchor,
22604        new_name: String,
22605        cx: &mut App,
22606    ) -> Option<Task<Result<ProjectTransaction>>> {
22607        Some(self.update(cx, |project, cx| {
22608            project.perform_rename(buffer.clone(), position, new_name, cx)
22609        }))
22610    }
22611}
22612
22613fn inlay_hint_settings(
22614    location: Anchor,
22615    snapshot: &MultiBufferSnapshot,
22616    cx: &mut Context<Editor>,
22617) -> InlayHintSettings {
22618    let file = snapshot.file_at(location);
22619    let language = snapshot.language_at(location).map(|l| l.name());
22620    language_settings(language, file, cx).inlay_hints
22621}
22622
22623fn consume_contiguous_rows(
22624    contiguous_row_selections: &mut Vec<Selection<Point>>,
22625    selection: &Selection<Point>,
22626    display_map: &DisplaySnapshot,
22627    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22628) -> (MultiBufferRow, MultiBufferRow) {
22629    contiguous_row_selections.push(selection.clone());
22630    let start_row = starting_row(selection, display_map);
22631    let mut end_row = ending_row(selection, display_map);
22632
22633    while let Some(next_selection) = selections.peek() {
22634        if next_selection.start.row <= end_row.0 {
22635            end_row = ending_row(next_selection, display_map);
22636            contiguous_row_selections.push(selections.next().unwrap().clone());
22637        } else {
22638            break;
22639        }
22640    }
22641    (start_row, end_row)
22642}
22643
22644fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22645    if selection.start.column > 0 {
22646        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22647    } else {
22648        MultiBufferRow(selection.start.row)
22649    }
22650}
22651
22652fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22653    if next_selection.end.column > 0 || next_selection.is_empty() {
22654        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22655    } else {
22656        MultiBufferRow(next_selection.end.row)
22657    }
22658}
22659
22660impl EditorSnapshot {
22661    pub fn remote_selections_in_range<'a>(
22662        &'a self,
22663        range: &'a Range<Anchor>,
22664        collaboration_hub: &dyn CollaborationHub,
22665        cx: &'a App,
22666    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22667        let participant_names = collaboration_hub.user_names(cx);
22668        let participant_indices = collaboration_hub.user_participant_indices(cx);
22669        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22670        let collaborators_by_replica_id = collaborators_by_peer_id
22671            .values()
22672            .map(|collaborator| (collaborator.replica_id, collaborator))
22673            .collect::<HashMap<_, _>>();
22674        self.buffer_snapshot
22675            .selections_in_range(range, false)
22676            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22677                if replica_id == AGENT_REPLICA_ID {
22678                    Some(RemoteSelection {
22679                        replica_id,
22680                        selection,
22681                        cursor_shape,
22682                        line_mode,
22683                        collaborator_id: CollaboratorId::Agent,
22684                        user_name: Some("Agent".into()),
22685                        color: cx.theme().players().agent(),
22686                    })
22687                } else {
22688                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22689                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22690                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22691                    Some(RemoteSelection {
22692                        replica_id,
22693                        selection,
22694                        cursor_shape,
22695                        line_mode,
22696                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22697                        user_name,
22698                        color: if let Some(index) = participant_index {
22699                            cx.theme().players().color_for_participant(index.0)
22700                        } else {
22701                            cx.theme().players().absent()
22702                        },
22703                    })
22704                }
22705            })
22706    }
22707
22708    pub fn hunks_for_ranges(
22709        &self,
22710        ranges: impl IntoIterator<Item = Range<Point>>,
22711    ) -> Vec<MultiBufferDiffHunk> {
22712        let mut hunks = Vec::new();
22713        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22714            HashMap::default();
22715        for query_range in ranges {
22716            let query_rows =
22717                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22718            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22719                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22720            ) {
22721                // Include deleted hunks that are adjacent to the query range, because
22722                // otherwise they would be missed.
22723                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22724                if hunk.status().is_deleted() {
22725                    intersects_range |= hunk.row_range.start == query_rows.end;
22726                    intersects_range |= hunk.row_range.end == query_rows.start;
22727                }
22728                if intersects_range {
22729                    if !processed_buffer_rows
22730                        .entry(hunk.buffer_id)
22731                        .or_default()
22732                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22733                    {
22734                        continue;
22735                    }
22736                    hunks.push(hunk);
22737                }
22738            }
22739        }
22740
22741        hunks
22742    }
22743
22744    fn display_diff_hunks_for_rows<'a>(
22745        &'a self,
22746        display_rows: Range<DisplayRow>,
22747        folded_buffers: &'a HashSet<BufferId>,
22748    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22749        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22750        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22751
22752        self.buffer_snapshot
22753            .diff_hunks_in_range(buffer_start..buffer_end)
22754            .filter_map(|hunk| {
22755                if folded_buffers.contains(&hunk.buffer_id) {
22756                    return None;
22757                }
22758
22759                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22760                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22761
22762                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22763                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22764
22765                let display_hunk = if hunk_display_start.column() != 0 {
22766                    DisplayDiffHunk::Folded {
22767                        display_row: hunk_display_start.row(),
22768                    }
22769                } else {
22770                    let mut end_row = hunk_display_end.row();
22771                    if hunk_display_end.column() > 0 {
22772                        end_row.0 += 1;
22773                    }
22774                    let is_created_file = hunk.is_created_file();
22775                    DisplayDiffHunk::Unfolded {
22776                        status: hunk.status(),
22777                        diff_base_byte_range: hunk.diff_base_byte_range,
22778                        display_row_range: hunk_display_start.row()..end_row,
22779                        multi_buffer_range: Anchor::range_in_buffer(
22780                            hunk.excerpt_id,
22781                            hunk.buffer_id,
22782                            hunk.buffer_range,
22783                        ),
22784                        is_created_file,
22785                    }
22786                };
22787
22788                Some(display_hunk)
22789            })
22790    }
22791
22792    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22793        self.display_snapshot.buffer_snapshot.language_at(position)
22794    }
22795
22796    pub fn is_focused(&self) -> bool {
22797        self.is_focused
22798    }
22799
22800    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22801        self.placeholder_text.as_ref()
22802    }
22803
22804    pub fn scroll_position(&self) -> gpui::Point<f32> {
22805        self.scroll_anchor.scroll_position(&self.display_snapshot)
22806    }
22807
22808    fn gutter_dimensions(
22809        &self,
22810        font_id: FontId,
22811        font_size: Pixels,
22812        max_line_number_width: Pixels,
22813        cx: &App,
22814    ) -> Option<GutterDimensions> {
22815        if !self.show_gutter {
22816            return None;
22817        }
22818
22819        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22820        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22821
22822        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22823            matches!(
22824                ProjectSettings::get_global(cx).git.git_gutter,
22825                Some(GitGutterSetting::TrackedFiles)
22826            )
22827        });
22828        let gutter_settings = EditorSettings::get_global(cx).gutter;
22829        let show_line_numbers = self
22830            .show_line_numbers
22831            .unwrap_or(gutter_settings.line_numbers);
22832        let line_gutter_width = if show_line_numbers {
22833            // Avoid flicker-like gutter resizes when the line number gains another digit by
22834            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22835            let min_width_for_number_on_gutter =
22836                ch_advance * gutter_settings.min_line_number_digits as f32;
22837            max_line_number_width.max(min_width_for_number_on_gutter)
22838        } else {
22839            0.0.into()
22840        };
22841
22842        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22843        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22844
22845        let git_blame_entries_width =
22846            self.git_blame_gutter_max_author_length
22847                .map(|max_author_length| {
22848                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22849                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22850
22851                    /// The number of characters to dedicate to gaps and margins.
22852                    const SPACING_WIDTH: usize = 4;
22853
22854                    let max_char_count = max_author_length.min(renderer.max_author_length())
22855                        + ::git::SHORT_SHA_LENGTH
22856                        + MAX_RELATIVE_TIMESTAMP.len()
22857                        + SPACING_WIDTH;
22858
22859                    ch_advance * max_char_count
22860                });
22861
22862        let is_singleton = self.buffer_snapshot.is_singleton();
22863
22864        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22865        left_padding += if !is_singleton {
22866            ch_width * 4.0
22867        } else if show_runnables || show_breakpoints {
22868            ch_width * 3.0
22869        } else if show_git_gutter && show_line_numbers {
22870            ch_width * 2.0
22871        } else if show_git_gutter || show_line_numbers {
22872            ch_width
22873        } else {
22874            px(0.)
22875        };
22876
22877        let shows_folds = is_singleton && gutter_settings.folds;
22878
22879        let right_padding = if shows_folds && show_line_numbers {
22880            ch_width * 4.0
22881        } else if shows_folds || (!is_singleton && show_line_numbers) {
22882            ch_width * 3.0
22883        } else if show_line_numbers {
22884            ch_width
22885        } else {
22886            px(0.)
22887        };
22888
22889        Some(GutterDimensions {
22890            left_padding,
22891            right_padding,
22892            width: line_gutter_width + left_padding + right_padding,
22893            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22894            git_blame_entries_width,
22895        })
22896    }
22897
22898    pub fn render_crease_toggle(
22899        &self,
22900        buffer_row: MultiBufferRow,
22901        row_contains_cursor: bool,
22902        editor: Entity<Editor>,
22903        window: &mut Window,
22904        cx: &mut App,
22905    ) -> Option<AnyElement> {
22906        let folded = self.is_line_folded(buffer_row);
22907        let mut is_foldable = false;
22908
22909        if let Some(crease) = self
22910            .crease_snapshot
22911            .query_row(buffer_row, &self.buffer_snapshot)
22912        {
22913            is_foldable = true;
22914            match crease {
22915                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22916                    if let Some(render_toggle) = render_toggle {
22917                        let toggle_callback =
22918                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22919                                if folded {
22920                                    editor.update(cx, |editor, cx| {
22921                                        editor.fold_at(buffer_row, window, cx)
22922                                    });
22923                                } else {
22924                                    editor.update(cx, |editor, cx| {
22925                                        editor.unfold_at(buffer_row, window, cx)
22926                                    });
22927                                }
22928                            });
22929                        return Some((render_toggle)(
22930                            buffer_row,
22931                            folded,
22932                            toggle_callback,
22933                            window,
22934                            cx,
22935                        ));
22936                    }
22937                }
22938            }
22939        }
22940
22941        is_foldable |= self.starts_indent(buffer_row);
22942
22943        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22944            Some(
22945                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22946                    .toggle_state(folded)
22947                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22948                        if folded {
22949                            this.unfold_at(buffer_row, window, cx);
22950                        } else {
22951                            this.fold_at(buffer_row, window, cx);
22952                        }
22953                    }))
22954                    .into_any_element(),
22955            )
22956        } else {
22957            None
22958        }
22959    }
22960
22961    pub fn render_crease_trailer(
22962        &self,
22963        buffer_row: MultiBufferRow,
22964        window: &mut Window,
22965        cx: &mut App,
22966    ) -> Option<AnyElement> {
22967        let folded = self.is_line_folded(buffer_row);
22968        if let Crease::Inline { render_trailer, .. } = self
22969            .crease_snapshot
22970            .query_row(buffer_row, &self.buffer_snapshot)?
22971        {
22972            let render_trailer = render_trailer.as_ref()?;
22973            Some(render_trailer(buffer_row, folded, window, cx))
22974        } else {
22975            None
22976        }
22977    }
22978}
22979
22980impl Deref for EditorSnapshot {
22981    type Target = DisplaySnapshot;
22982
22983    fn deref(&self) -> &Self::Target {
22984        &self.display_snapshot
22985    }
22986}
22987
22988#[derive(Clone, Debug, PartialEq, Eq)]
22989pub enum EditorEvent {
22990    InputIgnored {
22991        text: Arc<str>,
22992    },
22993    InputHandled {
22994        utf16_range_to_replace: Option<Range<isize>>,
22995        text: Arc<str>,
22996    },
22997    ExcerptsAdded {
22998        buffer: Entity<Buffer>,
22999        predecessor: ExcerptId,
23000        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23001    },
23002    ExcerptsRemoved {
23003        ids: Vec<ExcerptId>,
23004        removed_buffer_ids: Vec<BufferId>,
23005    },
23006    BufferFoldToggled {
23007        ids: Vec<ExcerptId>,
23008        folded: bool,
23009    },
23010    ExcerptsEdited {
23011        ids: Vec<ExcerptId>,
23012    },
23013    ExcerptsExpanded {
23014        ids: Vec<ExcerptId>,
23015    },
23016    BufferEdited,
23017    Edited {
23018        transaction_id: clock::Lamport,
23019    },
23020    Reparsed(BufferId),
23021    Focused,
23022    FocusedIn,
23023    Blurred,
23024    DirtyChanged,
23025    Saved,
23026    TitleChanged,
23027    DiffBaseChanged,
23028    SelectionsChanged {
23029        local: bool,
23030    },
23031    ScrollPositionChanged {
23032        local: bool,
23033        autoscroll: bool,
23034    },
23035    Closed,
23036    TransactionUndone {
23037        transaction_id: clock::Lamport,
23038    },
23039    TransactionBegun {
23040        transaction_id: clock::Lamport,
23041    },
23042    Reloaded,
23043    CursorShapeChanged,
23044    BreadcrumbsChanged,
23045    PushedToNavHistory {
23046        anchor: Anchor,
23047        is_deactivate: bool,
23048    },
23049}
23050
23051impl EventEmitter<EditorEvent> for Editor {}
23052
23053impl Focusable for Editor {
23054    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23055        self.focus_handle.clone()
23056    }
23057}
23058
23059impl Render for Editor {
23060    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23061        let settings = ThemeSettings::get_global(cx);
23062
23063        let mut text_style = match self.mode {
23064            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23065                color: cx.theme().colors().editor_foreground,
23066                font_family: settings.ui_font.family.clone(),
23067                font_features: settings.ui_font.features.clone(),
23068                font_fallbacks: settings.ui_font.fallbacks.clone(),
23069                font_size: rems(0.875).into(),
23070                font_weight: settings.ui_font.weight,
23071                line_height: relative(settings.buffer_line_height.value()),
23072                ..Default::default()
23073            },
23074            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23075                color: cx.theme().colors().editor_foreground,
23076                font_family: settings.buffer_font.family.clone(),
23077                font_features: settings.buffer_font.features.clone(),
23078                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23079                font_size: settings.buffer_font_size(cx).into(),
23080                font_weight: settings.buffer_font.weight,
23081                line_height: relative(settings.buffer_line_height.value()),
23082                ..Default::default()
23083            },
23084        };
23085        if let Some(text_style_refinement) = &self.text_style_refinement {
23086            text_style.refine(text_style_refinement)
23087        }
23088
23089        let background = match self.mode {
23090            EditorMode::SingleLine => cx.theme().system().transparent,
23091            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23092            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23093            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23094        };
23095
23096        EditorElement::new(
23097            &cx.entity(),
23098            EditorStyle {
23099                background,
23100                border: cx.theme().colors().border,
23101                local_player: cx.theme().players().local(),
23102                text: text_style,
23103                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23104                syntax: cx.theme().syntax().clone(),
23105                status: cx.theme().status().clone(),
23106                inlay_hints_style: make_inlay_hints_style(cx),
23107                edit_prediction_styles: make_suggestion_styles(cx),
23108                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23109                show_underlines: self.diagnostics_enabled(),
23110            },
23111        )
23112    }
23113}
23114
23115impl EntityInputHandler for Editor {
23116    fn text_for_range(
23117        &mut self,
23118        range_utf16: Range<usize>,
23119        adjusted_range: &mut Option<Range<usize>>,
23120        _: &mut Window,
23121        cx: &mut Context<Self>,
23122    ) -> Option<String> {
23123        let snapshot = self.buffer.read(cx).read(cx);
23124        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23125        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23126        if (start.0..end.0) != range_utf16 {
23127            adjusted_range.replace(start.0..end.0);
23128        }
23129        Some(snapshot.text_for_range(start..end).collect())
23130    }
23131
23132    fn selected_text_range(
23133        &mut self,
23134        ignore_disabled_input: bool,
23135        _: &mut Window,
23136        cx: &mut Context<Self>,
23137    ) -> Option<UTF16Selection> {
23138        // Prevent the IME menu from appearing when holding down an alphabetic key
23139        // while input is disabled.
23140        if !ignore_disabled_input && !self.input_enabled {
23141            return None;
23142        }
23143
23144        let selection = self.selections.newest::<OffsetUtf16>(cx);
23145        let range = selection.range();
23146
23147        Some(UTF16Selection {
23148            range: range.start.0..range.end.0,
23149            reversed: selection.reversed,
23150        })
23151    }
23152
23153    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23154        let snapshot = self.buffer.read(cx).read(cx);
23155        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23156        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23157    }
23158
23159    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23160        self.clear_highlights::<InputComposition>(cx);
23161        self.ime_transaction.take();
23162    }
23163
23164    fn replace_text_in_range(
23165        &mut self,
23166        range_utf16: Option<Range<usize>>,
23167        text: &str,
23168        window: &mut Window,
23169        cx: &mut Context<Self>,
23170    ) {
23171        if !self.input_enabled {
23172            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23173            return;
23174        }
23175
23176        self.transact(window, cx, |this, window, cx| {
23177            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23178                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23179                Some(this.selection_replacement_ranges(range_utf16, cx))
23180            } else {
23181                this.marked_text_ranges(cx)
23182            };
23183
23184            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23185                let newest_selection_id = this.selections.newest_anchor().id;
23186                this.selections
23187                    .all::<OffsetUtf16>(cx)
23188                    .iter()
23189                    .zip(ranges_to_replace.iter())
23190                    .find_map(|(selection, range)| {
23191                        if selection.id == newest_selection_id {
23192                            Some(
23193                                (range.start.0 as isize - selection.head().0 as isize)
23194                                    ..(range.end.0 as isize - selection.head().0 as isize),
23195                            )
23196                        } else {
23197                            None
23198                        }
23199                    })
23200            });
23201
23202            cx.emit(EditorEvent::InputHandled {
23203                utf16_range_to_replace: range_to_replace,
23204                text: text.into(),
23205            });
23206
23207            if let Some(new_selected_ranges) = new_selected_ranges {
23208                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23209                    selections.select_ranges(new_selected_ranges)
23210                });
23211                this.backspace(&Default::default(), window, cx);
23212            }
23213
23214            this.handle_input(text, window, cx);
23215        });
23216
23217        if let Some(transaction) = self.ime_transaction {
23218            self.buffer.update(cx, |buffer, cx| {
23219                buffer.group_until_transaction(transaction, cx);
23220            });
23221        }
23222
23223        self.unmark_text(window, cx);
23224    }
23225
23226    fn replace_and_mark_text_in_range(
23227        &mut self,
23228        range_utf16: Option<Range<usize>>,
23229        text: &str,
23230        new_selected_range_utf16: Option<Range<usize>>,
23231        window: &mut Window,
23232        cx: &mut Context<Self>,
23233    ) {
23234        if !self.input_enabled {
23235            return;
23236        }
23237
23238        let transaction = self.transact(window, cx, |this, window, cx| {
23239            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23240                let snapshot = this.buffer.read(cx).read(cx);
23241                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23242                    for marked_range in &mut marked_ranges {
23243                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23244                        marked_range.start.0 += relative_range_utf16.start;
23245                        marked_range.start =
23246                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23247                        marked_range.end =
23248                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23249                    }
23250                }
23251                Some(marked_ranges)
23252            } else if let Some(range_utf16) = range_utf16 {
23253                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23254                Some(this.selection_replacement_ranges(range_utf16, cx))
23255            } else {
23256                None
23257            };
23258
23259            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23260                let newest_selection_id = this.selections.newest_anchor().id;
23261                this.selections
23262                    .all::<OffsetUtf16>(cx)
23263                    .iter()
23264                    .zip(ranges_to_replace.iter())
23265                    .find_map(|(selection, range)| {
23266                        if selection.id == newest_selection_id {
23267                            Some(
23268                                (range.start.0 as isize - selection.head().0 as isize)
23269                                    ..(range.end.0 as isize - selection.head().0 as isize),
23270                            )
23271                        } else {
23272                            None
23273                        }
23274                    })
23275            });
23276
23277            cx.emit(EditorEvent::InputHandled {
23278                utf16_range_to_replace: range_to_replace,
23279                text: text.into(),
23280            });
23281
23282            if let Some(ranges) = ranges_to_replace {
23283                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23284                    s.select_ranges(ranges)
23285                });
23286            }
23287
23288            let marked_ranges = {
23289                let snapshot = this.buffer.read(cx).read(cx);
23290                this.selections
23291                    .disjoint_anchors()
23292                    .iter()
23293                    .map(|selection| {
23294                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23295                    })
23296                    .collect::<Vec<_>>()
23297            };
23298
23299            if text.is_empty() {
23300                this.unmark_text(window, cx);
23301            } else {
23302                this.highlight_text::<InputComposition>(
23303                    marked_ranges.clone(),
23304                    HighlightStyle {
23305                        underline: Some(UnderlineStyle {
23306                            thickness: px(1.),
23307                            color: None,
23308                            wavy: false,
23309                        }),
23310                        ..Default::default()
23311                    },
23312                    cx,
23313                );
23314            }
23315
23316            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23317            let use_autoclose = this.use_autoclose;
23318            let use_auto_surround = this.use_auto_surround;
23319            this.set_use_autoclose(false);
23320            this.set_use_auto_surround(false);
23321            this.handle_input(text, window, cx);
23322            this.set_use_autoclose(use_autoclose);
23323            this.set_use_auto_surround(use_auto_surround);
23324
23325            if let Some(new_selected_range) = new_selected_range_utf16 {
23326                let snapshot = this.buffer.read(cx).read(cx);
23327                let new_selected_ranges = marked_ranges
23328                    .into_iter()
23329                    .map(|marked_range| {
23330                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23331                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23332                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23333                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23334                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23335                    })
23336                    .collect::<Vec<_>>();
23337
23338                drop(snapshot);
23339                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23340                    selections.select_ranges(new_selected_ranges)
23341                });
23342            }
23343        });
23344
23345        self.ime_transaction = self.ime_transaction.or(transaction);
23346        if let Some(transaction) = self.ime_transaction {
23347            self.buffer.update(cx, |buffer, cx| {
23348                buffer.group_until_transaction(transaction, cx);
23349            });
23350        }
23351
23352        if self.text_highlights::<InputComposition>(cx).is_none() {
23353            self.ime_transaction.take();
23354        }
23355    }
23356
23357    fn bounds_for_range(
23358        &mut self,
23359        range_utf16: Range<usize>,
23360        element_bounds: gpui::Bounds<Pixels>,
23361        window: &mut Window,
23362        cx: &mut Context<Self>,
23363    ) -> Option<gpui::Bounds<Pixels>> {
23364        let text_layout_details = self.text_layout_details(window);
23365        let CharacterDimensions {
23366            em_width,
23367            em_advance,
23368            line_height,
23369        } = self.character_dimensions(window);
23370
23371        let snapshot = self.snapshot(window, cx);
23372        let scroll_position = snapshot.scroll_position();
23373        let scroll_left = scroll_position.x * em_advance;
23374
23375        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23376        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23377            + self.gutter_dimensions.full_width();
23378        let y = line_height * (start.row().as_f32() - scroll_position.y);
23379
23380        Some(Bounds {
23381            origin: element_bounds.origin + point(x, y),
23382            size: size(em_width, line_height),
23383        })
23384    }
23385
23386    fn character_index_for_point(
23387        &mut self,
23388        point: gpui::Point<Pixels>,
23389        _window: &mut Window,
23390        _cx: &mut Context<Self>,
23391    ) -> Option<usize> {
23392        let position_map = self.last_position_map.as_ref()?;
23393        if !position_map.text_hitbox.contains(&point) {
23394            return None;
23395        }
23396        let display_point = position_map.point_for_position(point).previous_valid;
23397        let anchor = position_map
23398            .snapshot
23399            .display_point_to_anchor(display_point, Bias::Left);
23400        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23401        Some(utf16_offset.0)
23402    }
23403}
23404
23405trait SelectionExt {
23406    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23407    fn spanned_rows(
23408        &self,
23409        include_end_if_at_line_start: bool,
23410        map: &DisplaySnapshot,
23411    ) -> Range<MultiBufferRow>;
23412}
23413
23414impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23415    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23416        let start = self
23417            .start
23418            .to_point(&map.buffer_snapshot)
23419            .to_display_point(map);
23420        let end = self
23421            .end
23422            .to_point(&map.buffer_snapshot)
23423            .to_display_point(map);
23424        if self.reversed {
23425            end..start
23426        } else {
23427            start..end
23428        }
23429    }
23430
23431    fn spanned_rows(
23432        &self,
23433        include_end_if_at_line_start: bool,
23434        map: &DisplaySnapshot,
23435    ) -> Range<MultiBufferRow> {
23436        let start = self.start.to_point(&map.buffer_snapshot);
23437        let mut end = self.end.to_point(&map.buffer_snapshot);
23438        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23439            end.row -= 1;
23440        }
23441
23442        let buffer_start = map.prev_line_boundary(start).0;
23443        let buffer_end = map.next_line_boundary(end).0;
23444        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23445    }
23446}
23447
23448impl<T: InvalidationRegion> InvalidationStack<T> {
23449    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23450    where
23451        S: Clone + ToOffset,
23452    {
23453        while let Some(region) = self.last() {
23454            let all_selections_inside_invalidation_ranges =
23455                if selections.len() == region.ranges().len() {
23456                    selections
23457                        .iter()
23458                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23459                        .all(|(selection, invalidation_range)| {
23460                            let head = selection.head().to_offset(buffer);
23461                            invalidation_range.start <= head && invalidation_range.end >= head
23462                        })
23463                } else {
23464                    false
23465                };
23466
23467            if all_selections_inside_invalidation_ranges {
23468                break;
23469            } else {
23470                self.pop();
23471            }
23472        }
23473    }
23474}
23475
23476impl<T> Default for InvalidationStack<T> {
23477    fn default() -> Self {
23478        Self(Default::default())
23479    }
23480}
23481
23482impl<T> Deref for InvalidationStack<T> {
23483    type Target = Vec<T>;
23484
23485    fn deref(&self) -> &Self::Target {
23486        &self.0
23487    }
23488}
23489
23490impl<T> DerefMut for InvalidationStack<T> {
23491    fn deref_mut(&mut self) -> &mut Self::Target {
23492        &mut self.0
23493    }
23494}
23495
23496impl InvalidationRegion for SnippetState {
23497    fn ranges(&self) -> &[Range<Anchor>] {
23498        &self.ranges[self.active_index]
23499    }
23500}
23501
23502fn edit_prediction_edit_text(
23503    current_snapshot: &BufferSnapshot,
23504    edits: &[(Range<Anchor>, String)],
23505    edit_preview: &EditPreview,
23506    include_deletions: bool,
23507    cx: &App,
23508) -> HighlightedText {
23509    let edits = edits
23510        .iter()
23511        .map(|(anchor, text)| {
23512            (
23513                anchor.start.text_anchor..anchor.end.text_anchor,
23514                text.clone(),
23515            )
23516        })
23517        .collect::<Vec<_>>();
23518
23519    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23520}
23521
23522fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23523    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23524    // Just show the raw edit text with basic styling
23525    let mut text = String::new();
23526    let mut highlights = Vec::new();
23527
23528    let insertion_highlight_style = HighlightStyle {
23529        color: Some(cx.theme().colors().text),
23530        ..Default::default()
23531    };
23532
23533    for (_, edit_text) in edits {
23534        let start_offset = text.len();
23535        text.push_str(edit_text);
23536        let end_offset = text.len();
23537
23538        if start_offset < end_offset {
23539            highlights.push((start_offset..end_offset, insertion_highlight_style));
23540        }
23541    }
23542
23543    HighlightedText {
23544        text: text.into(),
23545        highlights,
23546    }
23547}
23548
23549pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23550    match severity {
23551        lsp::DiagnosticSeverity::ERROR => colors.error,
23552        lsp::DiagnosticSeverity::WARNING => colors.warning,
23553        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23554        lsp::DiagnosticSeverity::HINT => colors.info,
23555        _ => colors.ignored,
23556    }
23557}
23558
23559pub fn styled_runs_for_code_label<'a>(
23560    label: &'a CodeLabel,
23561    syntax_theme: &'a theme::SyntaxTheme,
23562) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23563    let fade_out = HighlightStyle {
23564        fade_out: Some(0.35),
23565        ..Default::default()
23566    };
23567
23568    let mut prev_end = label.filter_range.end;
23569    label
23570        .runs
23571        .iter()
23572        .enumerate()
23573        .flat_map(move |(ix, (range, highlight_id))| {
23574            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23575                style
23576            } else {
23577                return Default::default();
23578            };
23579            let mut muted_style = style;
23580            muted_style.highlight(fade_out);
23581
23582            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23583            if range.start >= label.filter_range.end {
23584                if range.start > prev_end {
23585                    runs.push((prev_end..range.start, fade_out));
23586                }
23587                runs.push((range.clone(), muted_style));
23588            } else if range.end <= label.filter_range.end {
23589                runs.push((range.clone(), style));
23590            } else {
23591                runs.push((range.start..label.filter_range.end, style));
23592                runs.push((label.filter_range.end..range.end, muted_style));
23593            }
23594            prev_end = cmp::max(prev_end, range.end);
23595
23596            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23597                runs.push((prev_end..label.text.len(), fade_out));
23598            }
23599
23600            runs
23601        })
23602}
23603
23604pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23605    let mut prev_index = 0;
23606    let mut prev_codepoint: Option<char> = None;
23607    text.char_indices()
23608        .chain([(text.len(), '\0')])
23609        .filter_map(move |(index, codepoint)| {
23610            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23611            let is_boundary = index == text.len()
23612                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23613                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23614            if is_boundary {
23615                let chunk = &text[prev_index..index];
23616                prev_index = index;
23617                Some(chunk)
23618            } else {
23619                None
23620            }
23621        })
23622}
23623
23624pub trait RangeToAnchorExt: Sized {
23625    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23626
23627    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23628        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23629        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23630    }
23631}
23632
23633impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23634    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23635        let start_offset = self.start.to_offset(snapshot);
23636        let end_offset = self.end.to_offset(snapshot);
23637        if start_offset == end_offset {
23638            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23639        } else {
23640            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23641        }
23642    }
23643}
23644
23645pub trait RowExt {
23646    fn as_f32(&self) -> f32;
23647
23648    fn next_row(&self) -> Self;
23649
23650    fn previous_row(&self) -> Self;
23651
23652    fn minus(&self, other: Self) -> u32;
23653}
23654
23655impl RowExt for DisplayRow {
23656    fn as_f32(&self) -> f32 {
23657        self.0 as f32
23658    }
23659
23660    fn next_row(&self) -> Self {
23661        Self(self.0 + 1)
23662    }
23663
23664    fn previous_row(&self) -> Self {
23665        Self(self.0.saturating_sub(1))
23666    }
23667
23668    fn minus(&self, other: Self) -> u32 {
23669        self.0 - other.0
23670    }
23671}
23672
23673impl RowExt for MultiBufferRow {
23674    fn as_f32(&self) -> f32 {
23675        self.0 as f32
23676    }
23677
23678    fn next_row(&self) -> Self {
23679        Self(self.0 + 1)
23680    }
23681
23682    fn previous_row(&self) -> Self {
23683        Self(self.0.saturating_sub(1))
23684    }
23685
23686    fn minus(&self, other: Self) -> u32 {
23687        self.0 - other.0
23688    }
23689}
23690
23691trait RowRangeExt {
23692    type Row;
23693
23694    fn len(&self) -> usize;
23695
23696    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23697}
23698
23699impl RowRangeExt for Range<MultiBufferRow> {
23700    type Row = MultiBufferRow;
23701
23702    fn len(&self) -> usize {
23703        (self.end.0 - self.start.0) as usize
23704    }
23705
23706    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23707        (self.start.0..self.end.0).map(MultiBufferRow)
23708    }
23709}
23710
23711impl RowRangeExt for Range<DisplayRow> {
23712    type Row = DisplayRow;
23713
23714    fn len(&self) -> usize {
23715        (self.end.0 - self.start.0) as usize
23716    }
23717
23718    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23719        (self.start.0..self.end.0).map(DisplayRow)
23720    }
23721}
23722
23723/// If select range has more than one line, we
23724/// just point the cursor to range.start.
23725fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23726    if range.start.row == range.end.row {
23727        range
23728    } else {
23729        range.start..range.start
23730    }
23731}
23732pub struct KillRing(ClipboardItem);
23733impl Global for KillRing {}
23734
23735const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23736
23737enum BreakpointPromptEditAction {
23738    Log,
23739    Condition,
23740    HitCondition,
23741}
23742
23743struct BreakpointPromptEditor {
23744    pub(crate) prompt: Entity<Editor>,
23745    editor: WeakEntity<Editor>,
23746    breakpoint_anchor: Anchor,
23747    breakpoint: Breakpoint,
23748    edit_action: BreakpointPromptEditAction,
23749    block_ids: HashSet<CustomBlockId>,
23750    editor_margins: Arc<Mutex<EditorMargins>>,
23751    _subscriptions: Vec<Subscription>,
23752}
23753
23754impl BreakpointPromptEditor {
23755    const MAX_LINES: u8 = 4;
23756
23757    fn new(
23758        editor: WeakEntity<Editor>,
23759        breakpoint_anchor: Anchor,
23760        breakpoint: Breakpoint,
23761        edit_action: BreakpointPromptEditAction,
23762        window: &mut Window,
23763        cx: &mut Context<Self>,
23764    ) -> Self {
23765        let base_text = match edit_action {
23766            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23767            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23768            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23769        }
23770        .map(|msg| msg.to_string())
23771        .unwrap_or_default();
23772
23773        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23774        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23775
23776        let prompt = cx.new(|cx| {
23777            let mut prompt = Editor::new(
23778                EditorMode::AutoHeight {
23779                    min_lines: 1,
23780                    max_lines: Some(Self::MAX_LINES as usize),
23781                },
23782                buffer,
23783                None,
23784                window,
23785                cx,
23786            );
23787            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23788            prompt.set_show_cursor_when_unfocused(false, cx);
23789            prompt.set_placeholder_text(
23790                match edit_action {
23791                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23792                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23793                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23794                },
23795                cx,
23796            );
23797
23798            prompt
23799        });
23800
23801        Self {
23802            prompt,
23803            editor,
23804            breakpoint_anchor,
23805            breakpoint,
23806            edit_action,
23807            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23808            block_ids: Default::default(),
23809            _subscriptions: vec![],
23810        }
23811    }
23812
23813    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23814        self.block_ids.extend(block_ids)
23815    }
23816
23817    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23818        if let Some(editor) = self.editor.upgrade() {
23819            let message = self
23820                .prompt
23821                .read(cx)
23822                .buffer
23823                .read(cx)
23824                .as_singleton()
23825                .expect("A multi buffer in breakpoint prompt isn't possible")
23826                .read(cx)
23827                .as_rope()
23828                .to_string();
23829
23830            editor.update(cx, |editor, cx| {
23831                editor.edit_breakpoint_at_anchor(
23832                    self.breakpoint_anchor,
23833                    self.breakpoint.clone(),
23834                    match self.edit_action {
23835                        BreakpointPromptEditAction::Log => {
23836                            BreakpointEditAction::EditLogMessage(message.into())
23837                        }
23838                        BreakpointPromptEditAction::Condition => {
23839                            BreakpointEditAction::EditCondition(message.into())
23840                        }
23841                        BreakpointPromptEditAction::HitCondition => {
23842                            BreakpointEditAction::EditHitCondition(message.into())
23843                        }
23844                    },
23845                    cx,
23846                );
23847
23848                editor.remove_blocks(self.block_ids.clone(), None, cx);
23849                cx.focus_self(window);
23850            });
23851        }
23852    }
23853
23854    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23855        self.editor
23856            .update(cx, |editor, cx| {
23857                editor.remove_blocks(self.block_ids.clone(), None, cx);
23858                window.focus(&editor.focus_handle);
23859            })
23860            .log_err();
23861    }
23862
23863    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23864        let settings = ThemeSettings::get_global(cx);
23865        let text_style = TextStyle {
23866            color: if self.prompt.read(cx).read_only(cx) {
23867                cx.theme().colors().text_disabled
23868            } else {
23869                cx.theme().colors().text
23870            },
23871            font_family: settings.buffer_font.family.clone(),
23872            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23873            font_size: settings.buffer_font_size(cx).into(),
23874            font_weight: settings.buffer_font.weight,
23875            line_height: relative(settings.buffer_line_height.value()),
23876            ..Default::default()
23877        };
23878        EditorElement::new(
23879            &self.prompt,
23880            EditorStyle {
23881                background: cx.theme().colors().editor_background,
23882                local_player: cx.theme().players().local(),
23883                text: text_style,
23884                ..Default::default()
23885            },
23886        )
23887    }
23888}
23889
23890impl Render for BreakpointPromptEditor {
23891    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23892        let editor_margins = *self.editor_margins.lock();
23893        let gutter_dimensions = editor_margins.gutter;
23894        h_flex()
23895            .key_context("Editor")
23896            .bg(cx.theme().colors().editor_background)
23897            .border_y_1()
23898            .border_color(cx.theme().status().info_border)
23899            .size_full()
23900            .py(window.line_height() / 2.5)
23901            .on_action(cx.listener(Self::confirm))
23902            .on_action(cx.listener(Self::cancel))
23903            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23904            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23905    }
23906}
23907
23908impl Focusable for BreakpointPromptEditor {
23909    fn focus_handle(&self, cx: &App) -> FocusHandle {
23910        self.prompt.focus_handle(cx)
23911    }
23912}
23913
23914fn all_edits_insertions_or_deletions(
23915    edits: &Vec<(Range<Anchor>, String)>,
23916    snapshot: &MultiBufferSnapshot,
23917) -> bool {
23918    let mut all_insertions = true;
23919    let mut all_deletions = true;
23920
23921    for (range, new_text) in edits.iter() {
23922        let range_is_empty = range.to_offset(snapshot).is_empty();
23923        let text_is_empty = new_text.is_empty();
23924
23925        if range_is_empty != text_is_empty {
23926            if range_is_empty {
23927                all_deletions = false;
23928            } else {
23929                all_insertions = false;
23930            }
23931        } else {
23932            return false;
23933        }
23934
23935        if !all_insertions && !all_deletions {
23936            return false;
23937        }
23938    }
23939    all_insertions || all_deletions
23940}
23941
23942struct MissingEditPredictionKeybindingTooltip;
23943
23944impl Render for MissingEditPredictionKeybindingTooltip {
23945    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23946        ui::tooltip_container(window, cx, |container, _, cx| {
23947            container
23948                .flex_shrink_0()
23949                .max_w_80()
23950                .min_h(rems_from_px(124.))
23951                .justify_between()
23952                .child(
23953                    v_flex()
23954                        .flex_1()
23955                        .text_ui_sm(cx)
23956                        .child(Label::new("Conflict with Accept Keybinding"))
23957                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23958                )
23959                .child(
23960                    h_flex()
23961                        .pb_1()
23962                        .gap_1()
23963                        .items_end()
23964                        .w_full()
23965                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23966                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23967                        }))
23968                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23969                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23970                        })),
23971                )
23972        })
23973    }
23974}
23975
23976#[derive(Debug, Clone, Copy, PartialEq)]
23977pub struct LineHighlight {
23978    pub background: Background,
23979    pub border: Option<gpui::Hsla>,
23980    pub include_gutter: bool,
23981    pub type_id: Option<TypeId>,
23982}
23983
23984struct LineManipulationResult {
23985    pub new_text: String,
23986    pub line_count_before: usize,
23987    pub line_count_after: usize,
23988}
23989
23990fn render_diff_hunk_controls(
23991    row: u32,
23992    status: &DiffHunkStatus,
23993    hunk_range: Range<Anchor>,
23994    is_created_file: bool,
23995    line_height: Pixels,
23996    editor: &Entity<Editor>,
23997    _window: &mut Window,
23998    cx: &mut App,
23999) -> AnyElement {
24000    h_flex()
24001        .h(line_height)
24002        .mr_1()
24003        .gap_1()
24004        .px_0p5()
24005        .pb_1()
24006        .border_x_1()
24007        .border_b_1()
24008        .border_color(cx.theme().colors().border_variant)
24009        .rounded_b_lg()
24010        .bg(cx.theme().colors().editor_background)
24011        .gap_1()
24012        .block_mouse_except_scroll()
24013        .shadow_md()
24014        .child(if status.has_secondary_hunk() {
24015            Button::new(("stage", row as u64), "Stage")
24016                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24017                .tooltip({
24018                    let focus_handle = editor.focus_handle(cx);
24019                    move |window, cx| {
24020                        Tooltip::for_action_in(
24021                            "Stage Hunk",
24022                            &::git::ToggleStaged,
24023                            &focus_handle,
24024                            window,
24025                            cx,
24026                        )
24027                    }
24028                })
24029                .on_click({
24030                    let editor = editor.clone();
24031                    move |_event, _window, cx| {
24032                        editor.update(cx, |editor, cx| {
24033                            editor.stage_or_unstage_diff_hunks(
24034                                true,
24035                                vec![hunk_range.start..hunk_range.start],
24036                                cx,
24037                            );
24038                        });
24039                    }
24040                })
24041        } else {
24042            Button::new(("unstage", row as u64), "Unstage")
24043                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24044                .tooltip({
24045                    let focus_handle = editor.focus_handle(cx);
24046                    move |window, cx| {
24047                        Tooltip::for_action_in(
24048                            "Unstage Hunk",
24049                            &::git::ToggleStaged,
24050                            &focus_handle,
24051                            window,
24052                            cx,
24053                        )
24054                    }
24055                })
24056                .on_click({
24057                    let editor = editor.clone();
24058                    move |_event, _window, cx| {
24059                        editor.update(cx, |editor, cx| {
24060                            editor.stage_or_unstage_diff_hunks(
24061                                false,
24062                                vec![hunk_range.start..hunk_range.start],
24063                                cx,
24064                            );
24065                        });
24066                    }
24067                })
24068        })
24069        .child(
24070            Button::new(("restore", row as u64), "Restore")
24071                .tooltip({
24072                    let focus_handle = editor.focus_handle(cx);
24073                    move |window, cx| {
24074                        Tooltip::for_action_in(
24075                            "Restore Hunk",
24076                            &::git::Restore,
24077                            &focus_handle,
24078                            window,
24079                            cx,
24080                        )
24081                    }
24082                })
24083                .on_click({
24084                    let editor = editor.clone();
24085                    move |_event, window, cx| {
24086                        editor.update(cx, |editor, cx| {
24087                            let snapshot = editor.snapshot(window, cx);
24088                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24089                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24090                        });
24091                    }
24092                })
24093                .disabled(is_created_file),
24094        )
24095        .when(
24096            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24097            |el| {
24098                el.child(
24099                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24100                        .shape(IconButtonShape::Square)
24101                        .icon_size(IconSize::Small)
24102                        // .disabled(!has_multiple_hunks)
24103                        .tooltip({
24104                            let focus_handle = editor.focus_handle(cx);
24105                            move |window, cx| {
24106                                Tooltip::for_action_in(
24107                                    "Next Hunk",
24108                                    &GoToHunk,
24109                                    &focus_handle,
24110                                    window,
24111                                    cx,
24112                                )
24113                            }
24114                        })
24115                        .on_click({
24116                            let editor = editor.clone();
24117                            move |_event, window, cx| {
24118                                editor.update(cx, |editor, cx| {
24119                                    let snapshot = editor.snapshot(window, cx);
24120                                    let position =
24121                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24122                                    editor.go_to_hunk_before_or_after_position(
24123                                        &snapshot,
24124                                        position,
24125                                        Direction::Next,
24126                                        window,
24127                                        cx,
24128                                    );
24129                                    editor.expand_selected_diff_hunks(cx);
24130                                });
24131                            }
24132                        }),
24133                )
24134                .child(
24135                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24136                        .shape(IconButtonShape::Square)
24137                        .icon_size(IconSize::Small)
24138                        // .disabled(!has_multiple_hunks)
24139                        .tooltip({
24140                            let focus_handle = editor.focus_handle(cx);
24141                            move |window, cx| {
24142                                Tooltip::for_action_in(
24143                                    "Previous Hunk",
24144                                    &GoToPreviousHunk,
24145                                    &focus_handle,
24146                                    window,
24147                                    cx,
24148                                )
24149                            }
24150                        })
24151                        .on_click({
24152                            let editor = editor.clone();
24153                            move |_event, window, cx| {
24154                                editor.update(cx, |editor, cx| {
24155                                    let snapshot = editor.snapshot(window, cx);
24156                                    let point =
24157                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24158                                    editor.go_to_hunk_before_or_after_position(
24159                                        &snapshot,
24160                                        point,
24161                                        Direction::Prev,
24162                                        window,
24163                                        cx,
24164                                    );
24165                                    editor.expand_selected_diff_hunks(cx);
24166                                });
24167                            }
24168                        }),
24169                )
24170            },
24171        )
24172        .into_any_element()
24173}
24174
24175pub fn multibuffer_context_lines(cx: &App) -> u32 {
24176    EditorSettings::try_get(cx)
24177        .map(|settings| settings.excerpt_context_lines)
24178        .unwrap_or(2)
24179        .clamp(1, 32)
24180}