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, CompletionIntent, CompletionResponse,
  151    CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, Location, LocationLink,
  152    PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::breakpoint_store::Breakpoint,
  154    debugger::{
  155        breakpoint_store::{
  156            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  157            BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  164    project_settings::{GitGutterSetting, ProjectSettings},
  165};
  166use rand::{seq::SliceRandom, thread_rng};
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  169use selections_collection::{
  170    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  171};
  172use serde::{Deserialize, Serialize};
  173use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::TypeId,
  178    borrow::Cow,
  179    cell::OnceCell,
  180    cell::RefCell,
  181    cmp::{self, Ordering, Reverse},
  182    iter::Peekable,
  183    mem,
  184    num::NonZeroU32,
  185    ops::Not,
  186    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use sum_tree::TreeMap;
  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);
  229const 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: TreeMap<HighlightKey, BackgroundHighlight>,
 1063    gutter_highlights: TreeMap<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: TreeMap::default(),
 2115            gutter_highlights: TreeMap::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            if let Some(provider_responses) = provider_responses.await.log_err()
 5639                && !provider_responses.is_empty()
 5640            {
 5641                for response in provider_responses {
 5642                    completions.extend(response.completions);
 5643                    is_incomplete = is_incomplete || response.is_incomplete;
 5644                }
 5645                if completion_settings.words == WordsCompletionMode::Fallback {
 5646                    words = Task::ready(BTreeMap::default());
 5647                }
 5648            }
 5649
 5650            let mut words = words.await;
 5651            if let Some(word_to_exclude) = &word_to_exclude {
 5652                words.remove(word_to_exclude);
 5653            }
 5654            for lsp_completion in &completions {
 5655                words.remove(&lsp_completion.new_text);
 5656            }
 5657            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5658                replace_range: word_replace_range.clone(),
 5659                new_text: word.clone(),
 5660                label: CodeLabel::plain(word, None),
 5661                icon_path: None,
 5662                documentation: None,
 5663                source: CompletionSource::BufferWord {
 5664                    word_range,
 5665                    resolved: false,
 5666                },
 5667                insert_text_mode: Some(InsertTextMode::AS_IS),
 5668                confirm: None,
 5669            }));
 5670
 5671            let menu = if completions.is_empty() {
 5672                None
 5673            } else {
 5674                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5675                    let languages = editor
 5676                        .workspace
 5677                        .as_ref()
 5678                        .and_then(|(workspace, _)| workspace.upgrade())
 5679                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5680                    let menu = CompletionsMenu::new(
 5681                        id,
 5682                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5683                        sort_completions,
 5684                        show_completion_documentation,
 5685                        position,
 5686                        query.clone(),
 5687                        is_incomplete,
 5688                        buffer.clone(),
 5689                        completions.into(),
 5690                        snippet_sort_order,
 5691                        languages,
 5692                        language,
 5693                        cx,
 5694                    );
 5695
 5696                    let query = if filter_completions { query } else { None };
 5697                    let matches_task = if let Some(query) = query {
 5698                        menu.do_async_filtering(query, cx)
 5699                    } else {
 5700                        Task::ready(menu.unfiltered_matches())
 5701                    };
 5702                    (menu, matches_task)
 5703                }) else {
 5704                    return;
 5705                };
 5706
 5707                let matches = matches_task.await;
 5708
 5709                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5710                    // Newer menu already set, so exit.
 5711                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5712                        editor.context_menu.borrow().as_ref()
 5713                        && prev_menu.id > id
 5714                    {
 5715                        return;
 5716                    };
 5717
 5718                    // Only valid to take prev_menu because it the new menu is immediately set
 5719                    // below, or the menu is hidden.
 5720                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5721                        editor.context_menu.borrow_mut().take()
 5722                    {
 5723                        let position_matches =
 5724                            if prev_menu.initial_position == menu.initial_position {
 5725                                true
 5726                            } else {
 5727                                let snapshot = editor.buffer.read(cx).read(cx);
 5728                                prev_menu.initial_position.to_offset(&snapshot)
 5729                                    == menu.initial_position.to_offset(&snapshot)
 5730                            };
 5731                        if position_matches {
 5732                            // Preserve markdown cache before `set_filter_results` because it will
 5733                            // try to populate the documentation cache.
 5734                            menu.preserve_markdown_cache(prev_menu);
 5735                        }
 5736                    };
 5737
 5738                    menu.set_filter_results(matches, provider, window, cx);
 5739                }) else {
 5740                    return;
 5741                };
 5742
 5743                menu.visible().then_some(menu)
 5744            };
 5745
 5746            editor
 5747                .update_in(cx, |editor, window, cx| {
 5748                    if editor.focus_handle.is_focused(window)
 5749                        && let Some(menu) = menu
 5750                    {
 5751                        *editor.context_menu.borrow_mut() =
 5752                            Some(CodeContextMenu::Completions(menu));
 5753
 5754                        crate::hover_popover::hide_hover(editor, cx);
 5755                        if editor.show_edit_predictions_in_menu() {
 5756                            editor.update_visible_edit_prediction(window, cx);
 5757                        } else {
 5758                            editor.discard_edit_prediction(false, cx);
 5759                        }
 5760
 5761                        cx.notify();
 5762                        return;
 5763                    }
 5764
 5765                    if editor.completion_tasks.len() <= 1 {
 5766                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5767                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5768                        // If it was already hidden and we don't show edit predictions in the menu,
 5769                        // we should also show the edit prediction when available.
 5770                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5771                            editor.update_visible_edit_prediction(window, cx);
 5772                        }
 5773                    }
 5774                })
 5775                .ok();
 5776        });
 5777
 5778        self.completion_tasks.push((id, task));
 5779    }
 5780
 5781    #[cfg(feature = "test-support")]
 5782    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5783        let menu = self.context_menu.borrow();
 5784        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5785            let completions = menu.completions.borrow();
 5786            Some(completions.to_vec())
 5787        } else {
 5788            None
 5789        }
 5790    }
 5791
 5792    pub fn with_completions_menu_matching_id<R>(
 5793        &self,
 5794        id: CompletionId,
 5795        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5796    ) -> R {
 5797        let mut context_menu = self.context_menu.borrow_mut();
 5798        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5799            return f(None);
 5800        };
 5801        if completions_menu.id != id {
 5802            return f(None);
 5803        }
 5804        f(Some(completions_menu))
 5805    }
 5806
 5807    pub fn confirm_completion(
 5808        &mut self,
 5809        action: &ConfirmCompletion,
 5810        window: &mut Window,
 5811        cx: &mut Context<Self>,
 5812    ) -> Option<Task<Result<()>>> {
 5813        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5814        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5815    }
 5816
 5817    pub fn confirm_completion_insert(
 5818        &mut self,
 5819        _: &ConfirmCompletionInsert,
 5820        window: &mut Window,
 5821        cx: &mut Context<Self>,
 5822    ) -> Option<Task<Result<()>>> {
 5823        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5824        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5825    }
 5826
 5827    pub fn confirm_completion_replace(
 5828        &mut self,
 5829        _: &ConfirmCompletionReplace,
 5830        window: &mut Window,
 5831        cx: &mut Context<Self>,
 5832    ) -> Option<Task<Result<()>>> {
 5833        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5834        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5835    }
 5836
 5837    pub fn compose_completion(
 5838        &mut self,
 5839        action: &ComposeCompletion,
 5840        window: &mut Window,
 5841        cx: &mut Context<Self>,
 5842    ) -> Option<Task<Result<()>>> {
 5843        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5844        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5845    }
 5846
 5847    fn do_completion(
 5848        &mut self,
 5849        item_ix: Option<usize>,
 5850        intent: CompletionIntent,
 5851        window: &mut Window,
 5852        cx: &mut Context<Editor>,
 5853    ) -> Option<Task<Result<()>>> {
 5854        use language::ToOffset as _;
 5855
 5856        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5857        else {
 5858            return None;
 5859        };
 5860
 5861        let candidate_id = {
 5862            let entries = completions_menu.entries.borrow();
 5863            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5864            if self.show_edit_predictions_in_menu() {
 5865                self.discard_edit_prediction(true, cx);
 5866            }
 5867            mat.candidate_id
 5868        };
 5869
 5870        let completion = completions_menu
 5871            .completions
 5872            .borrow()
 5873            .get(candidate_id)?
 5874            .clone();
 5875        cx.stop_propagation();
 5876
 5877        let buffer_handle = completions_menu.buffer.clone();
 5878
 5879        let CompletionEdit {
 5880            new_text,
 5881            snippet,
 5882            replace_range,
 5883        } = process_completion_for_edit(
 5884            &completion,
 5885            intent,
 5886            &buffer_handle,
 5887            &completions_menu.initial_position.text_anchor,
 5888            cx,
 5889        );
 5890
 5891        let buffer = buffer_handle.read(cx);
 5892        let snapshot = self.buffer.read(cx).snapshot(cx);
 5893        let newest_anchor = self.selections.newest_anchor();
 5894        let replace_range_multibuffer = {
 5895            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5896            let multibuffer_anchor = snapshot
 5897                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5898                .unwrap()
 5899                ..snapshot
 5900                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5901                    .unwrap();
 5902            multibuffer_anchor.start.to_offset(&snapshot)
 5903                ..multibuffer_anchor.end.to_offset(&snapshot)
 5904        };
 5905        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5906            return None;
 5907        }
 5908
 5909        let old_text = buffer
 5910            .text_for_range(replace_range.clone())
 5911            .collect::<String>();
 5912        let lookbehind = newest_anchor
 5913            .start
 5914            .text_anchor
 5915            .to_offset(buffer)
 5916            .saturating_sub(replace_range.start);
 5917        let lookahead = replace_range
 5918            .end
 5919            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5920        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5921        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5922
 5923        let selections = self.selections.all::<usize>(cx);
 5924        let mut ranges = Vec::new();
 5925        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5926
 5927        for selection in &selections {
 5928            let range = if selection.id == newest_anchor.id {
 5929                replace_range_multibuffer.clone()
 5930            } else {
 5931                let mut range = selection.range();
 5932
 5933                // if prefix is present, don't duplicate it
 5934                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5935                    range.start = range.start.saturating_sub(lookbehind);
 5936
 5937                    // if suffix is also present, mimic the newest cursor and replace it
 5938                    if selection.id != newest_anchor.id
 5939                        && snapshot.contains_str_at(range.end, suffix)
 5940                    {
 5941                        range.end += lookahead;
 5942                    }
 5943                }
 5944                range
 5945            };
 5946
 5947            ranges.push(range.clone());
 5948
 5949            if !self.linked_edit_ranges.is_empty() {
 5950                let start_anchor = snapshot.anchor_before(range.start);
 5951                let end_anchor = snapshot.anchor_after(range.end);
 5952                if let Some(ranges) = self
 5953                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5954                {
 5955                    for (buffer, edits) in ranges {
 5956                        linked_edits
 5957                            .entry(buffer.clone())
 5958                            .or_default()
 5959                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5960                    }
 5961                }
 5962            }
 5963        }
 5964
 5965        let common_prefix_len = old_text
 5966            .chars()
 5967            .zip(new_text.chars())
 5968            .take_while(|(a, b)| a == b)
 5969            .map(|(a, _)| a.len_utf8())
 5970            .sum::<usize>();
 5971
 5972        cx.emit(EditorEvent::InputHandled {
 5973            utf16_range_to_replace: None,
 5974            text: new_text[common_prefix_len..].into(),
 5975        });
 5976
 5977        self.transact(window, cx, |editor, window, cx| {
 5978            if let Some(mut snippet) = snippet {
 5979                snippet.text = new_text.to_string();
 5980                editor
 5981                    .insert_snippet(&ranges, snippet, window, cx)
 5982                    .log_err();
 5983            } else {
 5984                editor.buffer.update(cx, |multi_buffer, cx| {
 5985                    let auto_indent = match completion.insert_text_mode {
 5986                        Some(InsertTextMode::AS_IS) => None,
 5987                        _ => editor.autoindent_mode.clone(),
 5988                    };
 5989                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5990                    multi_buffer.edit(edits, auto_indent, cx);
 5991                });
 5992            }
 5993            for (buffer, edits) in linked_edits {
 5994                buffer.update(cx, |buffer, cx| {
 5995                    let snapshot = buffer.snapshot();
 5996                    let edits = edits
 5997                        .into_iter()
 5998                        .map(|(range, text)| {
 5999                            use text::ToPoint as TP;
 6000                            let end_point = TP::to_point(&range.end, &snapshot);
 6001                            let start_point = TP::to_point(&range.start, &snapshot);
 6002                            (start_point..end_point, text)
 6003                        })
 6004                        .sorted_by_key(|(range, _)| range.start);
 6005                    buffer.edit(edits, None, cx);
 6006                })
 6007            }
 6008
 6009            editor.refresh_edit_prediction(true, false, window, cx);
 6010        });
 6011        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6012
 6013        let show_new_completions_on_confirm = completion
 6014            .confirm
 6015            .as_ref()
 6016            .is_some_and(|confirm| confirm(intent, window, cx));
 6017        if show_new_completions_on_confirm {
 6018            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6019        }
 6020
 6021        let provider = self.completion_provider.as_ref()?;
 6022        drop(completion);
 6023        let apply_edits = provider.apply_additional_edits_for_completion(
 6024            buffer_handle,
 6025            completions_menu.completions.clone(),
 6026            candidate_id,
 6027            true,
 6028            cx,
 6029        );
 6030
 6031        let editor_settings = EditorSettings::get_global(cx);
 6032        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6033            // After the code completion is finished, users often want to know what signatures are needed.
 6034            // so we should automatically call signature_help
 6035            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6036        }
 6037
 6038        Some(cx.foreground_executor().spawn(async move {
 6039            apply_edits.await?;
 6040            Ok(())
 6041        }))
 6042    }
 6043
 6044    pub fn toggle_code_actions(
 6045        &mut self,
 6046        action: &ToggleCodeActions,
 6047        window: &mut Window,
 6048        cx: &mut Context<Self>,
 6049    ) {
 6050        let quick_launch = action.quick_launch;
 6051        let mut context_menu = self.context_menu.borrow_mut();
 6052        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6053            if code_actions.deployed_from == action.deployed_from {
 6054                // Toggle if we're selecting the same one
 6055                *context_menu = None;
 6056                cx.notify();
 6057                return;
 6058            } else {
 6059                // Otherwise, clear it and start a new one
 6060                *context_menu = None;
 6061                cx.notify();
 6062            }
 6063        }
 6064        drop(context_menu);
 6065        let snapshot = self.snapshot(window, cx);
 6066        let deployed_from = action.deployed_from.clone();
 6067        let action = action.clone();
 6068        self.completion_tasks.clear();
 6069        self.discard_edit_prediction(false, cx);
 6070
 6071        let multibuffer_point = match &action.deployed_from {
 6072            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6073                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6074            }
 6075            _ => self.selections.newest::<Point>(cx).head(),
 6076        };
 6077        let Some((buffer, buffer_row)) = snapshot
 6078            .buffer_snapshot
 6079            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6080            .and_then(|(buffer_snapshot, range)| {
 6081                self.buffer()
 6082                    .read(cx)
 6083                    .buffer(buffer_snapshot.remote_id())
 6084                    .map(|buffer| (buffer, range.start.row))
 6085            })
 6086        else {
 6087            return;
 6088        };
 6089        let buffer_id = buffer.read(cx).remote_id();
 6090        let tasks = self
 6091            .tasks
 6092            .get(&(buffer_id, buffer_row))
 6093            .map(|t| Arc::new(t.to_owned()));
 6094
 6095        if !self.focus_handle.is_focused(window) {
 6096            return;
 6097        }
 6098        let project = self.project.clone();
 6099
 6100        let code_actions_task = match deployed_from {
 6101            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6102            _ => self.code_actions(buffer_row, window, cx),
 6103        };
 6104
 6105        let runnable_task = match deployed_from {
 6106            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6107            _ => {
 6108                let mut task_context_task = Task::ready(None);
 6109                if let Some(tasks) = &tasks
 6110                    && let Some(project) = project
 6111                {
 6112                    task_context_task =
 6113                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6114                }
 6115
 6116                cx.spawn_in(window, {
 6117                    let buffer = buffer.clone();
 6118                    async move |editor, cx| {
 6119                        let task_context = task_context_task.await;
 6120
 6121                        let resolved_tasks =
 6122                            tasks
 6123                                .zip(task_context.clone())
 6124                                .map(|(tasks, task_context)| ResolvedTasks {
 6125                                    templates: tasks.resolve(&task_context).collect(),
 6126                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6127                                        multibuffer_point.row,
 6128                                        tasks.column,
 6129                                    )),
 6130                                });
 6131                        let debug_scenarios = editor
 6132                            .update(cx, |editor, cx| {
 6133                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6134                            })?
 6135                            .await;
 6136                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6137                    }
 6138                })
 6139            }
 6140        };
 6141
 6142        cx.spawn_in(window, async move |editor, cx| {
 6143            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6144            let code_actions = code_actions_task.await;
 6145            let spawn_straight_away = quick_launch
 6146                && resolved_tasks
 6147                    .as_ref()
 6148                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6149                && code_actions
 6150                    .as_ref()
 6151                    .is_none_or(|actions| actions.is_empty())
 6152                && debug_scenarios.is_empty();
 6153
 6154            editor.update_in(cx, |editor, window, cx| {
 6155                crate::hover_popover::hide_hover(editor, cx);
 6156                let actions = CodeActionContents::new(
 6157                    resolved_tasks,
 6158                    code_actions,
 6159                    debug_scenarios,
 6160                    task_context.unwrap_or_default(),
 6161                );
 6162
 6163                // Don't show the menu if there are no actions available
 6164                if actions.is_empty() {
 6165                    cx.notify();
 6166                    return Task::ready(Ok(()));
 6167                }
 6168
 6169                *editor.context_menu.borrow_mut() =
 6170                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6171                        buffer,
 6172                        actions,
 6173                        selected_item: Default::default(),
 6174                        scroll_handle: UniformListScrollHandle::default(),
 6175                        deployed_from,
 6176                    }));
 6177                cx.notify();
 6178                if spawn_straight_away
 6179                    && let Some(task) = editor.confirm_code_action(
 6180                        &ConfirmCodeAction { item_ix: Some(0) },
 6181                        window,
 6182                        cx,
 6183                    )
 6184                {
 6185                    return task;
 6186                }
 6187
 6188                Task::ready(Ok(()))
 6189            })
 6190        })
 6191        .detach_and_log_err(cx);
 6192    }
 6193
 6194    fn debug_scenarios(
 6195        &mut self,
 6196        resolved_tasks: &Option<ResolvedTasks>,
 6197        buffer: &Entity<Buffer>,
 6198        cx: &mut App,
 6199    ) -> Task<Vec<task::DebugScenario>> {
 6200        maybe!({
 6201            let project = self.project()?;
 6202            let dap_store = project.read(cx).dap_store();
 6203            let mut scenarios = vec![];
 6204            let resolved_tasks = resolved_tasks.as_ref()?;
 6205            let buffer = buffer.read(cx);
 6206            let language = buffer.language()?;
 6207            let file = buffer.file();
 6208            let debug_adapter = language_settings(language.name().into(), file, cx)
 6209                .debuggers
 6210                .first()
 6211                .map(SharedString::from)
 6212                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6213
 6214            dap_store.update(cx, |dap_store, cx| {
 6215                for (_, task) in &resolved_tasks.templates {
 6216                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6217                        task.original_task().clone(),
 6218                        debug_adapter.clone().into(),
 6219                        task.display_label().to_owned().into(),
 6220                        cx,
 6221                    );
 6222                    scenarios.push(maybe_scenario);
 6223                }
 6224            });
 6225            Some(cx.background_spawn(async move {
 6226                futures::future::join_all(scenarios)
 6227                    .await
 6228                    .into_iter()
 6229                    .flatten()
 6230                    .collect::<Vec<_>>()
 6231            }))
 6232        })
 6233        .unwrap_or_else(|| Task::ready(vec![]))
 6234    }
 6235
 6236    fn code_actions(
 6237        &mut self,
 6238        buffer_row: u32,
 6239        window: &mut Window,
 6240        cx: &mut Context<Self>,
 6241    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6242        let mut task = self.code_actions_task.take();
 6243        cx.spawn_in(window, async move |editor, cx| {
 6244            while let Some(prev_task) = task {
 6245                prev_task.await.log_err();
 6246                task = editor
 6247                    .update(cx, |this, _| this.code_actions_task.take())
 6248                    .ok()?;
 6249            }
 6250
 6251            editor
 6252                .update(cx, |editor, cx| {
 6253                    editor
 6254                        .available_code_actions
 6255                        .clone()
 6256                        .and_then(|(location, code_actions)| {
 6257                            let snapshot = location.buffer.read(cx).snapshot();
 6258                            let point_range = location.range.to_point(&snapshot);
 6259                            let point_range = point_range.start.row..=point_range.end.row;
 6260                            if point_range.contains(&buffer_row) {
 6261                                Some(code_actions)
 6262                            } else {
 6263                                None
 6264                            }
 6265                        })
 6266                })
 6267                .ok()
 6268                .flatten()
 6269        })
 6270    }
 6271
 6272    pub fn confirm_code_action(
 6273        &mut self,
 6274        action: &ConfirmCodeAction,
 6275        window: &mut Window,
 6276        cx: &mut Context<Self>,
 6277    ) -> Option<Task<Result<()>>> {
 6278        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6279
 6280        let actions_menu =
 6281            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6282                menu
 6283            } else {
 6284                return None;
 6285            };
 6286
 6287        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6288        let action = actions_menu.actions.get(action_ix)?;
 6289        let title = action.label();
 6290        let buffer = actions_menu.buffer;
 6291        let workspace = self.workspace()?;
 6292
 6293        match action {
 6294            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6295                workspace.update(cx, |workspace, cx| {
 6296                    workspace.schedule_resolved_task(
 6297                        task_source_kind,
 6298                        resolved_task,
 6299                        false,
 6300                        window,
 6301                        cx,
 6302                    );
 6303
 6304                    Some(Task::ready(Ok(())))
 6305                })
 6306            }
 6307            CodeActionsItem::CodeAction {
 6308                excerpt_id,
 6309                action,
 6310                provider,
 6311            } => {
 6312                let apply_code_action =
 6313                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6314                let workspace = workspace.downgrade();
 6315                Some(cx.spawn_in(window, async move |editor, cx| {
 6316                    let project_transaction = apply_code_action.await?;
 6317                    Self::open_project_transaction(
 6318                        &editor,
 6319                        workspace,
 6320                        project_transaction,
 6321                        title,
 6322                        cx,
 6323                    )
 6324                    .await
 6325                }))
 6326            }
 6327            CodeActionsItem::DebugScenario(scenario) => {
 6328                let context = actions_menu.actions.context;
 6329
 6330                workspace.update(cx, |workspace, cx| {
 6331                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6332                    workspace.start_debug_session(
 6333                        scenario,
 6334                        context,
 6335                        Some(buffer),
 6336                        None,
 6337                        window,
 6338                        cx,
 6339                    );
 6340                });
 6341                Some(Task::ready(Ok(())))
 6342            }
 6343        }
 6344    }
 6345
 6346    pub async fn open_project_transaction(
 6347        editor: &WeakEntity<Editor>,
 6348        workspace: WeakEntity<Workspace>,
 6349        transaction: ProjectTransaction,
 6350        title: String,
 6351        cx: &mut AsyncWindowContext,
 6352    ) -> Result<()> {
 6353        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6354        cx.update(|_, cx| {
 6355            entries.sort_unstable_by_key(|(buffer, _)| {
 6356                buffer.read(cx).file().map(|f| f.path().clone())
 6357            });
 6358        })?;
 6359
 6360        // If the project transaction's edits are all contained within this editor, then
 6361        // avoid opening a new editor to display them.
 6362
 6363        if let Some((buffer, transaction)) = entries.first() {
 6364            if entries.len() == 1 {
 6365                let excerpt = editor.update(cx, |editor, cx| {
 6366                    editor
 6367                        .buffer()
 6368                        .read(cx)
 6369                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6370                })?;
 6371                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6372                    && excerpted_buffer == *buffer
 6373                {
 6374                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6375                        let excerpt_range = excerpt_range.to_offset(buffer);
 6376                        buffer
 6377                            .edited_ranges_for_transaction::<usize>(transaction)
 6378                            .all(|range| {
 6379                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6380                            })
 6381                    })?;
 6382
 6383                    if all_edits_within_excerpt {
 6384                        return Ok(());
 6385                    }
 6386                }
 6387            }
 6388        } else {
 6389            return Ok(());
 6390        }
 6391
 6392        let mut ranges_to_highlight = Vec::new();
 6393        let excerpt_buffer = cx.new(|cx| {
 6394            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6395            for (buffer_handle, transaction) in &entries {
 6396                let edited_ranges = buffer_handle
 6397                    .read(cx)
 6398                    .edited_ranges_for_transaction::<Point>(transaction)
 6399                    .collect::<Vec<_>>();
 6400                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6401                    PathKey::for_buffer(buffer_handle, cx),
 6402                    buffer_handle.clone(),
 6403                    edited_ranges,
 6404                    multibuffer_context_lines(cx),
 6405                    cx,
 6406                );
 6407
 6408                ranges_to_highlight.extend(ranges);
 6409            }
 6410            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6411            multibuffer
 6412        })?;
 6413
 6414        workspace.update_in(cx, |workspace, window, cx| {
 6415            let project = workspace.project().clone();
 6416            let editor =
 6417                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6418            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6419            editor.update(cx, |editor, cx| {
 6420                editor.highlight_background::<Self>(
 6421                    &ranges_to_highlight,
 6422                    |theme| theme.colors().editor_highlighted_line_background,
 6423                    cx,
 6424                );
 6425            });
 6426        })?;
 6427
 6428        Ok(())
 6429    }
 6430
 6431    pub fn clear_code_action_providers(&mut self) {
 6432        self.code_action_providers.clear();
 6433        self.available_code_actions.take();
 6434    }
 6435
 6436    pub fn add_code_action_provider(
 6437        &mut self,
 6438        provider: Rc<dyn CodeActionProvider>,
 6439        window: &mut Window,
 6440        cx: &mut Context<Self>,
 6441    ) {
 6442        if self
 6443            .code_action_providers
 6444            .iter()
 6445            .any(|existing_provider| existing_provider.id() == provider.id())
 6446        {
 6447            return;
 6448        }
 6449
 6450        self.code_action_providers.push(provider);
 6451        self.refresh_code_actions(window, cx);
 6452    }
 6453
 6454    pub fn remove_code_action_provider(
 6455        &mut self,
 6456        id: Arc<str>,
 6457        window: &mut Window,
 6458        cx: &mut Context<Self>,
 6459    ) {
 6460        self.code_action_providers
 6461            .retain(|provider| provider.id() != id);
 6462        self.refresh_code_actions(window, cx);
 6463    }
 6464
 6465    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6466        !self.code_action_providers.is_empty()
 6467            && EditorSettings::get_global(cx).toolbar.code_actions
 6468    }
 6469
 6470    pub fn has_available_code_actions(&self) -> bool {
 6471        self.available_code_actions
 6472            .as_ref()
 6473            .is_some_and(|(_, actions)| !actions.is_empty())
 6474    }
 6475
 6476    fn render_inline_code_actions(
 6477        &self,
 6478        icon_size: ui::IconSize,
 6479        display_row: DisplayRow,
 6480        is_active: bool,
 6481        cx: &mut Context<Self>,
 6482    ) -> AnyElement {
 6483        let show_tooltip = !self.context_menu_visible();
 6484        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6485            .icon_size(icon_size)
 6486            .shape(ui::IconButtonShape::Square)
 6487            .icon_color(ui::Color::Hidden)
 6488            .toggle_state(is_active)
 6489            .when(show_tooltip, |this| {
 6490                this.tooltip({
 6491                    let focus_handle = self.focus_handle.clone();
 6492                    move |window, cx| {
 6493                        Tooltip::for_action_in(
 6494                            "Toggle Code Actions",
 6495                            &ToggleCodeActions {
 6496                                deployed_from: None,
 6497                                quick_launch: false,
 6498                            },
 6499                            &focus_handle,
 6500                            window,
 6501                            cx,
 6502                        )
 6503                    }
 6504                })
 6505            })
 6506            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6507                window.focus(&editor.focus_handle(cx));
 6508                editor.toggle_code_actions(
 6509                    &crate::actions::ToggleCodeActions {
 6510                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6511                            display_row,
 6512                        )),
 6513                        quick_launch: false,
 6514                    },
 6515                    window,
 6516                    cx,
 6517                );
 6518            }))
 6519            .into_any_element()
 6520    }
 6521
 6522    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6523        &self.context_menu
 6524    }
 6525
 6526    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6527        let newest_selection = self.selections.newest_anchor().clone();
 6528        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6529        let buffer = self.buffer.read(cx);
 6530        if newest_selection.head().diff_base_anchor.is_some() {
 6531            return None;
 6532        }
 6533        let (start_buffer, start) =
 6534            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6535        let (end_buffer, end) =
 6536            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6537        if start_buffer != end_buffer {
 6538            return None;
 6539        }
 6540
 6541        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6542            cx.background_executor()
 6543                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6544                .await;
 6545
 6546            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6547                let providers = this.code_action_providers.clone();
 6548                let tasks = this
 6549                    .code_action_providers
 6550                    .iter()
 6551                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6552                    .collect::<Vec<_>>();
 6553                (providers, tasks)
 6554            })?;
 6555
 6556            let mut actions = Vec::new();
 6557            for (provider, provider_actions) in
 6558                providers.into_iter().zip(future::join_all(tasks).await)
 6559            {
 6560                if let Some(provider_actions) = provider_actions.log_err() {
 6561                    actions.extend(provider_actions.into_iter().map(|action| {
 6562                        AvailableCodeAction {
 6563                            excerpt_id: newest_selection.start.excerpt_id,
 6564                            action,
 6565                            provider: provider.clone(),
 6566                        }
 6567                    }));
 6568                }
 6569            }
 6570
 6571            this.update(cx, |this, cx| {
 6572                this.available_code_actions = if actions.is_empty() {
 6573                    None
 6574                } else {
 6575                    Some((
 6576                        Location {
 6577                            buffer: start_buffer,
 6578                            range: start..end,
 6579                        },
 6580                        actions.into(),
 6581                    ))
 6582                };
 6583                cx.notify();
 6584            })
 6585        }));
 6586        None
 6587    }
 6588
 6589    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6590        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6591            self.show_git_blame_inline = false;
 6592
 6593            self.show_git_blame_inline_delay_task =
 6594                Some(cx.spawn_in(window, async move |this, cx| {
 6595                    cx.background_executor().timer(delay).await;
 6596
 6597                    this.update(cx, |this, cx| {
 6598                        this.show_git_blame_inline = true;
 6599                        cx.notify();
 6600                    })
 6601                    .log_err();
 6602                }));
 6603        }
 6604    }
 6605
 6606    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6607        let snapshot = self.snapshot(window, cx);
 6608        let cursor = self.selections.newest::<Point>(cx).head();
 6609        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6610        else {
 6611            return;
 6612        };
 6613
 6614        let Some(blame) = self.blame.as_ref() else {
 6615            return;
 6616        };
 6617
 6618        let row_info = RowInfo {
 6619            buffer_id: Some(buffer.remote_id()),
 6620            buffer_row: Some(point.row),
 6621            ..Default::default()
 6622        };
 6623        let Some(blame_entry) = blame
 6624            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6625            .flatten()
 6626        else {
 6627            return;
 6628        };
 6629
 6630        let anchor = self.selections.newest_anchor().head();
 6631        let position = self.to_pixel_point(anchor, &snapshot, window);
 6632        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6633            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6634        };
 6635    }
 6636
 6637    fn show_blame_popover(
 6638        &mut self,
 6639        blame_entry: &BlameEntry,
 6640        position: gpui::Point<Pixels>,
 6641        ignore_timeout: bool,
 6642        cx: &mut Context<Self>,
 6643    ) {
 6644        if let Some(state) = &mut self.inline_blame_popover {
 6645            state.hide_task.take();
 6646        } else {
 6647            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6648            let blame_entry = blame_entry.clone();
 6649            let show_task = cx.spawn(async move |editor, cx| {
 6650                if !ignore_timeout {
 6651                    cx.background_executor()
 6652                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6653                        .await;
 6654                }
 6655                editor
 6656                    .update(cx, |editor, cx| {
 6657                        editor.inline_blame_popover_show_task.take();
 6658                        let Some(blame) = editor.blame.as_ref() else {
 6659                            return;
 6660                        };
 6661                        let blame = blame.read(cx);
 6662                        let details = blame.details_for_entry(&blame_entry);
 6663                        let markdown = cx.new(|cx| {
 6664                            Markdown::new(
 6665                                details
 6666                                    .as_ref()
 6667                                    .map(|message| message.message.clone())
 6668                                    .unwrap_or_default(),
 6669                                None,
 6670                                None,
 6671                                cx,
 6672                            )
 6673                        });
 6674                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6675                            position,
 6676                            hide_task: None,
 6677                            popover_bounds: None,
 6678                            popover_state: InlineBlamePopoverState {
 6679                                scroll_handle: ScrollHandle::new(),
 6680                                commit_message: details,
 6681                                markdown,
 6682                            },
 6683                            keyboard_grace: ignore_timeout,
 6684                        });
 6685                        cx.notify();
 6686                    })
 6687                    .ok();
 6688            });
 6689            self.inline_blame_popover_show_task = Some(show_task);
 6690        }
 6691    }
 6692
 6693    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6694        self.inline_blame_popover_show_task.take();
 6695        if let Some(state) = &mut self.inline_blame_popover {
 6696            let hide_task = cx.spawn(async move |editor, cx| {
 6697                cx.background_executor()
 6698                    .timer(std::time::Duration::from_millis(100))
 6699                    .await;
 6700                editor
 6701                    .update(cx, |editor, cx| {
 6702                        editor.inline_blame_popover.take();
 6703                        cx.notify();
 6704                    })
 6705                    .ok();
 6706            });
 6707            state.hide_task = Some(hide_task);
 6708        }
 6709    }
 6710
 6711    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6712        if self.pending_rename.is_some() {
 6713            return None;
 6714        }
 6715
 6716        let provider = self.semantics_provider.clone()?;
 6717        let buffer = self.buffer.read(cx);
 6718        let newest_selection = self.selections.newest_anchor().clone();
 6719        let cursor_position = newest_selection.head();
 6720        let (cursor_buffer, cursor_buffer_position) =
 6721            buffer.text_anchor_for_position(cursor_position, cx)?;
 6722        let (tail_buffer, tail_buffer_position) =
 6723            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6724        if cursor_buffer != tail_buffer {
 6725            return None;
 6726        }
 6727
 6728        let snapshot = cursor_buffer.read(cx).snapshot();
 6729        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6730        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6731        if start_word_range != end_word_range {
 6732            self.document_highlights_task.take();
 6733            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6734            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6735            return None;
 6736        }
 6737
 6738        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6739        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6740            cx.background_executor()
 6741                .timer(Duration::from_millis(debounce))
 6742                .await;
 6743
 6744            let highlights = if let Some(highlights) = cx
 6745                .update(|cx| {
 6746                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6747                })
 6748                .ok()
 6749                .flatten()
 6750            {
 6751                highlights.await.log_err()
 6752            } else {
 6753                None
 6754            };
 6755
 6756            if let Some(highlights) = highlights {
 6757                this.update(cx, |this, cx| {
 6758                    if this.pending_rename.is_some() {
 6759                        return;
 6760                    }
 6761
 6762                    let buffer = this.buffer.read(cx);
 6763                    if buffer
 6764                        .text_anchor_for_position(cursor_position, cx)
 6765                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6766                    {
 6767                        return;
 6768                    }
 6769
 6770                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6771                    let mut write_ranges = Vec::new();
 6772                    let mut read_ranges = Vec::new();
 6773                    for highlight in highlights {
 6774                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6775                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6776                        {
 6777                            let start = highlight
 6778                                .range
 6779                                .start
 6780                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6781                            let end = highlight
 6782                                .range
 6783                                .end
 6784                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6785                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6786                                continue;
 6787                            }
 6788
 6789                            let range = Anchor {
 6790                                buffer_id: Some(buffer_id),
 6791                                excerpt_id,
 6792                                text_anchor: start,
 6793                                diff_base_anchor: None,
 6794                            }..Anchor {
 6795                                buffer_id: Some(buffer_id),
 6796                                excerpt_id,
 6797                                text_anchor: end,
 6798                                diff_base_anchor: None,
 6799                            };
 6800                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6801                                write_ranges.push(range);
 6802                            } else {
 6803                                read_ranges.push(range);
 6804                            }
 6805                        }
 6806                    }
 6807
 6808                    this.highlight_background::<DocumentHighlightRead>(
 6809                        &read_ranges,
 6810                        |theme| theme.colors().editor_document_highlight_read_background,
 6811                        cx,
 6812                    );
 6813                    this.highlight_background::<DocumentHighlightWrite>(
 6814                        &write_ranges,
 6815                        |theme| theme.colors().editor_document_highlight_write_background,
 6816                        cx,
 6817                    );
 6818                    cx.notify();
 6819                })
 6820                .log_err();
 6821            }
 6822        }));
 6823        None
 6824    }
 6825
 6826    fn prepare_highlight_query_from_selection(
 6827        &mut self,
 6828        cx: &mut Context<Editor>,
 6829    ) -> Option<(String, Range<Anchor>)> {
 6830        if matches!(self.mode, EditorMode::SingleLine) {
 6831            return None;
 6832        }
 6833        if !EditorSettings::get_global(cx).selection_highlight {
 6834            return None;
 6835        }
 6836        if self.selections.count() != 1 || self.selections.line_mode {
 6837            return None;
 6838        }
 6839        let selection = self.selections.newest::<Point>(cx);
 6840        if selection.is_empty() || selection.start.row != selection.end.row {
 6841            return None;
 6842        }
 6843        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6844        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6845        let query = multi_buffer_snapshot
 6846            .text_for_range(selection_anchor_range.clone())
 6847            .collect::<String>();
 6848        if query.trim().is_empty() {
 6849            return None;
 6850        }
 6851        Some((query, selection_anchor_range))
 6852    }
 6853
 6854    fn update_selection_occurrence_highlights(
 6855        &mut self,
 6856        query_text: String,
 6857        query_range: Range<Anchor>,
 6858        multi_buffer_range_to_query: Range<Point>,
 6859        use_debounce: bool,
 6860        window: &mut Window,
 6861        cx: &mut Context<Editor>,
 6862    ) -> Task<()> {
 6863        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6864        cx.spawn_in(window, async move |editor, cx| {
 6865            if use_debounce {
 6866                cx.background_executor()
 6867                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6868                    .await;
 6869            }
 6870            let match_task = cx.background_spawn(async move {
 6871                let buffer_ranges = multi_buffer_snapshot
 6872                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6873                    .into_iter()
 6874                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6875                let mut match_ranges = Vec::new();
 6876                let Ok(regex) = project::search::SearchQuery::text(
 6877                    query_text.clone(),
 6878                    false,
 6879                    false,
 6880                    false,
 6881                    Default::default(),
 6882                    Default::default(),
 6883                    false,
 6884                    None,
 6885                ) else {
 6886                    return Vec::default();
 6887                };
 6888                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6889                    match_ranges.extend(
 6890                        regex
 6891                            .search(buffer_snapshot, Some(search_range.clone()))
 6892                            .await
 6893                            .into_iter()
 6894                            .filter_map(|match_range| {
 6895                                let match_start = buffer_snapshot
 6896                                    .anchor_after(search_range.start + match_range.start);
 6897                                let match_end = buffer_snapshot
 6898                                    .anchor_before(search_range.start + match_range.end);
 6899                                let match_anchor_range = Anchor::range_in_buffer(
 6900                                    excerpt_id,
 6901                                    buffer_snapshot.remote_id(),
 6902                                    match_start..match_end,
 6903                                );
 6904                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6905                            }),
 6906                    );
 6907                }
 6908                match_ranges
 6909            });
 6910            let match_ranges = match_task.await;
 6911            editor
 6912                .update_in(cx, |editor, _, cx| {
 6913                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6914                    if !match_ranges.is_empty() {
 6915                        editor.highlight_background::<SelectedTextHighlight>(
 6916                            &match_ranges,
 6917                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6918                            cx,
 6919                        )
 6920                    }
 6921                })
 6922                .log_err();
 6923        })
 6924    }
 6925
 6926    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6927        struct NewlineFold;
 6928        let type_id = std::any::TypeId::of::<NewlineFold>();
 6929        if !self.mode.is_single_line() {
 6930            return;
 6931        }
 6932        let snapshot = self.snapshot(window, cx);
 6933        if snapshot.buffer_snapshot.max_point().row == 0 {
 6934            return;
 6935        }
 6936        let task = cx.background_spawn(async move {
 6937            let new_newlines = snapshot
 6938                .buffer_chars_at(0)
 6939                .filter_map(|(c, i)| {
 6940                    if c == '\n' {
 6941                        Some(
 6942                            snapshot.buffer_snapshot.anchor_after(i)
 6943                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6944                        )
 6945                    } else {
 6946                        None
 6947                    }
 6948                })
 6949                .collect::<Vec<_>>();
 6950            let existing_newlines = snapshot
 6951                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6952                .filter_map(|fold| {
 6953                    if fold.placeholder.type_tag == Some(type_id) {
 6954                        Some(fold.range.start..fold.range.end)
 6955                    } else {
 6956                        None
 6957                    }
 6958                })
 6959                .collect::<Vec<_>>();
 6960
 6961            (new_newlines, existing_newlines)
 6962        });
 6963        self.folding_newlines = cx.spawn(async move |this, cx| {
 6964            let (new_newlines, existing_newlines) = task.await;
 6965            if new_newlines == existing_newlines {
 6966                return;
 6967            }
 6968            let placeholder = FoldPlaceholder {
 6969                render: Arc::new(move |_, _, cx| {
 6970                    div()
 6971                        .bg(cx.theme().status().hint_background)
 6972                        .border_b_1()
 6973                        .size_full()
 6974                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6975                        .border_color(cx.theme().status().hint)
 6976                        .child("\\n")
 6977                        .into_any()
 6978                }),
 6979                constrain_width: false,
 6980                merge_adjacent: false,
 6981                type_tag: Some(type_id),
 6982            };
 6983            let creases = new_newlines
 6984                .into_iter()
 6985                .map(|range| Crease::simple(range, placeholder.clone()))
 6986                .collect();
 6987            this.update(cx, |this, cx| {
 6988                this.display_map.update(cx, |display_map, cx| {
 6989                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6990                    display_map.fold(creases, cx);
 6991                });
 6992            })
 6993            .ok();
 6994        });
 6995    }
 6996
 6997    fn refresh_selected_text_highlights(
 6998        &mut self,
 6999        on_buffer_edit: bool,
 7000        window: &mut Window,
 7001        cx: &mut Context<Editor>,
 7002    ) {
 7003        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7004        else {
 7005            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7006            self.quick_selection_highlight_task.take();
 7007            self.debounced_selection_highlight_task.take();
 7008            return;
 7009        };
 7010        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7011        if on_buffer_edit
 7012            || self
 7013                .quick_selection_highlight_task
 7014                .as_ref()
 7015                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7016        {
 7017            let multi_buffer_visible_start = self
 7018                .scroll_manager
 7019                .anchor()
 7020                .anchor
 7021                .to_point(&multi_buffer_snapshot);
 7022            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7023                multi_buffer_visible_start
 7024                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7025                Bias::Left,
 7026            );
 7027            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7028            self.quick_selection_highlight_task = Some((
 7029                query_range.clone(),
 7030                self.update_selection_occurrence_highlights(
 7031                    query_text.clone(),
 7032                    query_range.clone(),
 7033                    multi_buffer_visible_range,
 7034                    false,
 7035                    window,
 7036                    cx,
 7037                ),
 7038            ));
 7039        }
 7040        if on_buffer_edit
 7041            || self
 7042                .debounced_selection_highlight_task
 7043                .as_ref()
 7044                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7045        {
 7046            let multi_buffer_start = multi_buffer_snapshot
 7047                .anchor_before(0)
 7048                .to_point(&multi_buffer_snapshot);
 7049            let multi_buffer_end = multi_buffer_snapshot
 7050                .anchor_after(multi_buffer_snapshot.len())
 7051                .to_point(&multi_buffer_snapshot);
 7052            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7053            self.debounced_selection_highlight_task = Some((
 7054                query_range.clone(),
 7055                self.update_selection_occurrence_highlights(
 7056                    query_text,
 7057                    query_range,
 7058                    multi_buffer_full_range,
 7059                    true,
 7060                    window,
 7061                    cx,
 7062                ),
 7063            ));
 7064        }
 7065    }
 7066
 7067    pub fn refresh_edit_prediction(
 7068        &mut self,
 7069        debounce: bool,
 7070        user_requested: bool,
 7071        window: &mut Window,
 7072        cx: &mut Context<Self>,
 7073    ) -> Option<()> {
 7074        if DisableAiSettings::get_global(cx).disable_ai {
 7075            return None;
 7076        }
 7077
 7078        let provider = self.edit_prediction_provider()?;
 7079        let cursor = self.selections.newest_anchor().head();
 7080        let (buffer, cursor_buffer_position) =
 7081            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7082
 7083        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7084            self.discard_edit_prediction(false, cx);
 7085            return None;
 7086        }
 7087
 7088        if !user_requested
 7089            && (!self.should_show_edit_predictions()
 7090                || !self.is_focused(window)
 7091                || buffer.read(cx).is_empty())
 7092        {
 7093            self.discard_edit_prediction(false, cx);
 7094            return None;
 7095        }
 7096
 7097        self.update_visible_edit_prediction(window, cx);
 7098        provider.refresh(
 7099            self.project.clone(),
 7100            buffer,
 7101            cursor_buffer_position,
 7102            debounce,
 7103            cx,
 7104        );
 7105        Some(())
 7106    }
 7107
 7108    fn show_edit_predictions_in_menu(&self) -> bool {
 7109        match self.edit_prediction_settings {
 7110            EditPredictionSettings::Disabled => false,
 7111            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7112        }
 7113    }
 7114
 7115    pub fn edit_predictions_enabled(&self) -> bool {
 7116        match self.edit_prediction_settings {
 7117            EditPredictionSettings::Disabled => false,
 7118            EditPredictionSettings::Enabled { .. } => true,
 7119        }
 7120    }
 7121
 7122    fn edit_prediction_requires_modifier(&self) -> bool {
 7123        match self.edit_prediction_settings {
 7124            EditPredictionSettings::Disabled => false,
 7125            EditPredictionSettings::Enabled {
 7126                preview_requires_modifier,
 7127                ..
 7128            } => preview_requires_modifier,
 7129        }
 7130    }
 7131
 7132    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7133        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7134            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7135            self.discard_edit_prediction(false, cx);
 7136        } else {
 7137            let selection = self.selections.newest_anchor();
 7138            let cursor = selection.head();
 7139
 7140            if let Some((buffer, cursor_buffer_position)) =
 7141                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7142            {
 7143                self.edit_prediction_settings =
 7144                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7145            }
 7146        }
 7147    }
 7148
 7149    fn edit_prediction_settings_at_position(
 7150        &self,
 7151        buffer: &Entity<Buffer>,
 7152        buffer_position: language::Anchor,
 7153        cx: &App,
 7154    ) -> EditPredictionSettings {
 7155        if !self.mode.is_full()
 7156            || !self.show_edit_predictions_override.unwrap_or(true)
 7157            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7158        {
 7159            return EditPredictionSettings::Disabled;
 7160        }
 7161
 7162        let buffer = buffer.read(cx);
 7163
 7164        let file = buffer.file();
 7165
 7166        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7167            return EditPredictionSettings::Disabled;
 7168        };
 7169
 7170        let by_provider = matches!(
 7171            self.menu_edit_predictions_policy,
 7172            MenuEditPredictionsPolicy::ByProvider
 7173        );
 7174
 7175        let show_in_menu = by_provider
 7176            && self
 7177                .edit_prediction_provider
 7178                .as_ref()
 7179                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7180
 7181        let preview_requires_modifier =
 7182            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7183
 7184        EditPredictionSettings::Enabled {
 7185            show_in_menu,
 7186            preview_requires_modifier,
 7187        }
 7188    }
 7189
 7190    fn should_show_edit_predictions(&self) -> bool {
 7191        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7192    }
 7193
 7194    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7195        matches!(
 7196            self.edit_prediction_preview,
 7197            EditPredictionPreview::Active { .. }
 7198        )
 7199    }
 7200
 7201    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7202        let cursor = self.selections.newest_anchor().head();
 7203        if let Some((buffer, cursor_position)) =
 7204            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7205        {
 7206            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7207        } else {
 7208            false
 7209        }
 7210    }
 7211
 7212    pub fn supports_minimap(&self, cx: &App) -> bool {
 7213        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7214    }
 7215
 7216    fn edit_predictions_enabled_in_buffer(
 7217        &self,
 7218        buffer: &Entity<Buffer>,
 7219        buffer_position: language::Anchor,
 7220        cx: &App,
 7221    ) -> bool {
 7222        maybe!({
 7223            if self.read_only(cx) {
 7224                return Some(false);
 7225            }
 7226            let provider = self.edit_prediction_provider()?;
 7227            if !provider.is_enabled(buffer, buffer_position, cx) {
 7228                return Some(false);
 7229            }
 7230            let buffer = buffer.read(cx);
 7231            let Some(file) = buffer.file() else {
 7232                return Some(true);
 7233            };
 7234            let settings = all_language_settings(Some(file), cx);
 7235            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7236        })
 7237        .unwrap_or(false)
 7238    }
 7239
 7240    fn cycle_edit_prediction(
 7241        &mut self,
 7242        direction: Direction,
 7243        window: &mut Window,
 7244        cx: &mut Context<Self>,
 7245    ) -> Option<()> {
 7246        let provider = self.edit_prediction_provider()?;
 7247        let cursor = self.selections.newest_anchor().head();
 7248        let (buffer, cursor_buffer_position) =
 7249            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7250        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7251            return None;
 7252        }
 7253
 7254        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7255        self.update_visible_edit_prediction(window, cx);
 7256
 7257        Some(())
 7258    }
 7259
 7260    pub fn show_edit_prediction(
 7261        &mut self,
 7262        _: &ShowEditPrediction,
 7263        window: &mut Window,
 7264        cx: &mut Context<Self>,
 7265    ) {
 7266        if !self.has_active_edit_prediction() {
 7267            self.refresh_edit_prediction(false, true, window, cx);
 7268            return;
 7269        }
 7270
 7271        self.update_visible_edit_prediction(window, cx);
 7272    }
 7273
 7274    pub fn display_cursor_names(
 7275        &mut self,
 7276        _: &DisplayCursorNames,
 7277        window: &mut Window,
 7278        cx: &mut Context<Self>,
 7279    ) {
 7280        self.show_cursor_names(window, cx);
 7281    }
 7282
 7283    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7284        self.show_cursor_names = true;
 7285        cx.notify();
 7286        cx.spawn_in(window, async move |this, cx| {
 7287            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7288            this.update(cx, |this, cx| {
 7289                this.show_cursor_names = false;
 7290                cx.notify()
 7291            })
 7292            .ok()
 7293        })
 7294        .detach();
 7295    }
 7296
 7297    pub fn next_edit_prediction(
 7298        &mut self,
 7299        _: &NextEditPrediction,
 7300        window: &mut Window,
 7301        cx: &mut Context<Self>,
 7302    ) {
 7303        if self.has_active_edit_prediction() {
 7304            self.cycle_edit_prediction(Direction::Next, window, cx);
 7305        } else {
 7306            let is_copilot_disabled = self
 7307                .refresh_edit_prediction(false, true, window, cx)
 7308                .is_none();
 7309            if is_copilot_disabled {
 7310                cx.propagate();
 7311            }
 7312        }
 7313    }
 7314
 7315    pub fn previous_edit_prediction(
 7316        &mut self,
 7317        _: &PreviousEditPrediction,
 7318        window: &mut Window,
 7319        cx: &mut Context<Self>,
 7320    ) {
 7321        if self.has_active_edit_prediction() {
 7322            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7323        } else {
 7324            let is_copilot_disabled = self
 7325                .refresh_edit_prediction(false, true, window, cx)
 7326                .is_none();
 7327            if is_copilot_disabled {
 7328                cx.propagate();
 7329            }
 7330        }
 7331    }
 7332
 7333    pub fn accept_edit_prediction(
 7334        &mut self,
 7335        _: &AcceptEditPrediction,
 7336        window: &mut Window,
 7337        cx: &mut Context<Self>,
 7338    ) {
 7339        if self.show_edit_predictions_in_menu() {
 7340            self.hide_context_menu(window, cx);
 7341        }
 7342
 7343        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7344            return;
 7345        };
 7346
 7347        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7348
 7349        match &active_edit_prediction.completion {
 7350            EditPrediction::Move { target, .. } => {
 7351                let target = *target;
 7352
 7353                if let Some(position_map) = &self.last_position_map {
 7354                    if position_map
 7355                        .visible_row_range
 7356                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7357                        || !self.edit_prediction_requires_modifier()
 7358                    {
 7359                        self.unfold_ranges(&[target..target], true, false, cx);
 7360                        // Note that this is also done in vim's handler of the Tab action.
 7361                        self.change_selections(
 7362                            SelectionEffects::scroll(Autoscroll::newest()),
 7363                            window,
 7364                            cx,
 7365                            |selections| {
 7366                                selections.select_anchor_ranges([target..target]);
 7367                            },
 7368                        );
 7369                        self.clear_row_highlights::<EditPredictionPreview>();
 7370
 7371                        self.edit_prediction_preview
 7372                            .set_previous_scroll_position(None);
 7373                    } else {
 7374                        self.edit_prediction_preview
 7375                            .set_previous_scroll_position(Some(
 7376                                position_map.snapshot.scroll_anchor,
 7377                            ));
 7378
 7379                        self.highlight_rows::<EditPredictionPreview>(
 7380                            target..target,
 7381                            cx.theme().colors().editor_highlighted_line_background,
 7382                            RowHighlightOptions {
 7383                                autoscroll: true,
 7384                                ..Default::default()
 7385                            },
 7386                            cx,
 7387                        );
 7388                        self.request_autoscroll(Autoscroll::fit(), cx);
 7389                    }
 7390                }
 7391            }
 7392            EditPrediction::Edit { edits, .. } => {
 7393                if let Some(provider) = self.edit_prediction_provider() {
 7394                    provider.accept(cx);
 7395                }
 7396
 7397                // Store the transaction ID and selections before applying the edit
 7398                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7399
 7400                let snapshot = self.buffer.read(cx).snapshot(cx);
 7401                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7402
 7403                self.buffer.update(cx, |buffer, cx| {
 7404                    buffer.edit(edits.iter().cloned(), None, cx)
 7405                });
 7406
 7407                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7408                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7409                });
 7410
 7411                let selections = self.selections.disjoint_anchors();
 7412                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7413                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7414                    if has_new_transaction {
 7415                        self.selection_history
 7416                            .insert_transaction(transaction_id_now, selections);
 7417                    }
 7418                }
 7419
 7420                self.update_visible_edit_prediction(window, cx);
 7421                if self.active_edit_prediction.is_none() {
 7422                    self.refresh_edit_prediction(true, true, window, cx);
 7423                }
 7424
 7425                cx.notify();
 7426            }
 7427        }
 7428
 7429        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7430    }
 7431
 7432    pub fn accept_partial_edit_prediction(
 7433        &mut self,
 7434        _: &AcceptPartialEditPrediction,
 7435        window: &mut Window,
 7436        cx: &mut Context<Self>,
 7437    ) {
 7438        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7439            return;
 7440        };
 7441        if self.selections.count() != 1 {
 7442            return;
 7443        }
 7444
 7445        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7446
 7447        match &active_edit_prediction.completion {
 7448            EditPrediction::Move { target, .. } => {
 7449                let target = *target;
 7450                self.change_selections(
 7451                    SelectionEffects::scroll(Autoscroll::newest()),
 7452                    window,
 7453                    cx,
 7454                    |selections| {
 7455                        selections.select_anchor_ranges([target..target]);
 7456                    },
 7457                );
 7458            }
 7459            EditPrediction::Edit { edits, .. } => {
 7460                // Find an insertion that starts at the cursor position.
 7461                let snapshot = self.buffer.read(cx).snapshot(cx);
 7462                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7463                let insertion = edits.iter().find_map(|(range, text)| {
 7464                    let range = range.to_offset(&snapshot);
 7465                    if range.is_empty() && range.start == cursor_offset {
 7466                        Some(text)
 7467                    } else {
 7468                        None
 7469                    }
 7470                });
 7471
 7472                if let Some(text) = insertion {
 7473                    let mut partial_completion = text
 7474                        .chars()
 7475                        .by_ref()
 7476                        .take_while(|c| c.is_alphabetic())
 7477                        .collect::<String>();
 7478                    if partial_completion.is_empty() {
 7479                        partial_completion = text
 7480                            .chars()
 7481                            .by_ref()
 7482                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7483                            .collect::<String>();
 7484                    }
 7485
 7486                    cx.emit(EditorEvent::InputHandled {
 7487                        utf16_range_to_replace: None,
 7488                        text: partial_completion.clone().into(),
 7489                    });
 7490
 7491                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7492
 7493                    self.refresh_edit_prediction(true, true, window, cx);
 7494                    cx.notify();
 7495                } else {
 7496                    self.accept_edit_prediction(&Default::default(), window, cx);
 7497                }
 7498            }
 7499        }
 7500    }
 7501
 7502    fn discard_edit_prediction(
 7503        &mut self,
 7504        should_report_edit_prediction_event: bool,
 7505        cx: &mut Context<Self>,
 7506    ) -> bool {
 7507        if should_report_edit_prediction_event {
 7508            let completion_id = self
 7509                .active_edit_prediction
 7510                .as_ref()
 7511                .and_then(|active_completion| active_completion.completion_id.clone());
 7512
 7513            self.report_edit_prediction_event(completion_id, false, cx);
 7514        }
 7515
 7516        if let Some(provider) = self.edit_prediction_provider() {
 7517            provider.discard(cx);
 7518        }
 7519
 7520        self.take_active_edit_prediction(cx)
 7521    }
 7522
 7523    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7524        let Some(provider) = self.edit_prediction_provider() else {
 7525            return;
 7526        };
 7527
 7528        let Some((_, buffer, _)) = self
 7529            .buffer
 7530            .read(cx)
 7531            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7532        else {
 7533            return;
 7534        };
 7535
 7536        let extension = buffer
 7537            .read(cx)
 7538            .file()
 7539            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7540
 7541        let event_type = match accepted {
 7542            true => "Edit Prediction Accepted",
 7543            false => "Edit Prediction Discarded",
 7544        };
 7545        telemetry::event!(
 7546            event_type,
 7547            provider = provider.name(),
 7548            prediction_id = id,
 7549            suggestion_accepted = accepted,
 7550            file_extension = extension,
 7551        );
 7552    }
 7553
 7554    pub fn has_active_edit_prediction(&self) -> bool {
 7555        self.active_edit_prediction.is_some()
 7556    }
 7557
 7558    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7559        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7560            return false;
 7561        };
 7562
 7563        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7564        self.clear_highlights::<EditPredictionHighlight>(cx);
 7565        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7566        true
 7567    }
 7568
 7569    /// Returns true when we're displaying the edit prediction popover below the cursor
 7570    /// like we are not previewing and the LSP autocomplete menu is visible
 7571    /// or we are in `when_holding_modifier` mode.
 7572    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7573        if self.edit_prediction_preview_is_active()
 7574            || !self.show_edit_predictions_in_menu()
 7575            || !self.edit_predictions_enabled()
 7576        {
 7577            return false;
 7578        }
 7579
 7580        if self.has_visible_completions_menu() {
 7581            return true;
 7582        }
 7583
 7584        has_completion && self.edit_prediction_requires_modifier()
 7585    }
 7586
 7587    fn handle_modifiers_changed(
 7588        &mut self,
 7589        modifiers: Modifiers,
 7590        position_map: &PositionMap,
 7591        window: &mut Window,
 7592        cx: &mut Context<Self>,
 7593    ) {
 7594        if self.show_edit_predictions_in_menu() {
 7595            self.update_edit_prediction_preview(&modifiers, window, cx);
 7596        }
 7597
 7598        self.update_selection_mode(&modifiers, position_map, window, cx);
 7599
 7600        let mouse_position = window.mouse_position();
 7601        if !position_map.text_hitbox.is_hovered(window) {
 7602            return;
 7603        }
 7604
 7605        self.update_hovered_link(
 7606            position_map.point_for_position(mouse_position),
 7607            &position_map.snapshot,
 7608            modifiers,
 7609            window,
 7610            cx,
 7611        )
 7612    }
 7613
 7614    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7615        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7616        if invert {
 7617            match multi_cursor_setting {
 7618                MultiCursorModifier::Alt => modifiers.alt,
 7619                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7620            }
 7621        } else {
 7622            match multi_cursor_setting {
 7623                MultiCursorModifier::Alt => modifiers.secondary(),
 7624                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7625            }
 7626        }
 7627    }
 7628
 7629    fn columnar_selection_mode(
 7630        modifiers: &Modifiers,
 7631        cx: &mut Context<Self>,
 7632    ) -> Option<ColumnarMode> {
 7633        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7634            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7635                Some(ColumnarMode::FromMouse)
 7636            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7637                Some(ColumnarMode::FromSelection)
 7638            } else {
 7639                None
 7640            }
 7641        } else {
 7642            None
 7643        }
 7644    }
 7645
 7646    fn update_selection_mode(
 7647        &mut self,
 7648        modifiers: &Modifiers,
 7649        position_map: &PositionMap,
 7650        window: &mut Window,
 7651        cx: &mut Context<Self>,
 7652    ) {
 7653        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7654            return;
 7655        };
 7656        if self.selections.pending.is_none() {
 7657            return;
 7658        }
 7659
 7660        let mouse_position = window.mouse_position();
 7661        let point_for_position = position_map.point_for_position(mouse_position);
 7662        let position = point_for_position.previous_valid;
 7663
 7664        self.select(
 7665            SelectPhase::BeginColumnar {
 7666                position,
 7667                reset: false,
 7668                mode,
 7669                goal_column: point_for_position.exact_unclipped.column(),
 7670            },
 7671            window,
 7672            cx,
 7673        );
 7674    }
 7675
 7676    fn update_edit_prediction_preview(
 7677        &mut self,
 7678        modifiers: &Modifiers,
 7679        window: &mut Window,
 7680        cx: &mut Context<Self>,
 7681    ) {
 7682        let mut modifiers_held = false;
 7683        if let Some(accept_keystroke) = self
 7684            .accept_edit_prediction_keybind(false, window, cx)
 7685            .keystroke()
 7686        {
 7687            modifiers_held = modifiers_held
 7688                || (accept_keystroke.modifiers() == modifiers
 7689                    && accept_keystroke.modifiers().modified());
 7690        };
 7691        if let Some(accept_partial_keystroke) = self
 7692            .accept_edit_prediction_keybind(true, window, cx)
 7693            .keystroke()
 7694        {
 7695            modifiers_held = modifiers_held
 7696                || (accept_partial_keystroke.modifiers() == modifiers
 7697                    && accept_partial_keystroke.modifiers().modified());
 7698        }
 7699
 7700        if modifiers_held {
 7701            if matches!(
 7702                self.edit_prediction_preview,
 7703                EditPredictionPreview::Inactive { .. }
 7704            ) {
 7705                self.edit_prediction_preview = EditPredictionPreview::Active {
 7706                    previous_scroll_position: None,
 7707                    since: Instant::now(),
 7708                };
 7709
 7710                self.update_visible_edit_prediction(window, cx);
 7711                cx.notify();
 7712            }
 7713        } else if let EditPredictionPreview::Active {
 7714            previous_scroll_position,
 7715            since,
 7716        } = self.edit_prediction_preview
 7717        {
 7718            if let (Some(previous_scroll_position), Some(position_map)) =
 7719                (previous_scroll_position, self.last_position_map.as_ref())
 7720            {
 7721                self.set_scroll_position(
 7722                    previous_scroll_position
 7723                        .scroll_position(&position_map.snapshot.display_snapshot),
 7724                    window,
 7725                    cx,
 7726                );
 7727            }
 7728
 7729            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7730                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7731            };
 7732            self.clear_row_highlights::<EditPredictionPreview>();
 7733            self.update_visible_edit_prediction(window, cx);
 7734            cx.notify();
 7735        }
 7736    }
 7737
 7738    fn update_visible_edit_prediction(
 7739        &mut self,
 7740        _window: &mut Window,
 7741        cx: &mut Context<Self>,
 7742    ) -> Option<()> {
 7743        if DisableAiSettings::get_global(cx).disable_ai {
 7744            return None;
 7745        }
 7746
 7747        let selection = self.selections.newest_anchor();
 7748        let cursor = selection.head();
 7749        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7750        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7751        let excerpt_id = cursor.excerpt_id;
 7752
 7753        let show_in_menu = self.show_edit_predictions_in_menu();
 7754        let completions_menu_has_precedence = !show_in_menu
 7755            && (self.context_menu.borrow().is_some()
 7756                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7757
 7758        if completions_menu_has_precedence
 7759            || !offset_selection.is_empty()
 7760            || self
 7761                .active_edit_prediction
 7762                .as_ref()
 7763                .is_some_and(|completion| {
 7764                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7765                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7766                    !invalidation_range.contains(&offset_selection.head())
 7767                })
 7768        {
 7769            self.discard_edit_prediction(false, cx);
 7770            return None;
 7771        }
 7772
 7773        self.take_active_edit_prediction(cx);
 7774        let Some(provider) = self.edit_prediction_provider() else {
 7775            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7776            return None;
 7777        };
 7778
 7779        let (buffer, cursor_buffer_position) =
 7780            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7781
 7782        self.edit_prediction_settings =
 7783            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7784
 7785        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7786            self.discard_edit_prediction(false, cx);
 7787            return None;
 7788        };
 7789
 7790        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7791
 7792        if self.edit_prediction_indent_conflict {
 7793            let cursor_point = cursor.to_point(&multibuffer);
 7794
 7795            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7796
 7797            if let Some((_, indent)) = indents.iter().next()
 7798                && indent.len == cursor_point.column
 7799            {
 7800                self.edit_prediction_indent_conflict = false;
 7801            }
 7802        }
 7803
 7804        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7805        let edits = edit_prediction
 7806            .edits
 7807            .into_iter()
 7808            .flat_map(|(range, new_text)| {
 7809                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7810                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7811                Some((start..end, new_text))
 7812            })
 7813            .collect::<Vec<_>>();
 7814        if edits.is_empty() {
 7815            return None;
 7816        }
 7817
 7818        let first_edit_start = edits.first().unwrap().0.start;
 7819        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7820        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7821
 7822        let last_edit_end = edits.last().unwrap().0.end;
 7823        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7824        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7825
 7826        let cursor_row = cursor.to_point(&multibuffer).row;
 7827
 7828        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7829
 7830        let mut inlay_ids = Vec::new();
 7831        let invalidation_row_range;
 7832        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7833            Some(cursor_row..edit_end_row)
 7834        } else if cursor_row > edit_end_row {
 7835            Some(edit_start_row..cursor_row)
 7836        } else {
 7837            None
 7838        };
 7839        let supports_jump = self
 7840            .edit_prediction_provider
 7841            .as_ref()
 7842            .map(|provider| provider.provider.supports_jump_to_edit())
 7843            .unwrap_or(true);
 7844
 7845        let is_move = supports_jump
 7846            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7847        let completion = if is_move {
 7848            invalidation_row_range =
 7849                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7850            let target = first_edit_start;
 7851            EditPrediction::Move { target, snapshot }
 7852        } else {
 7853            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7854                && !self.edit_predictions_hidden_for_vim_mode;
 7855
 7856            if show_completions_in_buffer {
 7857                if edits
 7858                    .iter()
 7859                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7860                {
 7861                    let mut inlays = Vec::new();
 7862                    for (range, new_text) in &edits {
 7863                        let inlay = Inlay::edit_prediction(
 7864                            post_inc(&mut self.next_inlay_id),
 7865                            range.start,
 7866                            new_text.as_str(),
 7867                        );
 7868                        inlay_ids.push(inlay.id);
 7869                        inlays.push(inlay);
 7870                    }
 7871
 7872                    self.splice_inlays(&[], inlays, cx);
 7873                } else {
 7874                    let background_color = cx.theme().status().deleted_background;
 7875                    self.highlight_text::<EditPredictionHighlight>(
 7876                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7877                        HighlightStyle {
 7878                            background_color: Some(background_color),
 7879                            ..Default::default()
 7880                        },
 7881                        cx,
 7882                    );
 7883                }
 7884            }
 7885
 7886            invalidation_row_range = edit_start_row..edit_end_row;
 7887
 7888            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7889                if provider.show_tab_accept_marker() {
 7890                    EditDisplayMode::TabAccept
 7891                } else {
 7892                    EditDisplayMode::Inline
 7893                }
 7894            } else {
 7895                EditDisplayMode::DiffPopover
 7896            };
 7897
 7898            EditPrediction::Edit {
 7899                edits,
 7900                edit_preview: edit_prediction.edit_preview,
 7901                display_mode,
 7902                snapshot,
 7903            }
 7904        };
 7905
 7906        let invalidation_range = multibuffer
 7907            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7908            ..multibuffer.anchor_after(Point::new(
 7909                invalidation_row_range.end,
 7910                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7911            ));
 7912
 7913        self.stale_edit_prediction_in_menu = None;
 7914        self.active_edit_prediction = Some(EditPredictionState {
 7915            inlay_ids,
 7916            completion,
 7917            completion_id: edit_prediction.id,
 7918            invalidation_range,
 7919        });
 7920
 7921        cx.notify();
 7922
 7923        Some(())
 7924    }
 7925
 7926    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7927        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7928    }
 7929
 7930    fn clear_tasks(&mut self) {
 7931        self.tasks.clear()
 7932    }
 7933
 7934    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7935        if self.tasks.insert(key, value).is_some() {
 7936            // This case should hopefully be rare, but just in case...
 7937            log::error!(
 7938                "multiple different run targets found on a single line, only the last target will be rendered"
 7939            )
 7940        }
 7941    }
 7942
 7943    /// Get all display points of breakpoints that will be rendered within editor
 7944    ///
 7945    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7946    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7947    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7948    fn active_breakpoints(
 7949        &self,
 7950        range: Range<DisplayRow>,
 7951        window: &mut Window,
 7952        cx: &mut Context<Self>,
 7953    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7954        let mut breakpoint_display_points = HashMap::default();
 7955
 7956        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7957            return breakpoint_display_points;
 7958        };
 7959
 7960        let snapshot = self.snapshot(window, cx);
 7961
 7962        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7963        let Some(project) = self.project() else {
 7964            return breakpoint_display_points;
 7965        };
 7966
 7967        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7968            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7969
 7970        for (buffer_snapshot, range, excerpt_id) in
 7971            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7972        {
 7973            let Some(buffer) = project
 7974                .read(cx)
 7975                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7976            else {
 7977                continue;
 7978            };
 7979            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7980                &buffer,
 7981                Some(
 7982                    buffer_snapshot.anchor_before(range.start)
 7983                        ..buffer_snapshot.anchor_after(range.end),
 7984                ),
 7985                buffer_snapshot,
 7986                cx,
 7987            );
 7988            for (breakpoint, state) in breakpoints {
 7989                let multi_buffer_anchor =
 7990                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7991                let position = multi_buffer_anchor
 7992                    .to_point(multi_buffer_snapshot)
 7993                    .to_display_point(&snapshot);
 7994
 7995                breakpoint_display_points.insert(
 7996                    position.row(),
 7997                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7998                );
 7999            }
 8000        }
 8001
 8002        breakpoint_display_points
 8003    }
 8004
 8005    fn breakpoint_context_menu(
 8006        &self,
 8007        anchor: Anchor,
 8008        window: &mut Window,
 8009        cx: &mut Context<Self>,
 8010    ) -> Entity<ui::ContextMenu> {
 8011        let weak_editor = cx.weak_entity();
 8012        let focus_handle = self.focus_handle(cx);
 8013
 8014        let row = self
 8015            .buffer
 8016            .read(cx)
 8017            .snapshot(cx)
 8018            .summary_for_anchor::<Point>(&anchor)
 8019            .row;
 8020
 8021        let breakpoint = self
 8022            .breakpoint_at_row(row, window, cx)
 8023            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8024
 8025        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8026            "Edit Log Breakpoint"
 8027        } else {
 8028            "Set Log Breakpoint"
 8029        };
 8030
 8031        let condition_breakpoint_msg = if breakpoint
 8032            .as_ref()
 8033            .is_some_and(|bp| bp.1.condition.is_some())
 8034        {
 8035            "Edit Condition Breakpoint"
 8036        } else {
 8037            "Set Condition Breakpoint"
 8038        };
 8039
 8040        let hit_condition_breakpoint_msg = if breakpoint
 8041            .as_ref()
 8042            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8043        {
 8044            "Edit Hit Condition Breakpoint"
 8045        } else {
 8046            "Set Hit Condition Breakpoint"
 8047        };
 8048
 8049        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8050            "Unset Breakpoint"
 8051        } else {
 8052            "Set Breakpoint"
 8053        };
 8054
 8055        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8056
 8057        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8058            BreakpointState::Enabled => Some("Disable"),
 8059            BreakpointState::Disabled => Some("Enable"),
 8060        });
 8061
 8062        let (anchor, breakpoint) =
 8063            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8064
 8065        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8066            menu.on_blur_subscription(Subscription::new(|| {}))
 8067                .context(focus_handle)
 8068                .when(run_to_cursor, |this| {
 8069                    let weak_editor = weak_editor.clone();
 8070                    this.entry("Run to cursor", None, move |window, cx| {
 8071                        weak_editor
 8072                            .update(cx, |editor, cx| {
 8073                                editor.change_selections(
 8074                                    SelectionEffects::no_scroll(),
 8075                                    window,
 8076                                    cx,
 8077                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8078                                );
 8079                            })
 8080                            .ok();
 8081
 8082                        window.dispatch_action(Box::new(RunToCursor), cx);
 8083                    })
 8084                    .separator()
 8085                })
 8086                .when_some(toggle_state_msg, |this, msg| {
 8087                    this.entry(msg, None, {
 8088                        let weak_editor = weak_editor.clone();
 8089                        let breakpoint = breakpoint.clone();
 8090                        move |_window, cx| {
 8091                            weak_editor
 8092                                .update(cx, |this, cx| {
 8093                                    this.edit_breakpoint_at_anchor(
 8094                                        anchor,
 8095                                        breakpoint.as_ref().clone(),
 8096                                        BreakpointEditAction::InvertState,
 8097                                        cx,
 8098                                    );
 8099                                })
 8100                                .log_err();
 8101                        }
 8102                    })
 8103                })
 8104                .entry(set_breakpoint_msg, None, {
 8105                    let weak_editor = weak_editor.clone();
 8106                    let breakpoint = breakpoint.clone();
 8107                    move |_window, cx| {
 8108                        weak_editor
 8109                            .update(cx, |this, cx| {
 8110                                this.edit_breakpoint_at_anchor(
 8111                                    anchor,
 8112                                    breakpoint.as_ref().clone(),
 8113                                    BreakpointEditAction::Toggle,
 8114                                    cx,
 8115                                );
 8116                            })
 8117                            .log_err();
 8118                    }
 8119                })
 8120                .entry(log_breakpoint_msg, None, {
 8121                    let breakpoint = breakpoint.clone();
 8122                    let weak_editor = weak_editor.clone();
 8123                    move |window, cx| {
 8124                        weak_editor
 8125                            .update(cx, |this, cx| {
 8126                                this.add_edit_breakpoint_block(
 8127                                    anchor,
 8128                                    breakpoint.as_ref(),
 8129                                    BreakpointPromptEditAction::Log,
 8130                                    window,
 8131                                    cx,
 8132                                );
 8133                            })
 8134                            .log_err();
 8135                    }
 8136                })
 8137                .entry(condition_breakpoint_msg, None, {
 8138                    let breakpoint = breakpoint.clone();
 8139                    let weak_editor = weak_editor.clone();
 8140                    move |window, cx| {
 8141                        weak_editor
 8142                            .update(cx, |this, cx| {
 8143                                this.add_edit_breakpoint_block(
 8144                                    anchor,
 8145                                    breakpoint.as_ref(),
 8146                                    BreakpointPromptEditAction::Condition,
 8147                                    window,
 8148                                    cx,
 8149                                );
 8150                            })
 8151                            .log_err();
 8152                    }
 8153                })
 8154                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8155                    weak_editor
 8156                        .update(cx, |this, cx| {
 8157                            this.add_edit_breakpoint_block(
 8158                                anchor,
 8159                                breakpoint.as_ref(),
 8160                                BreakpointPromptEditAction::HitCondition,
 8161                                window,
 8162                                cx,
 8163                            );
 8164                        })
 8165                        .log_err();
 8166                })
 8167        })
 8168    }
 8169
 8170    fn render_breakpoint(
 8171        &self,
 8172        position: Anchor,
 8173        row: DisplayRow,
 8174        breakpoint: &Breakpoint,
 8175        state: Option<BreakpointSessionState>,
 8176        cx: &mut Context<Self>,
 8177    ) -> IconButton {
 8178        let is_rejected = state.is_some_and(|s| !s.verified);
 8179        // Is it a breakpoint that shows up when hovering over gutter?
 8180        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8181            (false, false),
 8182            |PhantomBreakpointIndicator {
 8183                 is_active,
 8184                 display_row,
 8185                 collides_with_existing_breakpoint,
 8186             }| {
 8187                (
 8188                    is_active && display_row == row,
 8189                    collides_with_existing_breakpoint,
 8190                )
 8191            },
 8192        );
 8193
 8194        let (color, icon) = {
 8195            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8196                (false, false) => ui::IconName::DebugBreakpoint,
 8197                (true, false) => ui::IconName::DebugLogBreakpoint,
 8198                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8199                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8200            };
 8201
 8202            let color = if is_phantom {
 8203                Color::Hint
 8204            } else if is_rejected {
 8205                Color::Disabled
 8206            } else {
 8207                Color::Debugger
 8208            };
 8209
 8210            (color, icon)
 8211        };
 8212
 8213        let breakpoint = Arc::from(breakpoint.clone());
 8214
 8215        let alt_as_text = gpui::Keystroke {
 8216            modifiers: Modifiers::secondary_key(),
 8217            ..Default::default()
 8218        };
 8219        let primary_action_text = if breakpoint.is_disabled() {
 8220            "Enable breakpoint"
 8221        } else if is_phantom && !collides_with_existing {
 8222            "Set breakpoint"
 8223        } else {
 8224            "Unset breakpoint"
 8225        };
 8226        let focus_handle = self.focus_handle.clone();
 8227
 8228        let meta = if is_rejected {
 8229            SharedString::from("No executable code is associated with this line.")
 8230        } else if collides_with_existing && !breakpoint.is_disabled() {
 8231            SharedString::from(format!(
 8232                "{alt_as_text}-click to disable,\nright-click for more options."
 8233            ))
 8234        } else {
 8235            SharedString::from("Right-click for more options.")
 8236        };
 8237        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8238            .icon_size(IconSize::XSmall)
 8239            .size(ui::ButtonSize::None)
 8240            .when(is_rejected, |this| {
 8241                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8242            })
 8243            .icon_color(color)
 8244            .style(ButtonStyle::Transparent)
 8245            .on_click(cx.listener({
 8246                move |editor, event: &ClickEvent, window, cx| {
 8247                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8248                        BreakpointEditAction::InvertState
 8249                    } else {
 8250                        BreakpointEditAction::Toggle
 8251                    };
 8252
 8253                    window.focus(&editor.focus_handle(cx));
 8254                    editor.edit_breakpoint_at_anchor(
 8255                        position,
 8256                        breakpoint.as_ref().clone(),
 8257                        edit_action,
 8258                        cx,
 8259                    );
 8260                }
 8261            }))
 8262            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8263                editor.set_breakpoint_context_menu(
 8264                    row,
 8265                    Some(position),
 8266                    event.position(),
 8267                    window,
 8268                    cx,
 8269                );
 8270            }))
 8271            .tooltip(move |window, cx| {
 8272                Tooltip::with_meta_in(
 8273                    primary_action_text,
 8274                    Some(&ToggleBreakpoint),
 8275                    meta.clone(),
 8276                    &focus_handle,
 8277                    window,
 8278                    cx,
 8279                )
 8280            })
 8281    }
 8282
 8283    fn build_tasks_context(
 8284        project: &Entity<Project>,
 8285        buffer: &Entity<Buffer>,
 8286        buffer_row: u32,
 8287        tasks: &Arc<RunnableTasks>,
 8288        cx: &mut Context<Self>,
 8289    ) -> Task<Option<task::TaskContext>> {
 8290        let position = Point::new(buffer_row, tasks.column);
 8291        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8292        let location = Location {
 8293            buffer: buffer.clone(),
 8294            range: range_start..range_start,
 8295        };
 8296        // Fill in the environmental variables from the tree-sitter captures
 8297        let mut captured_task_variables = TaskVariables::default();
 8298        for (capture_name, value) in tasks.extra_variables.clone() {
 8299            captured_task_variables.insert(
 8300                task::VariableName::Custom(capture_name.into()),
 8301                value.clone(),
 8302            );
 8303        }
 8304        project.update(cx, |project, cx| {
 8305            project.task_store().update(cx, |task_store, cx| {
 8306                task_store.task_context_for_location(captured_task_variables, location, cx)
 8307            })
 8308        })
 8309    }
 8310
 8311    pub fn spawn_nearest_task(
 8312        &mut self,
 8313        action: &SpawnNearestTask,
 8314        window: &mut Window,
 8315        cx: &mut Context<Self>,
 8316    ) {
 8317        let Some((workspace, _)) = self.workspace.clone() else {
 8318            return;
 8319        };
 8320        let Some(project) = self.project.clone() else {
 8321            return;
 8322        };
 8323
 8324        // Try to find a closest, enclosing node using tree-sitter that has a task
 8325        let Some((buffer, buffer_row, tasks)) = self
 8326            .find_enclosing_node_task(cx)
 8327            // Or find the task that's closest in row-distance.
 8328            .or_else(|| self.find_closest_task(cx))
 8329        else {
 8330            return;
 8331        };
 8332
 8333        let reveal_strategy = action.reveal;
 8334        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8335        cx.spawn_in(window, async move |_, cx| {
 8336            let context = task_context.await?;
 8337            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8338
 8339            let resolved = &mut resolved_task.resolved;
 8340            resolved.reveal = reveal_strategy;
 8341
 8342            workspace
 8343                .update_in(cx, |workspace, window, cx| {
 8344                    workspace.schedule_resolved_task(
 8345                        task_source_kind,
 8346                        resolved_task,
 8347                        false,
 8348                        window,
 8349                        cx,
 8350                    );
 8351                })
 8352                .ok()
 8353        })
 8354        .detach();
 8355    }
 8356
 8357    fn find_closest_task(
 8358        &mut self,
 8359        cx: &mut Context<Self>,
 8360    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8361        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8362
 8363        let ((buffer_id, row), tasks) = self
 8364            .tasks
 8365            .iter()
 8366            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8367
 8368        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8369        let tasks = Arc::new(tasks.to_owned());
 8370        Some((buffer, *row, tasks))
 8371    }
 8372
 8373    fn find_enclosing_node_task(
 8374        &mut self,
 8375        cx: &mut Context<Self>,
 8376    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8377        let snapshot = self.buffer.read(cx).snapshot(cx);
 8378        let offset = self.selections.newest::<usize>(cx).head();
 8379        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8380        let buffer_id = excerpt.buffer().remote_id();
 8381
 8382        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8383        let mut cursor = layer.node().walk();
 8384
 8385        while cursor.goto_first_child_for_byte(offset).is_some() {
 8386            if cursor.node().end_byte() == offset {
 8387                cursor.goto_next_sibling();
 8388            }
 8389        }
 8390
 8391        // Ascend to the smallest ancestor that contains the range and has a task.
 8392        loop {
 8393            let node = cursor.node();
 8394            let node_range = node.byte_range();
 8395            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8396
 8397            // Check if this node contains our offset
 8398            if node_range.start <= offset && node_range.end >= offset {
 8399                // If it contains offset, check for task
 8400                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8401                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8402                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8403                }
 8404            }
 8405
 8406            if !cursor.goto_parent() {
 8407                break;
 8408            }
 8409        }
 8410        None
 8411    }
 8412
 8413    fn render_run_indicator(
 8414        &self,
 8415        _style: &EditorStyle,
 8416        is_active: bool,
 8417        row: DisplayRow,
 8418        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8419        cx: &mut Context<Self>,
 8420    ) -> IconButton {
 8421        let color = Color::Muted;
 8422        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8423
 8424        IconButton::new(
 8425            ("run_indicator", row.0 as usize),
 8426            ui::IconName::PlayOutlined,
 8427        )
 8428        .shape(ui::IconButtonShape::Square)
 8429        .icon_size(IconSize::XSmall)
 8430        .icon_color(color)
 8431        .toggle_state(is_active)
 8432        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8433            let quick_launch = match e {
 8434                ClickEvent::Keyboard(_) => true,
 8435                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8436            };
 8437
 8438            window.focus(&editor.focus_handle(cx));
 8439            editor.toggle_code_actions(
 8440                &ToggleCodeActions {
 8441                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8442                    quick_launch,
 8443                },
 8444                window,
 8445                cx,
 8446            );
 8447        }))
 8448        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8449            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8450        }))
 8451    }
 8452
 8453    pub fn context_menu_visible(&self) -> bool {
 8454        !self.edit_prediction_preview_is_active()
 8455            && self
 8456                .context_menu
 8457                .borrow()
 8458                .as_ref()
 8459                .is_some_and(|menu| menu.visible())
 8460    }
 8461
 8462    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8463        self.context_menu
 8464            .borrow()
 8465            .as_ref()
 8466            .map(|menu| menu.origin())
 8467    }
 8468
 8469    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8470        self.context_menu_options = Some(options);
 8471    }
 8472
 8473    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8474    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8475
 8476    fn render_edit_prediction_popover(
 8477        &mut self,
 8478        text_bounds: &Bounds<Pixels>,
 8479        content_origin: gpui::Point<Pixels>,
 8480        right_margin: Pixels,
 8481        editor_snapshot: &EditorSnapshot,
 8482        visible_row_range: Range<DisplayRow>,
 8483        scroll_top: f32,
 8484        scroll_bottom: f32,
 8485        line_layouts: &[LineWithInvisibles],
 8486        line_height: Pixels,
 8487        scroll_pixel_position: gpui::Point<Pixels>,
 8488        newest_selection_head: Option<DisplayPoint>,
 8489        editor_width: Pixels,
 8490        style: &EditorStyle,
 8491        window: &mut Window,
 8492        cx: &mut App,
 8493    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8494        if self.mode().is_minimap() {
 8495            return None;
 8496        }
 8497        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8498
 8499        if self.edit_prediction_visible_in_cursor_popover(true) {
 8500            return None;
 8501        }
 8502
 8503        match &active_edit_prediction.completion {
 8504            EditPrediction::Move { target, .. } => {
 8505                let target_display_point = target.to_display_point(editor_snapshot);
 8506
 8507                if self.edit_prediction_requires_modifier() {
 8508                    if !self.edit_prediction_preview_is_active() {
 8509                        return None;
 8510                    }
 8511
 8512                    self.render_edit_prediction_modifier_jump_popover(
 8513                        text_bounds,
 8514                        content_origin,
 8515                        visible_row_range,
 8516                        line_layouts,
 8517                        line_height,
 8518                        scroll_pixel_position,
 8519                        newest_selection_head,
 8520                        target_display_point,
 8521                        window,
 8522                        cx,
 8523                    )
 8524                } else {
 8525                    self.render_edit_prediction_eager_jump_popover(
 8526                        text_bounds,
 8527                        content_origin,
 8528                        editor_snapshot,
 8529                        visible_row_range,
 8530                        scroll_top,
 8531                        scroll_bottom,
 8532                        line_height,
 8533                        scroll_pixel_position,
 8534                        target_display_point,
 8535                        editor_width,
 8536                        window,
 8537                        cx,
 8538                    )
 8539                }
 8540            }
 8541            EditPrediction::Edit {
 8542                display_mode: EditDisplayMode::Inline,
 8543                ..
 8544            } => None,
 8545            EditPrediction::Edit {
 8546                display_mode: EditDisplayMode::TabAccept,
 8547                edits,
 8548                ..
 8549            } => {
 8550                let range = &edits.first()?.0;
 8551                let target_display_point = range.end.to_display_point(editor_snapshot);
 8552
 8553                self.render_edit_prediction_end_of_line_popover(
 8554                    "Accept",
 8555                    editor_snapshot,
 8556                    visible_row_range,
 8557                    target_display_point,
 8558                    line_height,
 8559                    scroll_pixel_position,
 8560                    content_origin,
 8561                    editor_width,
 8562                    window,
 8563                    cx,
 8564                )
 8565            }
 8566            EditPrediction::Edit {
 8567                edits,
 8568                edit_preview,
 8569                display_mode: EditDisplayMode::DiffPopover,
 8570                snapshot,
 8571            } => self.render_edit_prediction_diff_popover(
 8572                text_bounds,
 8573                content_origin,
 8574                right_margin,
 8575                editor_snapshot,
 8576                visible_row_range,
 8577                line_layouts,
 8578                line_height,
 8579                scroll_pixel_position,
 8580                newest_selection_head,
 8581                editor_width,
 8582                style,
 8583                edits,
 8584                edit_preview,
 8585                snapshot,
 8586                window,
 8587                cx,
 8588            ),
 8589        }
 8590    }
 8591
 8592    fn render_edit_prediction_modifier_jump_popover(
 8593        &mut self,
 8594        text_bounds: &Bounds<Pixels>,
 8595        content_origin: gpui::Point<Pixels>,
 8596        visible_row_range: Range<DisplayRow>,
 8597        line_layouts: &[LineWithInvisibles],
 8598        line_height: Pixels,
 8599        scroll_pixel_position: gpui::Point<Pixels>,
 8600        newest_selection_head: Option<DisplayPoint>,
 8601        target_display_point: DisplayPoint,
 8602        window: &mut Window,
 8603        cx: &mut App,
 8604    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8605        let scrolled_content_origin =
 8606            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8607
 8608        const SCROLL_PADDING_Y: Pixels = px(12.);
 8609
 8610        if target_display_point.row() < visible_row_range.start {
 8611            return self.render_edit_prediction_scroll_popover(
 8612                |_| SCROLL_PADDING_Y,
 8613                IconName::ArrowUp,
 8614                visible_row_range,
 8615                line_layouts,
 8616                newest_selection_head,
 8617                scrolled_content_origin,
 8618                window,
 8619                cx,
 8620            );
 8621        } else if target_display_point.row() >= visible_row_range.end {
 8622            return self.render_edit_prediction_scroll_popover(
 8623                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8624                IconName::ArrowDown,
 8625                visible_row_range,
 8626                line_layouts,
 8627                newest_selection_head,
 8628                scrolled_content_origin,
 8629                window,
 8630                cx,
 8631            );
 8632        }
 8633
 8634        const POLE_WIDTH: Pixels = px(2.);
 8635
 8636        let line_layout =
 8637            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8638        let target_column = target_display_point.column() as usize;
 8639
 8640        let target_x = line_layout.x_for_index(target_column);
 8641        let target_y =
 8642            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8643
 8644        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8645
 8646        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8647        border_color.l += 0.001;
 8648
 8649        let mut element = v_flex()
 8650            .items_end()
 8651            .when(flag_on_right, |el| el.items_start())
 8652            .child(if flag_on_right {
 8653                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8654                    .rounded_bl(px(0.))
 8655                    .rounded_tl(px(0.))
 8656                    .border_l_2()
 8657                    .border_color(border_color)
 8658            } else {
 8659                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8660                    .rounded_br(px(0.))
 8661                    .rounded_tr(px(0.))
 8662                    .border_r_2()
 8663                    .border_color(border_color)
 8664            })
 8665            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8666            .into_any();
 8667
 8668        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8669
 8670        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8671            - point(
 8672                if flag_on_right {
 8673                    POLE_WIDTH
 8674                } else {
 8675                    size.width - POLE_WIDTH
 8676                },
 8677                size.height - line_height,
 8678            );
 8679
 8680        origin.x = origin.x.max(content_origin.x);
 8681
 8682        element.prepaint_at(origin, window, cx);
 8683
 8684        Some((element, origin))
 8685    }
 8686
 8687    fn render_edit_prediction_scroll_popover(
 8688        &mut self,
 8689        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8690        scroll_icon: IconName,
 8691        visible_row_range: Range<DisplayRow>,
 8692        line_layouts: &[LineWithInvisibles],
 8693        newest_selection_head: Option<DisplayPoint>,
 8694        scrolled_content_origin: gpui::Point<Pixels>,
 8695        window: &mut Window,
 8696        cx: &mut App,
 8697    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8698        let mut element = self
 8699            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8700            .into_any();
 8701
 8702        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8703
 8704        let cursor = newest_selection_head?;
 8705        let cursor_row_layout =
 8706            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8707        let cursor_column = cursor.column() as usize;
 8708
 8709        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8710
 8711        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8712
 8713        element.prepaint_at(origin, window, cx);
 8714        Some((element, origin))
 8715    }
 8716
 8717    fn render_edit_prediction_eager_jump_popover(
 8718        &mut self,
 8719        text_bounds: &Bounds<Pixels>,
 8720        content_origin: gpui::Point<Pixels>,
 8721        editor_snapshot: &EditorSnapshot,
 8722        visible_row_range: Range<DisplayRow>,
 8723        scroll_top: f32,
 8724        scroll_bottom: f32,
 8725        line_height: Pixels,
 8726        scroll_pixel_position: gpui::Point<Pixels>,
 8727        target_display_point: DisplayPoint,
 8728        editor_width: Pixels,
 8729        window: &mut Window,
 8730        cx: &mut App,
 8731    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8732        if target_display_point.row().as_f32() < scroll_top {
 8733            let mut element = self
 8734                .render_edit_prediction_line_popover(
 8735                    "Jump to Edit",
 8736                    Some(IconName::ArrowUp),
 8737                    window,
 8738                    cx,
 8739                )?
 8740                .into_any();
 8741
 8742            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8743            let offset = point(
 8744                (text_bounds.size.width - size.width) / 2.,
 8745                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8746            );
 8747
 8748            let origin = text_bounds.origin + offset;
 8749            element.prepaint_at(origin, window, cx);
 8750            Some((element, origin))
 8751        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8752            let mut element = self
 8753                .render_edit_prediction_line_popover(
 8754                    "Jump to Edit",
 8755                    Some(IconName::ArrowDown),
 8756                    window,
 8757                    cx,
 8758                )?
 8759                .into_any();
 8760
 8761            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8762            let offset = point(
 8763                (text_bounds.size.width - size.width) / 2.,
 8764                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8765            );
 8766
 8767            let origin = text_bounds.origin + offset;
 8768            element.prepaint_at(origin, window, cx);
 8769            Some((element, origin))
 8770        } else {
 8771            self.render_edit_prediction_end_of_line_popover(
 8772                "Jump to Edit",
 8773                editor_snapshot,
 8774                visible_row_range,
 8775                target_display_point,
 8776                line_height,
 8777                scroll_pixel_position,
 8778                content_origin,
 8779                editor_width,
 8780                window,
 8781                cx,
 8782            )
 8783        }
 8784    }
 8785
 8786    fn render_edit_prediction_end_of_line_popover(
 8787        self: &mut Editor,
 8788        label: &'static str,
 8789        editor_snapshot: &EditorSnapshot,
 8790        visible_row_range: Range<DisplayRow>,
 8791        target_display_point: DisplayPoint,
 8792        line_height: Pixels,
 8793        scroll_pixel_position: gpui::Point<Pixels>,
 8794        content_origin: gpui::Point<Pixels>,
 8795        editor_width: Pixels,
 8796        window: &mut Window,
 8797        cx: &mut App,
 8798    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8799        let target_line_end = DisplayPoint::new(
 8800            target_display_point.row(),
 8801            editor_snapshot.line_len(target_display_point.row()),
 8802        );
 8803
 8804        let mut element = self
 8805            .render_edit_prediction_line_popover(label, None, window, cx)?
 8806            .into_any();
 8807
 8808        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8809
 8810        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8811
 8812        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8813        let mut origin = start_point
 8814            + line_origin
 8815            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8816        origin.x = origin.x.max(content_origin.x);
 8817
 8818        let max_x = content_origin.x + editor_width - size.width;
 8819
 8820        if origin.x > max_x {
 8821            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8822
 8823            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8824                origin.y += offset;
 8825                IconName::ArrowUp
 8826            } else {
 8827                origin.y -= offset;
 8828                IconName::ArrowDown
 8829            };
 8830
 8831            element = self
 8832                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8833                .into_any();
 8834
 8835            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8836
 8837            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8838        }
 8839
 8840        element.prepaint_at(origin, window, cx);
 8841        Some((element, origin))
 8842    }
 8843
 8844    fn render_edit_prediction_diff_popover(
 8845        self: &Editor,
 8846        text_bounds: &Bounds<Pixels>,
 8847        content_origin: gpui::Point<Pixels>,
 8848        right_margin: Pixels,
 8849        editor_snapshot: &EditorSnapshot,
 8850        visible_row_range: Range<DisplayRow>,
 8851        line_layouts: &[LineWithInvisibles],
 8852        line_height: Pixels,
 8853        scroll_pixel_position: gpui::Point<Pixels>,
 8854        newest_selection_head: Option<DisplayPoint>,
 8855        editor_width: Pixels,
 8856        style: &EditorStyle,
 8857        edits: &Vec<(Range<Anchor>, String)>,
 8858        edit_preview: &Option<language::EditPreview>,
 8859        snapshot: &language::BufferSnapshot,
 8860        window: &mut Window,
 8861        cx: &mut App,
 8862    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8863        let edit_start = edits
 8864            .first()
 8865            .unwrap()
 8866            .0
 8867            .start
 8868            .to_display_point(editor_snapshot);
 8869        let edit_end = edits
 8870            .last()
 8871            .unwrap()
 8872            .0
 8873            .end
 8874            .to_display_point(editor_snapshot);
 8875
 8876        let is_visible = visible_row_range.contains(&edit_start.row())
 8877            || visible_row_range.contains(&edit_end.row());
 8878        if !is_visible {
 8879            return None;
 8880        }
 8881
 8882        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8883            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8884        } else {
 8885            // Fallback for providers without edit_preview
 8886            crate::edit_prediction_fallback_text(edits, cx)
 8887        };
 8888
 8889        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8890        let line_count = highlighted_edits.text.lines().count();
 8891
 8892        const BORDER_WIDTH: Pixels = px(1.);
 8893
 8894        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8895        let has_keybind = keybind.is_some();
 8896
 8897        let mut element = h_flex()
 8898            .items_start()
 8899            .child(
 8900                h_flex()
 8901                    .bg(cx.theme().colors().editor_background)
 8902                    .border(BORDER_WIDTH)
 8903                    .shadow_xs()
 8904                    .border_color(cx.theme().colors().border)
 8905                    .rounded_l_lg()
 8906                    .when(line_count > 1, |el| el.rounded_br_lg())
 8907                    .pr_1()
 8908                    .child(styled_text),
 8909            )
 8910            .child(
 8911                h_flex()
 8912                    .h(line_height + BORDER_WIDTH * 2.)
 8913                    .px_1p5()
 8914                    .gap_1()
 8915                    // Workaround: For some reason, there's a gap if we don't do this
 8916                    .ml(-BORDER_WIDTH)
 8917                    .shadow(vec![gpui::BoxShadow {
 8918                        color: gpui::black().opacity(0.05),
 8919                        offset: point(px(1.), px(1.)),
 8920                        blur_radius: px(2.),
 8921                        spread_radius: px(0.),
 8922                    }])
 8923                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8924                    .border(BORDER_WIDTH)
 8925                    .border_color(cx.theme().colors().border)
 8926                    .rounded_r_lg()
 8927                    .id("edit_prediction_diff_popover_keybind")
 8928                    .when(!has_keybind, |el| {
 8929                        let status_colors = cx.theme().status();
 8930
 8931                        el.bg(status_colors.error_background)
 8932                            .border_color(status_colors.error.opacity(0.6))
 8933                            .child(Icon::new(IconName::Info).color(Color::Error))
 8934                            .cursor_default()
 8935                            .hoverable_tooltip(move |_window, cx| {
 8936                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8937                            })
 8938                    })
 8939                    .children(keybind),
 8940            )
 8941            .into_any();
 8942
 8943        let longest_row =
 8944            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8945        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8946            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8947        } else {
 8948            layout_line(
 8949                longest_row,
 8950                editor_snapshot,
 8951                style,
 8952                editor_width,
 8953                |_| false,
 8954                window,
 8955                cx,
 8956            )
 8957            .width
 8958        };
 8959
 8960        let viewport_bounds =
 8961            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8962                right: -right_margin,
 8963                ..Default::default()
 8964            });
 8965
 8966        let x_after_longest =
 8967            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8968                - scroll_pixel_position.x;
 8969
 8970        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8971
 8972        // Fully visible if it can be displayed within the window (allow overlapping other
 8973        // panes). However, this is only allowed if the popover starts within text_bounds.
 8974        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8975            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8976
 8977        let mut origin = if can_position_to_the_right {
 8978            point(
 8979                x_after_longest,
 8980                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8981                    - scroll_pixel_position.y,
 8982            )
 8983        } else {
 8984            let cursor_row = newest_selection_head.map(|head| head.row());
 8985            let above_edit = edit_start
 8986                .row()
 8987                .0
 8988                .checked_sub(line_count as u32)
 8989                .map(DisplayRow);
 8990            let below_edit = Some(edit_end.row() + 1);
 8991            let above_cursor =
 8992                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8993            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8994
 8995            // Place the edit popover adjacent to the edit if there is a location
 8996            // available that is onscreen and does not obscure the cursor. Otherwise,
 8997            // place it adjacent to the cursor.
 8998            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8999                .into_iter()
 9000                .flatten()
 9001                .find(|&start_row| {
 9002                    let end_row = start_row + line_count as u32;
 9003                    visible_row_range.contains(&start_row)
 9004                        && visible_row_range.contains(&end_row)
 9005                        && cursor_row
 9006                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9007                })?;
 9008
 9009            content_origin
 9010                + point(
 9011                    -scroll_pixel_position.x,
 9012                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9013                )
 9014        };
 9015
 9016        origin.x -= BORDER_WIDTH;
 9017
 9018        window.defer_draw(element, origin, 1);
 9019
 9020        // Do not return an element, since it will already be drawn due to defer_draw.
 9021        None
 9022    }
 9023
 9024    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9025        px(30.)
 9026    }
 9027
 9028    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9029        if self.read_only(cx) {
 9030            cx.theme().players().read_only()
 9031        } else {
 9032            self.style.as_ref().unwrap().local_player
 9033        }
 9034    }
 9035
 9036    fn render_edit_prediction_accept_keybind(
 9037        &self,
 9038        window: &mut Window,
 9039        cx: &App,
 9040    ) -> Option<AnyElement> {
 9041        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9042        let accept_keystroke = accept_binding.keystroke()?;
 9043
 9044        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9045
 9046        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9047            Color::Accent
 9048        } else {
 9049            Color::Muted
 9050        };
 9051
 9052        h_flex()
 9053            .px_0p5()
 9054            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9055            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9056            .text_size(TextSize::XSmall.rems(cx))
 9057            .child(h_flex().children(ui::render_modifiers(
 9058                accept_keystroke.modifiers(),
 9059                PlatformStyle::platform(),
 9060                Some(modifiers_color),
 9061                Some(IconSize::XSmall.rems().into()),
 9062                true,
 9063            )))
 9064            .when(is_platform_style_mac, |parent| {
 9065                parent.child(accept_keystroke.key().to_string())
 9066            })
 9067            .when(!is_platform_style_mac, |parent| {
 9068                parent.child(
 9069                    Key::new(
 9070                        util::capitalize(accept_keystroke.key()),
 9071                        Some(Color::Default),
 9072                    )
 9073                    .size(Some(IconSize::XSmall.rems().into())),
 9074                )
 9075            })
 9076            .into_any()
 9077            .into()
 9078    }
 9079
 9080    fn render_edit_prediction_line_popover(
 9081        &self,
 9082        label: impl Into<SharedString>,
 9083        icon: Option<IconName>,
 9084        window: &mut Window,
 9085        cx: &App,
 9086    ) -> Option<Stateful<Div>> {
 9087        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9088
 9089        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9090        let has_keybind = keybind.is_some();
 9091
 9092        let result = h_flex()
 9093            .id("ep-line-popover")
 9094            .py_0p5()
 9095            .pl_1()
 9096            .pr(padding_right)
 9097            .gap_1()
 9098            .rounded_md()
 9099            .border_1()
 9100            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9101            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9102            .shadow_xs()
 9103            .when(!has_keybind, |el| {
 9104                let status_colors = cx.theme().status();
 9105
 9106                el.bg(status_colors.error_background)
 9107                    .border_color(status_colors.error.opacity(0.6))
 9108                    .pl_2()
 9109                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9110                    .cursor_default()
 9111                    .hoverable_tooltip(move |_window, cx| {
 9112                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9113                    })
 9114            })
 9115            .children(keybind)
 9116            .child(
 9117                Label::new(label)
 9118                    .size(LabelSize::Small)
 9119                    .when(!has_keybind, |el| {
 9120                        el.color(cx.theme().status().error.into()).strikethrough()
 9121                    }),
 9122            )
 9123            .when(!has_keybind, |el| {
 9124                el.child(
 9125                    h_flex().ml_1().child(
 9126                        Icon::new(IconName::Info)
 9127                            .size(IconSize::Small)
 9128                            .color(cx.theme().status().error.into()),
 9129                    ),
 9130                )
 9131            })
 9132            .when_some(icon, |element, icon| {
 9133                element.child(
 9134                    div()
 9135                        .mt(px(1.5))
 9136                        .child(Icon::new(icon).size(IconSize::Small)),
 9137                )
 9138            });
 9139
 9140        Some(result)
 9141    }
 9142
 9143    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9144        let accent_color = cx.theme().colors().text_accent;
 9145        let editor_bg_color = cx.theme().colors().editor_background;
 9146        editor_bg_color.blend(accent_color.opacity(0.1))
 9147    }
 9148
 9149    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9150        let accent_color = cx.theme().colors().text_accent;
 9151        let editor_bg_color = cx.theme().colors().editor_background;
 9152        editor_bg_color.blend(accent_color.opacity(0.6))
 9153    }
 9154    fn get_prediction_provider_icon_name(
 9155        provider: &Option<RegisteredEditPredictionProvider>,
 9156    ) -> IconName {
 9157        match provider {
 9158            Some(provider) => match provider.provider.name() {
 9159                "copilot" => IconName::Copilot,
 9160                "supermaven" => IconName::Supermaven,
 9161                _ => IconName::ZedPredict,
 9162            },
 9163            None => IconName::ZedPredict,
 9164        }
 9165    }
 9166
 9167    fn render_edit_prediction_cursor_popover(
 9168        &self,
 9169        min_width: Pixels,
 9170        max_width: Pixels,
 9171        cursor_point: Point,
 9172        style: &EditorStyle,
 9173        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9174        _window: &Window,
 9175        cx: &mut Context<Editor>,
 9176    ) -> Option<AnyElement> {
 9177        let provider = self.edit_prediction_provider.as_ref()?;
 9178        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9179
 9180        let is_refreshing = provider.provider.is_refreshing(cx);
 9181
 9182        fn pending_completion_container(icon: IconName) -> Div {
 9183            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9184        }
 9185
 9186        let completion = match &self.active_edit_prediction {
 9187            Some(prediction) => {
 9188                if !self.has_visible_completions_menu() {
 9189                    const RADIUS: Pixels = px(6.);
 9190                    const BORDER_WIDTH: Pixels = px(1.);
 9191
 9192                    return Some(
 9193                        h_flex()
 9194                            .elevation_2(cx)
 9195                            .border(BORDER_WIDTH)
 9196                            .border_color(cx.theme().colors().border)
 9197                            .when(accept_keystroke.is_none(), |el| {
 9198                                el.border_color(cx.theme().status().error)
 9199                            })
 9200                            .rounded(RADIUS)
 9201                            .rounded_tl(px(0.))
 9202                            .overflow_hidden()
 9203                            .child(div().px_1p5().child(match &prediction.completion {
 9204                                EditPrediction::Move { target, snapshot } => {
 9205                                    use text::ToPoint as _;
 9206                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9207                                    {
 9208                                        Icon::new(IconName::ZedPredictDown)
 9209                                    } else {
 9210                                        Icon::new(IconName::ZedPredictUp)
 9211                                    }
 9212                                }
 9213                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9214                            }))
 9215                            .child(
 9216                                h_flex()
 9217                                    .gap_1()
 9218                                    .py_1()
 9219                                    .px_2()
 9220                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9221                                    .border_l_1()
 9222                                    .border_color(cx.theme().colors().border)
 9223                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9224                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9225                                        el.child(
 9226                                            Label::new("Hold")
 9227                                                .size(LabelSize::Small)
 9228                                                .when(accept_keystroke.is_none(), |el| {
 9229                                                    el.strikethrough()
 9230                                                })
 9231                                                .line_height_style(LineHeightStyle::UiLabel),
 9232                                        )
 9233                                    })
 9234                                    .id("edit_prediction_cursor_popover_keybind")
 9235                                    .when(accept_keystroke.is_none(), |el| {
 9236                                        let status_colors = cx.theme().status();
 9237
 9238                                        el.bg(status_colors.error_background)
 9239                                            .border_color(status_colors.error.opacity(0.6))
 9240                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9241                                            .cursor_default()
 9242                                            .hoverable_tooltip(move |_window, cx| {
 9243                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9244                                                    .into()
 9245                                            })
 9246                                    })
 9247                                    .when_some(
 9248                                        accept_keystroke.as_ref(),
 9249                                        |el, accept_keystroke| {
 9250                                            el.child(h_flex().children(ui::render_modifiers(
 9251                                                accept_keystroke.modifiers(),
 9252                                                PlatformStyle::platform(),
 9253                                                Some(Color::Default),
 9254                                                Some(IconSize::XSmall.rems().into()),
 9255                                                false,
 9256                                            )))
 9257                                        },
 9258                                    ),
 9259                            )
 9260                            .into_any(),
 9261                    );
 9262                }
 9263
 9264                self.render_edit_prediction_cursor_popover_preview(
 9265                    prediction,
 9266                    cursor_point,
 9267                    style,
 9268                    cx,
 9269                )?
 9270            }
 9271
 9272            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9273                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9274                    stale_completion,
 9275                    cursor_point,
 9276                    style,
 9277                    cx,
 9278                )?,
 9279
 9280                None => pending_completion_container(provider_icon)
 9281                    .child(Label::new("...").size(LabelSize::Small)),
 9282            },
 9283
 9284            None => pending_completion_container(provider_icon)
 9285                .child(Label::new("...").size(LabelSize::Small)),
 9286        };
 9287
 9288        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9289            completion
 9290                .with_animation(
 9291                    "loading-completion",
 9292                    Animation::new(Duration::from_secs(2))
 9293                        .repeat()
 9294                        .with_easing(pulsating_between(0.4, 0.8)),
 9295                    |label, delta| label.opacity(delta),
 9296                )
 9297                .into_any_element()
 9298        } else {
 9299            completion.into_any_element()
 9300        };
 9301
 9302        let has_completion = self.active_edit_prediction.is_some();
 9303
 9304        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9305        Some(
 9306            h_flex()
 9307                .min_w(min_width)
 9308                .max_w(max_width)
 9309                .flex_1()
 9310                .elevation_2(cx)
 9311                .border_color(cx.theme().colors().border)
 9312                .child(
 9313                    div()
 9314                        .flex_1()
 9315                        .py_1()
 9316                        .px_2()
 9317                        .overflow_hidden()
 9318                        .child(completion),
 9319                )
 9320                .when_some(accept_keystroke, |el, accept_keystroke| {
 9321                    if !accept_keystroke.modifiers().modified() {
 9322                        return el;
 9323                    }
 9324
 9325                    el.child(
 9326                        h_flex()
 9327                            .h_full()
 9328                            .border_l_1()
 9329                            .rounded_r_lg()
 9330                            .border_color(cx.theme().colors().border)
 9331                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9332                            .gap_1()
 9333                            .py_1()
 9334                            .px_2()
 9335                            .child(
 9336                                h_flex()
 9337                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9338                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9339                                    .child(h_flex().children(ui::render_modifiers(
 9340                                        accept_keystroke.modifiers(),
 9341                                        PlatformStyle::platform(),
 9342                                        Some(if !has_completion {
 9343                                            Color::Muted
 9344                                        } else {
 9345                                            Color::Default
 9346                                        }),
 9347                                        None,
 9348                                        false,
 9349                                    ))),
 9350                            )
 9351                            .child(Label::new("Preview").into_any_element())
 9352                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9353                    )
 9354                })
 9355                .into_any(),
 9356        )
 9357    }
 9358
 9359    fn render_edit_prediction_cursor_popover_preview(
 9360        &self,
 9361        completion: &EditPredictionState,
 9362        cursor_point: Point,
 9363        style: &EditorStyle,
 9364        cx: &mut Context<Editor>,
 9365    ) -> Option<Div> {
 9366        use text::ToPoint as _;
 9367
 9368        fn render_relative_row_jump(
 9369            prefix: impl Into<String>,
 9370            current_row: u32,
 9371            target_row: u32,
 9372        ) -> Div {
 9373            let (row_diff, arrow) = if target_row < current_row {
 9374                (current_row - target_row, IconName::ArrowUp)
 9375            } else {
 9376                (target_row - current_row, IconName::ArrowDown)
 9377            };
 9378
 9379            h_flex()
 9380                .child(
 9381                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9382                        .color(Color::Muted)
 9383                        .size(LabelSize::Small),
 9384                )
 9385                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9386        }
 9387
 9388        let supports_jump = self
 9389            .edit_prediction_provider
 9390            .as_ref()
 9391            .map(|provider| provider.provider.supports_jump_to_edit())
 9392            .unwrap_or(true);
 9393
 9394        match &completion.completion {
 9395            EditPrediction::Move {
 9396                target, snapshot, ..
 9397            } => {
 9398                if !supports_jump {
 9399                    return None;
 9400                }
 9401
 9402                Some(
 9403                    h_flex()
 9404                        .px_2()
 9405                        .gap_2()
 9406                        .flex_1()
 9407                        .child(
 9408                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9409                                Icon::new(IconName::ZedPredictDown)
 9410                            } else {
 9411                                Icon::new(IconName::ZedPredictUp)
 9412                            },
 9413                        )
 9414                        .child(Label::new("Jump to Edit")),
 9415                )
 9416            }
 9417
 9418            EditPrediction::Edit {
 9419                edits,
 9420                edit_preview,
 9421                snapshot,
 9422                display_mode: _,
 9423            } => {
 9424                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9425
 9426                let (highlighted_edits, has_more_lines) =
 9427                    if let Some(edit_preview) = edit_preview.as_ref() {
 9428                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9429                            .first_line_preview()
 9430                    } else {
 9431                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9432                    };
 9433
 9434                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9435                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9436
 9437                let preview = h_flex()
 9438                    .gap_1()
 9439                    .min_w_16()
 9440                    .child(styled_text)
 9441                    .when(has_more_lines, |parent| parent.child(""));
 9442
 9443                let left = if supports_jump && first_edit_row != cursor_point.row {
 9444                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9445                        .into_any_element()
 9446                } else {
 9447                    let icon_name =
 9448                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9449                    Icon::new(icon_name).into_any_element()
 9450                };
 9451
 9452                Some(
 9453                    h_flex()
 9454                        .h_full()
 9455                        .flex_1()
 9456                        .gap_2()
 9457                        .pr_1()
 9458                        .overflow_x_hidden()
 9459                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9460                        .child(left)
 9461                        .child(preview),
 9462                )
 9463            }
 9464        }
 9465    }
 9466
 9467    pub fn render_context_menu(
 9468        &self,
 9469        style: &EditorStyle,
 9470        max_height_in_lines: u32,
 9471        window: &mut Window,
 9472        cx: &mut Context<Editor>,
 9473    ) -> Option<AnyElement> {
 9474        let menu = self.context_menu.borrow();
 9475        let menu = menu.as_ref()?;
 9476        if !menu.visible() {
 9477            return None;
 9478        };
 9479        Some(menu.render(style, max_height_in_lines, window, cx))
 9480    }
 9481
 9482    fn render_context_menu_aside(
 9483        &mut self,
 9484        max_size: Size<Pixels>,
 9485        window: &mut Window,
 9486        cx: &mut Context<Editor>,
 9487    ) -> Option<AnyElement> {
 9488        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9489            if menu.visible() {
 9490                menu.render_aside(max_size, window, cx)
 9491            } else {
 9492                None
 9493            }
 9494        })
 9495    }
 9496
 9497    fn hide_context_menu(
 9498        &mut self,
 9499        window: &mut Window,
 9500        cx: &mut Context<Self>,
 9501    ) -> Option<CodeContextMenu> {
 9502        cx.notify();
 9503        self.completion_tasks.clear();
 9504        let context_menu = self.context_menu.borrow_mut().take();
 9505        self.stale_edit_prediction_in_menu.take();
 9506        self.update_visible_edit_prediction(window, cx);
 9507        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9508            && let Some(completion_provider) = &self.completion_provider
 9509        {
 9510            completion_provider.selection_changed(None, window, cx);
 9511        }
 9512        context_menu
 9513    }
 9514
 9515    fn show_snippet_choices(
 9516        &mut self,
 9517        choices: &Vec<String>,
 9518        selection: Range<Anchor>,
 9519        cx: &mut Context<Self>,
 9520    ) {
 9521        let Some((_, buffer, _)) = self
 9522            .buffer()
 9523            .read(cx)
 9524            .excerpt_containing(selection.start, cx)
 9525        else {
 9526            return;
 9527        };
 9528        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9529        else {
 9530            return;
 9531        };
 9532        if buffer != end_buffer {
 9533            log::error!("expected anchor range to have matching buffer IDs");
 9534            return;
 9535        }
 9536
 9537        let id = post_inc(&mut self.next_completion_id);
 9538        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9539        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9540            CompletionsMenu::new_snippet_choices(
 9541                id,
 9542                true,
 9543                choices,
 9544                selection,
 9545                buffer,
 9546                snippet_sort_order,
 9547            ),
 9548        ));
 9549    }
 9550
 9551    pub fn insert_snippet(
 9552        &mut self,
 9553        insertion_ranges: &[Range<usize>],
 9554        snippet: Snippet,
 9555        window: &mut Window,
 9556        cx: &mut Context<Self>,
 9557    ) -> Result<()> {
 9558        struct Tabstop<T> {
 9559            is_end_tabstop: bool,
 9560            ranges: Vec<Range<T>>,
 9561            choices: Option<Vec<String>>,
 9562        }
 9563
 9564        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9565            let snippet_text: Arc<str> = snippet.text.clone().into();
 9566            let edits = insertion_ranges
 9567                .iter()
 9568                .cloned()
 9569                .map(|range| (range, snippet_text.clone()));
 9570            let autoindent_mode = AutoindentMode::Block {
 9571                original_indent_columns: Vec::new(),
 9572            };
 9573            buffer.edit(edits, Some(autoindent_mode), cx);
 9574
 9575            let snapshot = &*buffer.read(cx);
 9576            let snippet = &snippet;
 9577            snippet
 9578                .tabstops
 9579                .iter()
 9580                .map(|tabstop| {
 9581                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9582                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9583                    });
 9584                    let mut tabstop_ranges = tabstop
 9585                        .ranges
 9586                        .iter()
 9587                        .flat_map(|tabstop_range| {
 9588                            let mut delta = 0_isize;
 9589                            insertion_ranges.iter().map(move |insertion_range| {
 9590                                let insertion_start = insertion_range.start as isize + delta;
 9591                                delta +=
 9592                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9593
 9594                                let start = ((insertion_start + tabstop_range.start) as usize)
 9595                                    .min(snapshot.len());
 9596                                let end = ((insertion_start + tabstop_range.end) as usize)
 9597                                    .min(snapshot.len());
 9598                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9599                            })
 9600                        })
 9601                        .collect::<Vec<_>>();
 9602                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9603
 9604                    Tabstop {
 9605                        is_end_tabstop,
 9606                        ranges: tabstop_ranges,
 9607                        choices: tabstop.choices.clone(),
 9608                    }
 9609                })
 9610                .collect::<Vec<_>>()
 9611        });
 9612        if let Some(tabstop) = tabstops.first() {
 9613            self.change_selections(Default::default(), window, cx, |s| {
 9614                // Reverse order so that the first range is the newest created selection.
 9615                // Completions will use it and autoscroll will prioritize it.
 9616                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9617            });
 9618
 9619            if let Some(choices) = &tabstop.choices
 9620                && let Some(selection) = tabstop.ranges.first()
 9621            {
 9622                self.show_snippet_choices(choices, selection.clone(), cx)
 9623            }
 9624
 9625            // If we're already at the last tabstop and it's at the end of the snippet,
 9626            // we're done, we don't need to keep the state around.
 9627            if !tabstop.is_end_tabstop {
 9628                let choices = tabstops
 9629                    .iter()
 9630                    .map(|tabstop| tabstop.choices.clone())
 9631                    .collect();
 9632
 9633                let ranges = tabstops
 9634                    .into_iter()
 9635                    .map(|tabstop| tabstop.ranges)
 9636                    .collect::<Vec<_>>();
 9637
 9638                self.snippet_stack.push(SnippetState {
 9639                    active_index: 0,
 9640                    ranges,
 9641                    choices,
 9642                });
 9643            }
 9644
 9645            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9646            if self.autoclose_regions.is_empty() {
 9647                let snapshot = self.buffer.read(cx).snapshot(cx);
 9648                let mut all_selections = self.selections.all::<Point>(cx);
 9649                for selection in &mut all_selections {
 9650                    let selection_head = selection.head();
 9651                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9652                        continue;
 9653                    };
 9654
 9655                    let mut bracket_pair = None;
 9656                    let max_lookup_length = scope
 9657                        .brackets()
 9658                        .map(|(pair, _)| {
 9659                            pair.start
 9660                                .as_str()
 9661                                .chars()
 9662                                .count()
 9663                                .max(pair.end.as_str().chars().count())
 9664                        })
 9665                        .max();
 9666                    if let Some(max_lookup_length) = max_lookup_length {
 9667                        let next_text = snapshot
 9668                            .chars_at(selection_head)
 9669                            .take(max_lookup_length)
 9670                            .collect::<String>();
 9671                        let prev_text = snapshot
 9672                            .reversed_chars_at(selection_head)
 9673                            .take(max_lookup_length)
 9674                            .collect::<String>();
 9675
 9676                        for (pair, enabled) in scope.brackets() {
 9677                            if enabled
 9678                                && pair.close
 9679                                && prev_text.starts_with(pair.start.as_str())
 9680                                && next_text.starts_with(pair.end.as_str())
 9681                            {
 9682                                bracket_pair = Some(pair.clone());
 9683                                break;
 9684                            }
 9685                        }
 9686                    }
 9687
 9688                    if let Some(pair) = bracket_pair {
 9689                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9690                        let autoclose_enabled =
 9691                            self.use_autoclose && snapshot_settings.use_autoclose;
 9692                        if autoclose_enabled {
 9693                            let start = snapshot.anchor_after(selection_head);
 9694                            let end = snapshot.anchor_after(selection_head);
 9695                            self.autoclose_regions.push(AutocloseRegion {
 9696                                selection_id: selection.id,
 9697                                range: start..end,
 9698                                pair,
 9699                            });
 9700                        }
 9701                    }
 9702                }
 9703            }
 9704        }
 9705        Ok(())
 9706    }
 9707
 9708    pub fn move_to_next_snippet_tabstop(
 9709        &mut self,
 9710        window: &mut Window,
 9711        cx: &mut Context<Self>,
 9712    ) -> bool {
 9713        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9714    }
 9715
 9716    pub fn move_to_prev_snippet_tabstop(
 9717        &mut self,
 9718        window: &mut Window,
 9719        cx: &mut Context<Self>,
 9720    ) -> bool {
 9721        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9722    }
 9723
 9724    pub fn move_to_snippet_tabstop(
 9725        &mut self,
 9726        bias: Bias,
 9727        window: &mut Window,
 9728        cx: &mut Context<Self>,
 9729    ) -> bool {
 9730        if let Some(mut snippet) = self.snippet_stack.pop() {
 9731            match bias {
 9732                Bias::Left => {
 9733                    if snippet.active_index > 0 {
 9734                        snippet.active_index -= 1;
 9735                    } else {
 9736                        self.snippet_stack.push(snippet);
 9737                        return false;
 9738                    }
 9739                }
 9740                Bias::Right => {
 9741                    if snippet.active_index + 1 < snippet.ranges.len() {
 9742                        snippet.active_index += 1;
 9743                    } else {
 9744                        self.snippet_stack.push(snippet);
 9745                        return false;
 9746                    }
 9747                }
 9748            }
 9749            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9750                self.change_selections(Default::default(), window, cx, |s| {
 9751                    // Reverse order so that the first range is the newest created selection.
 9752                    // Completions will use it and autoscroll will prioritize it.
 9753                    s.select_ranges(current_ranges.iter().rev().cloned())
 9754                });
 9755
 9756                if let Some(choices) = &snippet.choices[snippet.active_index]
 9757                    && let Some(selection) = current_ranges.first()
 9758                {
 9759                    self.show_snippet_choices(choices, selection.clone(), cx);
 9760                }
 9761
 9762                // If snippet state is not at the last tabstop, push it back on the stack
 9763                if snippet.active_index + 1 < snippet.ranges.len() {
 9764                    self.snippet_stack.push(snippet);
 9765                }
 9766                return true;
 9767            }
 9768        }
 9769
 9770        false
 9771    }
 9772
 9773    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9774        self.transact(window, cx, |this, window, cx| {
 9775            this.select_all(&SelectAll, window, cx);
 9776            this.insert("", window, cx);
 9777        });
 9778    }
 9779
 9780    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9781        if self.read_only(cx) {
 9782            return;
 9783        }
 9784        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9785        self.transact(window, cx, |this, window, cx| {
 9786            this.select_autoclose_pair(window, cx);
 9787            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9788            if !this.linked_edit_ranges.is_empty() {
 9789                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9790                let snapshot = this.buffer.read(cx).snapshot(cx);
 9791
 9792                for selection in selections.iter() {
 9793                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9794                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9795                    if selection_start.buffer_id != selection_end.buffer_id {
 9796                        continue;
 9797                    }
 9798                    if let Some(ranges) =
 9799                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9800                    {
 9801                        for (buffer, entries) in ranges {
 9802                            linked_ranges.entry(buffer).or_default().extend(entries);
 9803                        }
 9804                    }
 9805                }
 9806            }
 9807
 9808            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9809            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9810            for selection in &mut selections {
 9811                if selection.is_empty() {
 9812                    let old_head = selection.head();
 9813                    let mut new_head =
 9814                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9815                            .to_point(&display_map);
 9816                    if let Some((buffer, line_buffer_range)) = display_map
 9817                        .buffer_snapshot
 9818                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9819                    {
 9820                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9821                        let indent_len = match indent_size.kind {
 9822                            IndentKind::Space => {
 9823                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9824                            }
 9825                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9826                        };
 9827                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9828                            let indent_len = indent_len.get();
 9829                            new_head = cmp::min(
 9830                                new_head,
 9831                                MultiBufferPoint::new(
 9832                                    old_head.row,
 9833                                    ((old_head.column - 1) / indent_len) * indent_len,
 9834                                ),
 9835                            );
 9836                        }
 9837                    }
 9838
 9839                    selection.set_head(new_head, SelectionGoal::None);
 9840                }
 9841            }
 9842
 9843            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9844            this.insert("", window, cx);
 9845            let empty_str: Arc<str> = Arc::from("");
 9846            for (buffer, edits) in linked_ranges {
 9847                let snapshot = buffer.read(cx).snapshot();
 9848                use text::ToPoint as TP;
 9849
 9850                let edits = edits
 9851                    .into_iter()
 9852                    .map(|range| {
 9853                        let end_point = TP::to_point(&range.end, &snapshot);
 9854                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9855
 9856                        if end_point == start_point {
 9857                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9858                                .saturating_sub(1);
 9859                            start_point =
 9860                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9861                        };
 9862
 9863                        (start_point..end_point, empty_str.clone())
 9864                    })
 9865                    .sorted_by_key(|(range, _)| range.start)
 9866                    .collect::<Vec<_>>();
 9867                buffer.update(cx, |this, cx| {
 9868                    this.edit(edits, None, cx);
 9869                })
 9870            }
 9871            this.refresh_edit_prediction(true, false, window, cx);
 9872            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9873        });
 9874    }
 9875
 9876    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9877        if self.read_only(cx) {
 9878            return;
 9879        }
 9880        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9881        self.transact(window, cx, |this, window, cx| {
 9882            this.change_selections(Default::default(), window, cx, |s| {
 9883                s.move_with(|map, selection| {
 9884                    if selection.is_empty() {
 9885                        let cursor = movement::right(map, selection.head());
 9886                        selection.end = cursor;
 9887                        selection.reversed = true;
 9888                        selection.goal = SelectionGoal::None;
 9889                    }
 9890                })
 9891            });
 9892            this.insert("", window, cx);
 9893            this.refresh_edit_prediction(true, false, window, cx);
 9894        });
 9895    }
 9896
 9897    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9898        if self.mode.is_single_line() {
 9899            cx.propagate();
 9900            return;
 9901        }
 9902
 9903        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9904        if self.move_to_prev_snippet_tabstop(window, cx) {
 9905            return;
 9906        }
 9907        self.outdent(&Outdent, window, cx);
 9908    }
 9909
 9910    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9911        if self.mode.is_single_line() {
 9912            cx.propagate();
 9913            return;
 9914        }
 9915
 9916        if self.move_to_next_snippet_tabstop(window, cx) {
 9917            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9918            return;
 9919        }
 9920        if self.read_only(cx) {
 9921            return;
 9922        }
 9923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9924        let mut selections = self.selections.all_adjusted(cx);
 9925        let buffer = self.buffer.read(cx);
 9926        let snapshot = buffer.snapshot(cx);
 9927        let rows_iter = selections.iter().map(|s| s.head().row);
 9928        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9929
 9930        let has_some_cursor_in_whitespace = selections
 9931            .iter()
 9932            .filter(|selection| selection.is_empty())
 9933            .any(|selection| {
 9934                let cursor = selection.head();
 9935                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9936                cursor.column < current_indent.len
 9937            });
 9938
 9939        let mut edits = Vec::new();
 9940        let mut prev_edited_row = 0;
 9941        let mut row_delta = 0;
 9942        for selection in &mut selections {
 9943            if selection.start.row != prev_edited_row {
 9944                row_delta = 0;
 9945            }
 9946            prev_edited_row = selection.end.row;
 9947
 9948            // If the selection is non-empty, then increase the indentation of the selected lines.
 9949            if !selection.is_empty() {
 9950                row_delta =
 9951                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9952                continue;
 9953            }
 9954
 9955            let cursor = selection.head();
 9956            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9957            if let Some(suggested_indent) =
 9958                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9959            {
 9960                // Don't do anything if already at suggested indent
 9961                // and there is any other cursor which is not
 9962                if has_some_cursor_in_whitespace
 9963                    && cursor.column == current_indent.len
 9964                    && current_indent.len == suggested_indent.len
 9965                {
 9966                    continue;
 9967                }
 9968
 9969                // Adjust line and move cursor to suggested indent
 9970                // if cursor is not at suggested indent
 9971                if cursor.column < suggested_indent.len
 9972                    && cursor.column <= current_indent.len
 9973                    && current_indent.len <= suggested_indent.len
 9974                {
 9975                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9976                    selection.end = selection.start;
 9977                    if row_delta == 0 {
 9978                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9979                            cursor.row,
 9980                            current_indent,
 9981                            suggested_indent,
 9982                        ));
 9983                        row_delta = suggested_indent.len - current_indent.len;
 9984                    }
 9985                    continue;
 9986                }
 9987
 9988                // If current indent is more than suggested indent
 9989                // only move cursor to current indent and skip indent
 9990                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9991                    selection.start = Point::new(cursor.row, current_indent.len);
 9992                    selection.end = selection.start;
 9993                    continue;
 9994                }
 9995            }
 9996
 9997            // Otherwise, insert a hard or soft tab.
 9998            let settings = buffer.language_settings_at(cursor, cx);
 9999            let tab_size = if settings.hard_tabs {
10000                IndentSize::tab()
10001            } else {
10002                let tab_size = settings.tab_size.get();
10003                let indent_remainder = snapshot
10004                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10005                    .flat_map(str::chars)
10006                    .fold(row_delta % tab_size, |counter: u32, c| {
10007                        if c == '\t' {
10008                            0
10009                        } else {
10010                            (counter + 1) % tab_size
10011                        }
10012                    });
10013
10014                let chars_to_next_tab_stop = tab_size - indent_remainder;
10015                IndentSize::spaces(chars_to_next_tab_stop)
10016            };
10017            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10018            selection.end = selection.start;
10019            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10020            row_delta += tab_size.len;
10021        }
10022
10023        self.transact(window, cx, |this, window, cx| {
10024            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10025            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10026            this.refresh_edit_prediction(true, false, window, cx);
10027        });
10028    }
10029
10030    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10031        if self.read_only(cx) {
10032            return;
10033        }
10034        if self.mode.is_single_line() {
10035            cx.propagate();
10036            return;
10037        }
10038
10039        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10040        let mut selections = self.selections.all::<Point>(cx);
10041        let mut prev_edited_row = 0;
10042        let mut row_delta = 0;
10043        let mut edits = Vec::new();
10044        let buffer = self.buffer.read(cx);
10045        let snapshot = buffer.snapshot(cx);
10046        for selection in &mut selections {
10047            if selection.start.row != prev_edited_row {
10048                row_delta = 0;
10049            }
10050            prev_edited_row = selection.end.row;
10051
10052            row_delta =
10053                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10054        }
10055
10056        self.transact(window, cx, |this, window, cx| {
10057            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10058            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10059        });
10060    }
10061
10062    fn indent_selection(
10063        buffer: &MultiBuffer,
10064        snapshot: &MultiBufferSnapshot,
10065        selection: &mut Selection<Point>,
10066        edits: &mut Vec<(Range<Point>, String)>,
10067        delta_for_start_row: u32,
10068        cx: &App,
10069    ) -> u32 {
10070        let settings = buffer.language_settings_at(selection.start, cx);
10071        let tab_size = settings.tab_size.get();
10072        let indent_kind = if settings.hard_tabs {
10073            IndentKind::Tab
10074        } else {
10075            IndentKind::Space
10076        };
10077        let mut start_row = selection.start.row;
10078        let mut end_row = selection.end.row + 1;
10079
10080        // If a selection ends at the beginning of a line, don't indent
10081        // that last line.
10082        if selection.end.column == 0 && selection.end.row > selection.start.row {
10083            end_row -= 1;
10084        }
10085
10086        // Avoid re-indenting a row that has already been indented by a
10087        // previous selection, but still update this selection's column
10088        // to reflect that indentation.
10089        if delta_for_start_row > 0 {
10090            start_row += 1;
10091            selection.start.column += delta_for_start_row;
10092            if selection.end.row == selection.start.row {
10093                selection.end.column += delta_for_start_row;
10094            }
10095        }
10096
10097        let mut delta_for_end_row = 0;
10098        let has_multiple_rows = start_row + 1 != end_row;
10099        for row in start_row..end_row {
10100            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10101            let indent_delta = match (current_indent.kind, indent_kind) {
10102                (IndentKind::Space, IndentKind::Space) => {
10103                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10104                    IndentSize::spaces(columns_to_next_tab_stop)
10105                }
10106                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10107                (_, IndentKind::Tab) => IndentSize::tab(),
10108            };
10109
10110            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10111                0
10112            } else {
10113                selection.start.column
10114            };
10115            let row_start = Point::new(row, start);
10116            edits.push((
10117                row_start..row_start,
10118                indent_delta.chars().collect::<String>(),
10119            ));
10120
10121            // Update this selection's endpoints to reflect the indentation.
10122            if row == selection.start.row {
10123                selection.start.column += indent_delta.len;
10124            }
10125            if row == selection.end.row {
10126                selection.end.column += indent_delta.len;
10127                delta_for_end_row = indent_delta.len;
10128            }
10129        }
10130
10131        if selection.start.row == selection.end.row {
10132            delta_for_start_row + delta_for_end_row
10133        } else {
10134            delta_for_end_row
10135        }
10136    }
10137
10138    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10139        if self.read_only(cx) {
10140            return;
10141        }
10142        if self.mode.is_single_line() {
10143            cx.propagate();
10144            return;
10145        }
10146
10147        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10148        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10149        let selections = self.selections.all::<Point>(cx);
10150        let mut deletion_ranges = Vec::new();
10151        let mut last_outdent = None;
10152        {
10153            let buffer = self.buffer.read(cx);
10154            let snapshot = buffer.snapshot(cx);
10155            for selection in &selections {
10156                let settings = buffer.language_settings_at(selection.start, cx);
10157                let tab_size = settings.tab_size.get();
10158                let mut rows = selection.spanned_rows(false, &display_map);
10159
10160                // Avoid re-outdenting a row that has already been outdented by a
10161                // previous selection.
10162                if let Some(last_row) = last_outdent
10163                    && last_row == rows.start
10164                {
10165                    rows.start = rows.start.next_row();
10166                }
10167                let has_multiple_rows = rows.len() > 1;
10168                for row in rows.iter_rows() {
10169                    let indent_size = snapshot.indent_size_for_line(row);
10170                    if indent_size.len > 0 {
10171                        let deletion_len = match indent_size.kind {
10172                            IndentKind::Space => {
10173                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10174                                if columns_to_prev_tab_stop == 0 {
10175                                    tab_size
10176                                } else {
10177                                    columns_to_prev_tab_stop
10178                                }
10179                            }
10180                            IndentKind::Tab => 1,
10181                        };
10182                        let start = if has_multiple_rows
10183                            || deletion_len > selection.start.column
10184                            || indent_size.len < selection.start.column
10185                        {
10186                            0
10187                        } else {
10188                            selection.start.column - deletion_len
10189                        };
10190                        deletion_ranges.push(
10191                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10192                        );
10193                        last_outdent = Some(row);
10194                    }
10195                }
10196            }
10197        }
10198
10199        self.transact(window, cx, |this, window, cx| {
10200            this.buffer.update(cx, |buffer, cx| {
10201                let empty_str: Arc<str> = Arc::default();
10202                buffer.edit(
10203                    deletion_ranges
10204                        .into_iter()
10205                        .map(|range| (range, empty_str.clone())),
10206                    None,
10207                    cx,
10208                );
10209            });
10210            let selections = this.selections.all::<usize>(cx);
10211            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10212        });
10213    }
10214
10215    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10216        if self.read_only(cx) {
10217            return;
10218        }
10219        if self.mode.is_single_line() {
10220            cx.propagate();
10221            return;
10222        }
10223
10224        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10225        let selections = self
10226            .selections
10227            .all::<usize>(cx)
10228            .into_iter()
10229            .map(|s| s.range());
10230
10231        self.transact(window, cx, |this, window, cx| {
10232            this.buffer.update(cx, |buffer, cx| {
10233                buffer.autoindent_ranges(selections, cx);
10234            });
10235            let selections = this.selections.all::<usize>(cx);
10236            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10237        });
10238    }
10239
10240    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10241        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10242        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10243        let selections = self.selections.all::<Point>(cx);
10244
10245        let mut new_cursors = Vec::new();
10246        let mut edit_ranges = Vec::new();
10247        let mut selections = selections.iter().peekable();
10248        while let Some(selection) = selections.next() {
10249            let mut rows = selection.spanned_rows(false, &display_map);
10250            let goal_display_column = selection.head().to_display_point(&display_map).column();
10251
10252            // Accumulate contiguous regions of rows that we want to delete.
10253            while let Some(next_selection) = selections.peek() {
10254                let next_rows = next_selection.spanned_rows(false, &display_map);
10255                if next_rows.start <= rows.end {
10256                    rows.end = next_rows.end;
10257                    selections.next().unwrap();
10258                } else {
10259                    break;
10260                }
10261            }
10262
10263            let buffer = &display_map.buffer_snapshot;
10264            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10265            let edit_end;
10266            let cursor_buffer_row;
10267            if buffer.max_point().row >= rows.end.0 {
10268                // If there's a line after the range, delete the \n from the end of the row range
10269                // and position the cursor on the next line.
10270                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10271                cursor_buffer_row = rows.end;
10272            } else {
10273                // If there isn't a line after the range, delete the \n from the line before the
10274                // start of the row range and position the cursor there.
10275                edit_start = edit_start.saturating_sub(1);
10276                edit_end = buffer.len();
10277                cursor_buffer_row = rows.start.previous_row();
10278            }
10279
10280            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10281            *cursor.column_mut() =
10282                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10283
10284            new_cursors.push((
10285                selection.id,
10286                buffer.anchor_after(cursor.to_point(&display_map)),
10287            ));
10288            edit_ranges.push(edit_start..edit_end);
10289        }
10290
10291        self.transact(window, cx, |this, window, cx| {
10292            let buffer = this.buffer.update(cx, |buffer, cx| {
10293                let empty_str: Arc<str> = Arc::default();
10294                buffer.edit(
10295                    edit_ranges
10296                        .into_iter()
10297                        .map(|range| (range, empty_str.clone())),
10298                    None,
10299                    cx,
10300                );
10301                buffer.snapshot(cx)
10302            });
10303            let new_selections = new_cursors
10304                .into_iter()
10305                .map(|(id, cursor)| {
10306                    let cursor = cursor.to_point(&buffer);
10307                    Selection {
10308                        id,
10309                        start: cursor,
10310                        end: cursor,
10311                        reversed: false,
10312                        goal: SelectionGoal::None,
10313                    }
10314                })
10315                .collect();
10316
10317            this.change_selections(Default::default(), window, cx, |s| {
10318                s.select(new_selections);
10319            });
10320        });
10321    }
10322
10323    pub fn join_lines_impl(
10324        &mut self,
10325        insert_whitespace: bool,
10326        window: &mut Window,
10327        cx: &mut Context<Self>,
10328    ) {
10329        if self.read_only(cx) {
10330            return;
10331        }
10332        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10333        for selection in self.selections.all::<Point>(cx) {
10334            let start = MultiBufferRow(selection.start.row);
10335            // Treat single line selections as if they include the next line. Otherwise this action
10336            // would do nothing for single line selections individual cursors.
10337            let end = if selection.start.row == selection.end.row {
10338                MultiBufferRow(selection.start.row + 1)
10339            } else {
10340                MultiBufferRow(selection.end.row)
10341            };
10342
10343            if let Some(last_row_range) = row_ranges.last_mut()
10344                && start <= last_row_range.end
10345            {
10346                last_row_range.end = end;
10347                continue;
10348            }
10349            row_ranges.push(start..end);
10350        }
10351
10352        let snapshot = self.buffer.read(cx).snapshot(cx);
10353        let mut cursor_positions = Vec::new();
10354        for row_range in &row_ranges {
10355            let anchor = snapshot.anchor_before(Point::new(
10356                row_range.end.previous_row().0,
10357                snapshot.line_len(row_range.end.previous_row()),
10358            ));
10359            cursor_positions.push(anchor..anchor);
10360        }
10361
10362        self.transact(window, cx, |this, window, cx| {
10363            for row_range in row_ranges.into_iter().rev() {
10364                for row in row_range.iter_rows().rev() {
10365                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10366                    let next_line_row = row.next_row();
10367                    let indent = snapshot.indent_size_for_line(next_line_row);
10368                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10369
10370                    let replace =
10371                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10372                            " "
10373                        } else {
10374                            ""
10375                        };
10376
10377                    this.buffer.update(cx, |buffer, cx| {
10378                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10379                    });
10380                }
10381            }
10382
10383            this.change_selections(Default::default(), window, cx, |s| {
10384                s.select_anchor_ranges(cursor_positions)
10385            });
10386        });
10387    }
10388
10389    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10390        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10391        self.join_lines_impl(true, window, cx);
10392    }
10393
10394    pub fn sort_lines_case_sensitive(
10395        &mut self,
10396        _: &SortLinesCaseSensitive,
10397        window: &mut Window,
10398        cx: &mut Context<Self>,
10399    ) {
10400        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10401    }
10402
10403    pub fn sort_lines_by_length(
10404        &mut self,
10405        _: &SortLinesByLength,
10406        window: &mut Window,
10407        cx: &mut Context<Self>,
10408    ) {
10409        self.manipulate_immutable_lines(window, cx, |lines| {
10410            lines.sort_by_key(|&line| line.chars().count())
10411        })
10412    }
10413
10414    pub fn sort_lines_case_insensitive(
10415        &mut self,
10416        _: &SortLinesCaseInsensitive,
10417        window: &mut Window,
10418        cx: &mut Context<Self>,
10419    ) {
10420        self.manipulate_immutable_lines(window, cx, |lines| {
10421            lines.sort_by_key(|line| line.to_lowercase())
10422        })
10423    }
10424
10425    pub fn unique_lines_case_insensitive(
10426        &mut self,
10427        _: &UniqueLinesCaseInsensitive,
10428        window: &mut Window,
10429        cx: &mut Context<Self>,
10430    ) {
10431        self.manipulate_immutable_lines(window, cx, |lines| {
10432            let mut seen = HashSet::default();
10433            lines.retain(|line| seen.insert(line.to_lowercase()));
10434        })
10435    }
10436
10437    pub fn unique_lines_case_sensitive(
10438        &mut self,
10439        _: &UniqueLinesCaseSensitive,
10440        window: &mut Window,
10441        cx: &mut Context<Self>,
10442    ) {
10443        self.manipulate_immutable_lines(window, cx, |lines| {
10444            let mut seen = HashSet::default();
10445            lines.retain(|line| seen.insert(*line));
10446        })
10447    }
10448
10449    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10450        let snapshot = self.buffer.read(cx).snapshot(cx);
10451        for selection in self.selections.disjoint_anchors().iter() {
10452            if snapshot
10453                .language_at(selection.start)
10454                .and_then(|lang| lang.config().wrap_characters.as_ref())
10455                .is_some()
10456            {
10457                return true;
10458            }
10459        }
10460        false
10461    }
10462
10463    fn wrap_selections_in_tag(
10464        &mut self,
10465        _: &WrapSelectionsInTag,
10466        window: &mut Window,
10467        cx: &mut Context<Self>,
10468    ) {
10469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10470
10471        let snapshot = self.buffer.read(cx).snapshot(cx);
10472
10473        let mut edits = Vec::new();
10474        let mut boundaries = Vec::new();
10475
10476        for selection in self.selections.all::<Point>(cx).iter() {
10477            let Some(wrap_config) = snapshot
10478                .language_at(selection.start)
10479                .and_then(|lang| lang.config().wrap_characters.clone())
10480            else {
10481                continue;
10482            };
10483
10484            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10485            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10486
10487            let start_before = snapshot.anchor_before(selection.start);
10488            let end_after = snapshot.anchor_after(selection.end);
10489
10490            edits.push((start_before..start_before, open_tag));
10491            edits.push((end_after..end_after, close_tag));
10492
10493            boundaries.push((
10494                start_before,
10495                end_after,
10496                wrap_config.start_prefix.len(),
10497                wrap_config.end_suffix.len(),
10498            ));
10499        }
10500
10501        if edits.is_empty() {
10502            return;
10503        }
10504
10505        self.transact(window, cx, |this, window, cx| {
10506            let buffer = this.buffer.update(cx, |buffer, cx| {
10507                buffer.edit(edits, None, cx);
10508                buffer.snapshot(cx)
10509            });
10510
10511            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10512            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10513                boundaries.into_iter()
10514            {
10515                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10516                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10517                new_selections.push(open_offset..open_offset);
10518                new_selections.push(close_offset..close_offset);
10519            }
10520
10521            this.change_selections(Default::default(), window, cx, |s| {
10522                s.select_ranges(new_selections);
10523            });
10524
10525            this.request_autoscroll(Autoscroll::fit(), cx);
10526        });
10527    }
10528
10529    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10530        let Some(project) = self.project.clone() else {
10531            return;
10532        };
10533        self.reload(project, window, cx)
10534            .detach_and_notify_err(window, cx);
10535    }
10536
10537    pub fn restore_file(
10538        &mut self,
10539        _: &::git::RestoreFile,
10540        window: &mut Window,
10541        cx: &mut Context<Self>,
10542    ) {
10543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10544        let mut buffer_ids = HashSet::default();
10545        let snapshot = self.buffer().read(cx).snapshot(cx);
10546        for selection in self.selections.all::<usize>(cx) {
10547            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10548        }
10549
10550        let buffer = self.buffer().read(cx);
10551        let ranges = buffer_ids
10552            .into_iter()
10553            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10554            .collect::<Vec<_>>();
10555
10556        self.restore_hunks_in_ranges(ranges, window, cx);
10557    }
10558
10559    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10560        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10561        let selections = self
10562            .selections
10563            .all(cx)
10564            .into_iter()
10565            .map(|s| s.range())
10566            .collect();
10567        self.restore_hunks_in_ranges(selections, window, cx);
10568    }
10569
10570    pub fn restore_hunks_in_ranges(
10571        &mut self,
10572        ranges: Vec<Range<Point>>,
10573        window: &mut Window,
10574        cx: &mut Context<Editor>,
10575    ) {
10576        let mut revert_changes = HashMap::default();
10577        let chunk_by = self
10578            .snapshot(window, cx)
10579            .hunks_for_ranges(ranges)
10580            .into_iter()
10581            .chunk_by(|hunk| hunk.buffer_id);
10582        for (buffer_id, hunks) in &chunk_by {
10583            let hunks = hunks.collect::<Vec<_>>();
10584            for hunk in &hunks {
10585                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10586            }
10587            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10588        }
10589        drop(chunk_by);
10590        if !revert_changes.is_empty() {
10591            self.transact(window, cx, |editor, window, cx| {
10592                editor.restore(revert_changes, window, cx);
10593            });
10594        }
10595    }
10596
10597    pub fn open_active_item_in_terminal(
10598        &mut self,
10599        _: &OpenInTerminal,
10600        window: &mut Window,
10601        cx: &mut Context<Self>,
10602    ) {
10603        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10604            let project_path = buffer.read(cx).project_path(cx)?;
10605            let project = self.project()?.read(cx);
10606            let entry = project.entry_for_path(&project_path, cx)?;
10607            let parent = match &entry.canonical_path {
10608                Some(canonical_path) => canonical_path.to_path_buf(),
10609                None => project.absolute_path(&project_path, cx)?,
10610            }
10611            .parent()?
10612            .to_path_buf();
10613            Some(parent)
10614        }) {
10615            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10616        }
10617    }
10618
10619    fn set_breakpoint_context_menu(
10620        &mut self,
10621        display_row: DisplayRow,
10622        position: Option<Anchor>,
10623        clicked_point: gpui::Point<Pixels>,
10624        window: &mut Window,
10625        cx: &mut Context<Self>,
10626    ) {
10627        let source = self
10628            .buffer
10629            .read(cx)
10630            .snapshot(cx)
10631            .anchor_before(Point::new(display_row.0, 0u32));
10632
10633        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10634
10635        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10636            self,
10637            source,
10638            clicked_point,
10639            context_menu,
10640            window,
10641            cx,
10642        );
10643    }
10644
10645    fn add_edit_breakpoint_block(
10646        &mut self,
10647        anchor: Anchor,
10648        breakpoint: &Breakpoint,
10649        edit_action: BreakpointPromptEditAction,
10650        window: &mut Window,
10651        cx: &mut Context<Self>,
10652    ) {
10653        let weak_editor = cx.weak_entity();
10654        let bp_prompt = cx.new(|cx| {
10655            BreakpointPromptEditor::new(
10656                weak_editor,
10657                anchor,
10658                breakpoint.clone(),
10659                edit_action,
10660                window,
10661                cx,
10662            )
10663        });
10664
10665        let height = bp_prompt.update(cx, |this, cx| {
10666            this.prompt
10667                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10668        });
10669        let cloned_prompt = bp_prompt.clone();
10670        let blocks = vec![BlockProperties {
10671            style: BlockStyle::Sticky,
10672            placement: BlockPlacement::Above(anchor),
10673            height: Some(height),
10674            render: Arc::new(move |cx| {
10675                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10676                cloned_prompt.clone().into_any_element()
10677            }),
10678            priority: 0,
10679        }];
10680
10681        let focus_handle = bp_prompt.focus_handle(cx);
10682        window.focus(&focus_handle);
10683
10684        let block_ids = self.insert_blocks(blocks, None, cx);
10685        bp_prompt.update(cx, |prompt, _| {
10686            prompt.add_block_ids(block_ids);
10687        });
10688    }
10689
10690    pub(crate) fn breakpoint_at_row(
10691        &self,
10692        row: u32,
10693        window: &mut Window,
10694        cx: &mut Context<Self>,
10695    ) -> Option<(Anchor, Breakpoint)> {
10696        let snapshot = self.snapshot(window, cx);
10697        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10698
10699        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10700    }
10701
10702    pub(crate) fn breakpoint_at_anchor(
10703        &self,
10704        breakpoint_position: Anchor,
10705        snapshot: &EditorSnapshot,
10706        cx: &mut Context<Self>,
10707    ) -> Option<(Anchor, Breakpoint)> {
10708        let buffer = self
10709            .buffer
10710            .read(cx)
10711            .buffer_for_anchor(breakpoint_position, cx)?;
10712
10713        let enclosing_excerpt = breakpoint_position.excerpt_id;
10714        let buffer_snapshot = buffer.read(cx).snapshot();
10715
10716        let row = buffer_snapshot
10717            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10718            .row;
10719
10720        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10721        let anchor_end = snapshot
10722            .buffer_snapshot
10723            .anchor_after(Point::new(row, line_len));
10724
10725        self.breakpoint_store
10726            .as_ref()?
10727            .read_with(cx, |breakpoint_store, cx| {
10728                breakpoint_store
10729                    .breakpoints(
10730                        &buffer,
10731                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10732                        &buffer_snapshot,
10733                        cx,
10734                    )
10735                    .next()
10736                    .and_then(|(bp, _)| {
10737                        let breakpoint_row = buffer_snapshot
10738                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10739                            .row;
10740
10741                        if breakpoint_row == row {
10742                            snapshot
10743                                .buffer_snapshot
10744                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10745                                .map(|position| (position, bp.bp.clone()))
10746                        } else {
10747                            None
10748                        }
10749                    })
10750            })
10751    }
10752
10753    pub fn edit_log_breakpoint(
10754        &mut self,
10755        _: &EditLogBreakpoint,
10756        window: &mut Window,
10757        cx: &mut Context<Self>,
10758    ) {
10759        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10760            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10761                message: None,
10762                state: BreakpointState::Enabled,
10763                condition: None,
10764                hit_condition: None,
10765            });
10766
10767            self.add_edit_breakpoint_block(
10768                anchor,
10769                &breakpoint,
10770                BreakpointPromptEditAction::Log,
10771                window,
10772                cx,
10773            );
10774        }
10775    }
10776
10777    fn breakpoints_at_cursors(
10778        &self,
10779        window: &mut Window,
10780        cx: &mut Context<Self>,
10781    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10782        let snapshot = self.snapshot(window, cx);
10783        let cursors = self
10784            .selections
10785            .disjoint_anchors()
10786            .iter()
10787            .map(|selection| {
10788                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10789
10790                let breakpoint_position = self
10791                    .breakpoint_at_row(cursor_position.row, window, cx)
10792                    .map(|bp| bp.0)
10793                    .unwrap_or_else(|| {
10794                        snapshot
10795                            .display_snapshot
10796                            .buffer_snapshot
10797                            .anchor_after(Point::new(cursor_position.row, 0))
10798                    });
10799
10800                let breakpoint = self
10801                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10802                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10803
10804                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10805            })
10806            // 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.
10807            .collect::<HashMap<Anchor, _>>();
10808
10809        cursors.into_iter().collect()
10810    }
10811
10812    pub fn enable_breakpoint(
10813        &mut self,
10814        _: &crate::actions::EnableBreakpoint,
10815        window: &mut Window,
10816        cx: &mut Context<Self>,
10817    ) {
10818        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10819            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10820                continue;
10821            };
10822            self.edit_breakpoint_at_anchor(
10823                anchor,
10824                breakpoint,
10825                BreakpointEditAction::InvertState,
10826                cx,
10827            );
10828        }
10829    }
10830
10831    pub fn disable_breakpoint(
10832        &mut self,
10833        _: &crate::actions::DisableBreakpoint,
10834        window: &mut Window,
10835        cx: &mut Context<Self>,
10836    ) {
10837        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10838            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10839                continue;
10840            };
10841            self.edit_breakpoint_at_anchor(
10842                anchor,
10843                breakpoint,
10844                BreakpointEditAction::InvertState,
10845                cx,
10846            );
10847        }
10848    }
10849
10850    pub fn toggle_breakpoint(
10851        &mut self,
10852        _: &crate::actions::ToggleBreakpoint,
10853        window: &mut Window,
10854        cx: &mut Context<Self>,
10855    ) {
10856        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10857            if let Some(breakpoint) = breakpoint {
10858                self.edit_breakpoint_at_anchor(
10859                    anchor,
10860                    breakpoint,
10861                    BreakpointEditAction::Toggle,
10862                    cx,
10863                );
10864            } else {
10865                self.edit_breakpoint_at_anchor(
10866                    anchor,
10867                    Breakpoint::new_standard(),
10868                    BreakpointEditAction::Toggle,
10869                    cx,
10870                );
10871            }
10872        }
10873    }
10874
10875    pub fn edit_breakpoint_at_anchor(
10876        &mut self,
10877        breakpoint_position: Anchor,
10878        breakpoint: Breakpoint,
10879        edit_action: BreakpointEditAction,
10880        cx: &mut Context<Self>,
10881    ) {
10882        let Some(breakpoint_store) = &self.breakpoint_store else {
10883            return;
10884        };
10885
10886        let Some(buffer) = self
10887            .buffer
10888            .read(cx)
10889            .buffer_for_anchor(breakpoint_position, cx)
10890        else {
10891            return;
10892        };
10893
10894        breakpoint_store.update(cx, |breakpoint_store, cx| {
10895            breakpoint_store.toggle_breakpoint(
10896                buffer,
10897                BreakpointWithPosition {
10898                    position: breakpoint_position.text_anchor,
10899                    bp: breakpoint,
10900                },
10901                edit_action,
10902                cx,
10903            );
10904        });
10905
10906        cx.notify();
10907    }
10908
10909    #[cfg(any(test, feature = "test-support"))]
10910    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10911        self.breakpoint_store.clone()
10912    }
10913
10914    pub fn prepare_restore_change(
10915        &self,
10916        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10917        hunk: &MultiBufferDiffHunk,
10918        cx: &mut App,
10919    ) -> Option<()> {
10920        if hunk.is_created_file() {
10921            return None;
10922        }
10923        let buffer = self.buffer.read(cx);
10924        let diff = buffer.diff_for(hunk.buffer_id)?;
10925        let buffer = buffer.buffer(hunk.buffer_id)?;
10926        let buffer = buffer.read(cx);
10927        let original_text = diff
10928            .read(cx)
10929            .base_text()
10930            .as_rope()
10931            .slice(hunk.diff_base_byte_range.clone());
10932        let buffer_snapshot = buffer.snapshot();
10933        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10934        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10935            probe
10936                .0
10937                .start
10938                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10939                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10940        }) {
10941            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10942            Some(())
10943        } else {
10944            None
10945        }
10946    }
10947
10948    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10949        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10950    }
10951
10952    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10953        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10954    }
10955
10956    fn manipulate_lines<M>(
10957        &mut self,
10958        window: &mut Window,
10959        cx: &mut Context<Self>,
10960        mut manipulate: M,
10961    ) where
10962        M: FnMut(&str) -> LineManipulationResult,
10963    {
10964        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10965
10966        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10967        let buffer = self.buffer.read(cx).snapshot(cx);
10968
10969        let mut edits = Vec::new();
10970
10971        let selections = self.selections.all::<Point>(cx);
10972        let mut selections = selections.iter().peekable();
10973        let mut contiguous_row_selections = Vec::new();
10974        let mut new_selections = Vec::new();
10975        let mut added_lines = 0;
10976        let mut removed_lines = 0;
10977
10978        while let Some(selection) = selections.next() {
10979            let (start_row, end_row) = consume_contiguous_rows(
10980                &mut contiguous_row_selections,
10981                selection,
10982                &display_map,
10983                &mut selections,
10984            );
10985
10986            let start_point = Point::new(start_row.0, 0);
10987            let end_point = Point::new(
10988                end_row.previous_row().0,
10989                buffer.line_len(end_row.previous_row()),
10990            );
10991            let text = buffer
10992                .text_for_range(start_point..end_point)
10993                .collect::<String>();
10994
10995            let LineManipulationResult {
10996                new_text,
10997                line_count_before,
10998                line_count_after,
10999            } = manipulate(&text);
11000
11001            edits.push((start_point..end_point, new_text));
11002
11003            // Selections must change based on added and removed line count
11004            let start_row =
11005                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11006            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11007            new_selections.push(Selection {
11008                id: selection.id,
11009                start: start_row,
11010                end: end_row,
11011                goal: SelectionGoal::None,
11012                reversed: selection.reversed,
11013            });
11014
11015            if line_count_after > line_count_before {
11016                added_lines += line_count_after - line_count_before;
11017            } else if line_count_before > line_count_after {
11018                removed_lines += line_count_before - line_count_after;
11019            }
11020        }
11021
11022        self.transact(window, cx, |this, window, cx| {
11023            let buffer = this.buffer.update(cx, |buffer, cx| {
11024                buffer.edit(edits, None, cx);
11025                buffer.snapshot(cx)
11026            });
11027
11028            // Recalculate offsets on newly edited buffer
11029            let new_selections = new_selections
11030                .iter()
11031                .map(|s| {
11032                    let start_point = Point::new(s.start.0, 0);
11033                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11034                    Selection {
11035                        id: s.id,
11036                        start: buffer.point_to_offset(start_point),
11037                        end: buffer.point_to_offset(end_point),
11038                        goal: s.goal,
11039                        reversed: s.reversed,
11040                    }
11041                })
11042                .collect();
11043
11044            this.change_selections(Default::default(), window, cx, |s| {
11045                s.select(new_selections);
11046            });
11047
11048            this.request_autoscroll(Autoscroll::fit(), cx);
11049        });
11050    }
11051
11052    fn manipulate_immutable_lines<Fn>(
11053        &mut self,
11054        window: &mut Window,
11055        cx: &mut Context<Self>,
11056        mut callback: Fn,
11057    ) where
11058        Fn: FnMut(&mut Vec<&str>),
11059    {
11060        self.manipulate_lines(window, cx, |text| {
11061            let mut lines: Vec<&str> = text.split('\n').collect();
11062            let line_count_before = lines.len();
11063
11064            callback(&mut lines);
11065
11066            LineManipulationResult {
11067                new_text: lines.join("\n"),
11068                line_count_before,
11069                line_count_after: lines.len(),
11070            }
11071        });
11072    }
11073
11074    fn manipulate_mutable_lines<Fn>(
11075        &mut self,
11076        window: &mut Window,
11077        cx: &mut Context<Self>,
11078        mut callback: Fn,
11079    ) where
11080        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11081    {
11082        self.manipulate_lines(window, cx, |text| {
11083            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11084            let line_count_before = lines.len();
11085
11086            callback(&mut lines);
11087
11088            LineManipulationResult {
11089                new_text: lines.join("\n"),
11090                line_count_before,
11091                line_count_after: lines.len(),
11092            }
11093        });
11094    }
11095
11096    pub fn convert_indentation_to_spaces(
11097        &mut self,
11098        _: &ConvertIndentationToSpaces,
11099        window: &mut Window,
11100        cx: &mut Context<Self>,
11101    ) {
11102        let settings = self.buffer.read(cx).language_settings(cx);
11103        let tab_size = settings.tab_size.get() as usize;
11104
11105        self.manipulate_mutable_lines(window, cx, |lines| {
11106            // Allocates a reasonably sized scratch buffer once for the whole loop
11107            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11108            // Avoids recomputing spaces that could be inserted many times
11109            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11110                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11111                .collect();
11112
11113            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11114                let mut chars = line.as_ref().chars();
11115                let mut col = 0;
11116                let mut changed = false;
11117
11118                for ch in chars.by_ref() {
11119                    match ch {
11120                        ' ' => {
11121                            reindented_line.push(' ');
11122                            col += 1;
11123                        }
11124                        '\t' => {
11125                            // \t are converted to spaces depending on the current column
11126                            let spaces_len = tab_size - (col % tab_size);
11127                            reindented_line.extend(&space_cache[spaces_len - 1]);
11128                            col += spaces_len;
11129                            changed = true;
11130                        }
11131                        _ => {
11132                            // If we dont append before break, the character is consumed
11133                            reindented_line.push(ch);
11134                            break;
11135                        }
11136                    }
11137                }
11138
11139                if !changed {
11140                    reindented_line.clear();
11141                    continue;
11142                }
11143                // Append the rest of the line and replace old reference with new one
11144                reindented_line.extend(chars);
11145                *line = Cow::Owned(reindented_line.clone());
11146                reindented_line.clear();
11147            }
11148        });
11149    }
11150
11151    pub fn convert_indentation_to_tabs(
11152        &mut self,
11153        _: &ConvertIndentationToTabs,
11154        window: &mut Window,
11155        cx: &mut Context<Self>,
11156    ) {
11157        let settings = self.buffer.read(cx).language_settings(cx);
11158        let tab_size = settings.tab_size.get() as usize;
11159
11160        self.manipulate_mutable_lines(window, cx, |lines| {
11161            // Allocates a reasonably sized buffer once for the whole loop
11162            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11163            // Avoids recomputing spaces that could be inserted many times
11164            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11165                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11166                .collect();
11167
11168            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11169                let mut chars = line.chars();
11170                let mut spaces_count = 0;
11171                let mut first_non_indent_char = None;
11172                let mut changed = false;
11173
11174                for ch in chars.by_ref() {
11175                    match ch {
11176                        ' ' => {
11177                            // Keep track of spaces. Append \t when we reach tab_size
11178                            spaces_count += 1;
11179                            changed = true;
11180                            if spaces_count == tab_size {
11181                                reindented_line.push('\t');
11182                                spaces_count = 0;
11183                            }
11184                        }
11185                        '\t' => {
11186                            reindented_line.push('\t');
11187                            spaces_count = 0;
11188                        }
11189                        _ => {
11190                            // Dont append it yet, we might have remaining spaces
11191                            first_non_indent_char = Some(ch);
11192                            break;
11193                        }
11194                    }
11195                }
11196
11197                if !changed {
11198                    reindented_line.clear();
11199                    continue;
11200                }
11201                // Remaining spaces that didn't make a full tab stop
11202                if spaces_count > 0 {
11203                    reindented_line.extend(&space_cache[spaces_count - 1]);
11204                }
11205                // If we consume an extra character that was not indentation, add it back
11206                if let Some(extra_char) = first_non_indent_char {
11207                    reindented_line.push(extra_char);
11208                }
11209                // Append the rest of the line and replace old reference with new one
11210                reindented_line.extend(chars);
11211                *line = Cow::Owned(reindented_line.clone());
11212                reindented_line.clear();
11213            }
11214        });
11215    }
11216
11217    pub fn convert_to_upper_case(
11218        &mut self,
11219        _: &ConvertToUpperCase,
11220        window: &mut Window,
11221        cx: &mut Context<Self>,
11222    ) {
11223        self.manipulate_text(window, cx, |text| text.to_uppercase())
11224    }
11225
11226    pub fn convert_to_lower_case(
11227        &mut self,
11228        _: &ConvertToLowerCase,
11229        window: &mut Window,
11230        cx: &mut Context<Self>,
11231    ) {
11232        self.manipulate_text(window, cx, |text| text.to_lowercase())
11233    }
11234
11235    pub fn convert_to_title_case(
11236        &mut self,
11237        _: &ConvertToTitleCase,
11238        window: &mut Window,
11239        cx: &mut Context<Self>,
11240    ) {
11241        self.manipulate_text(window, cx, |text| {
11242            text.split('\n')
11243                .map(|line| line.to_case(Case::Title))
11244                .join("\n")
11245        })
11246    }
11247
11248    pub fn convert_to_snake_case(
11249        &mut self,
11250        _: &ConvertToSnakeCase,
11251        window: &mut Window,
11252        cx: &mut Context<Self>,
11253    ) {
11254        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11255    }
11256
11257    pub fn convert_to_kebab_case(
11258        &mut self,
11259        _: &ConvertToKebabCase,
11260        window: &mut Window,
11261        cx: &mut Context<Self>,
11262    ) {
11263        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11264    }
11265
11266    pub fn convert_to_upper_camel_case(
11267        &mut self,
11268        _: &ConvertToUpperCamelCase,
11269        window: &mut Window,
11270        cx: &mut Context<Self>,
11271    ) {
11272        self.manipulate_text(window, cx, |text| {
11273            text.split('\n')
11274                .map(|line| line.to_case(Case::UpperCamel))
11275                .join("\n")
11276        })
11277    }
11278
11279    pub fn convert_to_lower_camel_case(
11280        &mut self,
11281        _: &ConvertToLowerCamelCase,
11282        window: &mut Window,
11283        cx: &mut Context<Self>,
11284    ) {
11285        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11286    }
11287
11288    pub fn convert_to_opposite_case(
11289        &mut self,
11290        _: &ConvertToOppositeCase,
11291        window: &mut Window,
11292        cx: &mut Context<Self>,
11293    ) {
11294        self.manipulate_text(window, cx, |text| {
11295            text.chars()
11296                .fold(String::with_capacity(text.len()), |mut t, c| {
11297                    if c.is_uppercase() {
11298                        t.extend(c.to_lowercase());
11299                    } else {
11300                        t.extend(c.to_uppercase());
11301                    }
11302                    t
11303                })
11304        })
11305    }
11306
11307    pub fn convert_to_sentence_case(
11308        &mut self,
11309        _: &ConvertToSentenceCase,
11310        window: &mut Window,
11311        cx: &mut Context<Self>,
11312    ) {
11313        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11314    }
11315
11316    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11317        self.manipulate_text(window, cx, |text| {
11318            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11319            if has_upper_case_characters {
11320                text.to_lowercase()
11321            } else {
11322                text.to_uppercase()
11323            }
11324        })
11325    }
11326
11327    pub fn convert_to_rot13(
11328        &mut self,
11329        _: &ConvertToRot13,
11330        window: &mut Window,
11331        cx: &mut Context<Self>,
11332    ) {
11333        self.manipulate_text(window, cx, |text| {
11334            text.chars()
11335                .map(|c| match c {
11336                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11337                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11338                    _ => c,
11339                })
11340                .collect()
11341        })
11342    }
11343
11344    pub fn convert_to_rot47(
11345        &mut self,
11346        _: &ConvertToRot47,
11347        window: &mut Window,
11348        cx: &mut Context<Self>,
11349    ) {
11350        self.manipulate_text(window, cx, |text| {
11351            text.chars()
11352                .map(|c| {
11353                    let code_point = c as u32;
11354                    if code_point >= 33 && code_point <= 126 {
11355                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11356                    }
11357                    c
11358                })
11359                .collect()
11360        })
11361    }
11362
11363    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11364    where
11365        Fn: FnMut(&str) -> String,
11366    {
11367        let buffer = self.buffer.read(cx).snapshot(cx);
11368
11369        let mut new_selections = Vec::new();
11370        let mut edits = Vec::new();
11371        let mut selection_adjustment = 0i32;
11372
11373        for selection in self.selections.all::<usize>(cx) {
11374            let selection_is_empty = selection.is_empty();
11375
11376            let (start, end) = if selection_is_empty {
11377                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11378                (word_range.start, word_range.end)
11379            } else {
11380                (selection.start, selection.end)
11381            };
11382
11383            let text = buffer.text_for_range(start..end).collect::<String>();
11384            let old_length = text.len() as i32;
11385            let text = callback(&text);
11386
11387            new_selections.push(Selection {
11388                start: (start as i32 - selection_adjustment) as usize,
11389                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11390                goal: SelectionGoal::None,
11391                ..selection
11392            });
11393
11394            selection_adjustment += old_length - text.len() as i32;
11395
11396            edits.push((start..end, text));
11397        }
11398
11399        self.transact(window, cx, |this, window, cx| {
11400            this.buffer.update(cx, |buffer, cx| {
11401                buffer.edit(edits, None, cx);
11402            });
11403
11404            this.change_selections(Default::default(), window, cx, |s| {
11405                s.select(new_selections);
11406            });
11407
11408            this.request_autoscroll(Autoscroll::fit(), cx);
11409        });
11410    }
11411
11412    pub fn move_selection_on_drop(
11413        &mut self,
11414        selection: &Selection<Anchor>,
11415        target: DisplayPoint,
11416        is_cut: bool,
11417        window: &mut Window,
11418        cx: &mut Context<Self>,
11419    ) {
11420        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11421        let buffer = &display_map.buffer_snapshot;
11422        let mut edits = Vec::new();
11423        let insert_point = display_map
11424            .clip_point(target, Bias::Left)
11425            .to_point(&display_map);
11426        let text = buffer
11427            .text_for_range(selection.start..selection.end)
11428            .collect::<String>();
11429        if is_cut {
11430            edits.push(((selection.start..selection.end), String::new()));
11431        }
11432        let insert_anchor = buffer.anchor_before(insert_point);
11433        edits.push(((insert_anchor..insert_anchor), text));
11434        let last_edit_start = insert_anchor.bias_left(buffer);
11435        let last_edit_end = insert_anchor.bias_right(buffer);
11436        self.transact(window, cx, |this, window, cx| {
11437            this.buffer.update(cx, |buffer, cx| {
11438                buffer.edit(edits, None, cx);
11439            });
11440            this.change_selections(Default::default(), window, cx, |s| {
11441                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11442            });
11443        });
11444    }
11445
11446    pub fn clear_selection_drag_state(&mut self) {
11447        self.selection_drag_state = SelectionDragState::None;
11448    }
11449
11450    pub fn duplicate(
11451        &mut self,
11452        upwards: bool,
11453        whole_lines: bool,
11454        window: &mut Window,
11455        cx: &mut Context<Self>,
11456    ) {
11457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11458
11459        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11460        let buffer = &display_map.buffer_snapshot;
11461        let selections = self.selections.all::<Point>(cx);
11462
11463        let mut edits = Vec::new();
11464        let mut selections_iter = selections.iter().peekable();
11465        while let Some(selection) = selections_iter.next() {
11466            let mut rows = selection.spanned_rows(false, &display_map);
11467            // duplicate line-wise
11468            if whole_lines || selection.start == selection.end {
11469                // Avoid duplicating the same lines twice.
11470                while let Some(next_selection) = selections_iter.peek() {
11471                    let next_rows = next_selection.spanned_rows(false, &display_map);
11472                    if next_rows.start < rows.end {
11473                        rows.end = next_rows.end;
11474                        selections_iter.next().unwrap();
11475                    } else {
11476                        break;
11477                    }
11478                }
11479
11480                // Copy the text from the selected row region and splice it either at the start
11481                // or end of the region.
11482                let start = Point::new(rows.start.0, 0);
11483                let end = Point::new(
11484                    rows.end.previous_row().0,
11485                    buffer.line_len(rows.end.previous_row()),
11486                );
11487                let text = buffer
11488                    .text_for_range(start..end)
11489                    .chain(Some("\n"))
11490                    .collect::<String>();
11491                let insert_location = if upwards {
11492                    Point::new(rows.end.0, 0)
11493                } else {
11494                    start
11495                };
11496                edits.push((insert_location..insert_location, text));
11497            } else {
11498                // duplicate character-wise
11499                let start = selection.start;
11500                let end = selection.end;
11501                let text = buffer.text_for_range(start..end).collect::<String>();
11502                edits.push((selection.end..selection.end, text));
11503            }
11504        }
11505
11506        self.transact(window, cx, |this, _, cx| {
11507            this.buffer.update(cx, |buffer, cx| {
11508                buffer.edit(edits, None, cx);
11509            });
11510
11511            this.request_autoscroll(Autoscroll::fit(), cx);
11512        });
11513    }
11514
11515    pub fn duplicate_line_up(
11516        &mut self,
11517        _: &DuplicateLineUp,
11518        window: &mut Window,
11519        cx: &mut Context<Self>,
11520    ) {
11521        self.duplicate(true, true, window, cx);
11522    }
11523
11524    pub fn duplicate_line_down(
11525        &mut self,
11526        _: &DuplicateLineDown,
11527        window: &mut Window,
11528        cx: &mut Context<Self>,
11529    ) {
11530        self.duplicate(false, true, window, cx);
11531    }
11532
11533    pub fn duplicate_selection(
11534        &mut self,
11535        _: &DuplicateSelection,
11536        window: &mut Window,
11537        cx: &mut Context<Self>,
11538    ) {
11539        self.duplicate(false, false, window, cx);
11540    }
11541
11542    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11544        if self.mode.is_single_line() {
11545            cx.propagate();
11546            return;
11547        }
11548
11549        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11550        let buffer = self.buffer.read(cx).snapshot(cx);
11551
11552        let mut edits = Vec::new();
11553        let mut unfold_ranges = Vec::new();
11554        let mut refold_creases = Vec::new();
11555
11556        let selections = self.selections.all::<Point>(cx);
11557        let mut selections = selections.iter().peekable();
11558        let mut contiguous_row_selections = Vec::new();
11559        let mut new_selections = Vec::new();
11560
11561        while let Some(selection) = selections.next() {
11562            // Find all the selections that span a contiguous row range
11563            let (start_row, end_row) = consume_contiguous_rows(
11564                &mut contiguous_row_selections,
11565                selection,
11566                &display_map,
11567                &mut selections,
11568            );
11569
11570            // Move the text spanned by the row range to be before the line preceding the row range
11571            if start_row.0 > 0 {
11572                let range_to_move = Point::new(
11573                    start_row.previous_row().0,
11574                    buffer.line_len(start_row.previous_row()),
11575                )
11576                    ..Point::new(
11577                        end_row.previous_row().0,
11578                        buffer.line_len(end_row.previous_row()),
11579                    );
11580                let insertion_point = display_map
11581                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11582                    .0;
11583
11584                // Don't move lines across excerpts
11585                if buffer
11586                    .excerpt_containing(insertion_point..range_to_move.end)
11587                    .is_some()
11588                {
11589                    let text = buffer
11590                        .text_for_range(range_to_move.clone())
11591                        .flat_map(|s| s.chars())
11592                        .skip(1)
11593                        .chain(['\n'])
11594                        .collect::<String>();
11595
11596                    edits.push((
11597                        buffer.anchor_after(range_to_move.start)
11598                            ..buffer.anchor_before(range_to_move.end),
11599                        String::new(),
11600                    ));
11601                    let insertion_anchor = buffer.anchor_after(insertion_point);
11602                    edits.push((insertion_anchor..insertion_anchor, text));
11603
11604                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11605
11606                    // Move selections up
11607                    new_selections.extend(contiguous_row_selections.drain(..).map(
11608                        |mut selection| {
11609                            selection.start.row -= row_delta;
11610                            selection.end.row -= row_delta;
11611                            selection
11612                        },
11613                    ));
11614
11615                    // Move folds up
11616                    unfold_ranges.push(range_to_move.clone());
11617                    for fold in display_map.folds_in_range(
11618                        buffer.anchor_before(range_to_move.start)
11619                            ..buffer.anchor_after(range_to_move.end),
11620                    ) {
11621                        let mut start = fold.range.start.to_point(&buffer);
11622                        let mut end = fold.range.end.to_point(&buffer);
11623                        start.row -= row_delta;
11624                        end.row -= row_delta;
11625                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11626                    }
11627                }
11628            }
11629
11630            // If we didn't move line(s), preserve the existing selections
11631            new_selections.append(&mut contiguous_row_selections);
11632        }
11633
11634        self.transact(window, cx, |this, window, cx| {
11635            this.unfold_ranges(&unfold_ranges, true, true, cx);
11636            this.buffer.update(cx, |buffer, cx| {
11637                for (range, text) in edits {
11638                    buffer.edit([(range, text)], None, cx);
11639                }
11640            });
11641            this.fold_creases(refold_creases, true, window, cx);
11642            this.change_selections(Default::default(), window, cx, |s| {
11643                s.select(new_selections);
11644            })
11645        });
11646    }
11647
11648    pub fn move_line_down(
11649        &mut self,
11650        _: &MoveLineDown,
11651        window: &mut Window,
11652        cx: &mut Context<Self>,
11653    ) {
11654        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11655        if self.mode.is_single_line() {
11656            cx.propagate();
11657            return;
11658        }
11659
11660        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11661        let buffer = self.buffer.read(cx).snapshot(cx);
11662
11663        let mut edits = Vec::new();
11664        let mut unfold_ranges = Vec::new();
11665        let mut refold_creases = Vec::new();
11666
11667        let selections = self.selections.all::<Point>(cx);
11668        let mut selections = selections.iter().peekable();
11669        let mut contiguous_row_selections = Vec::new();
11670        let mut new_selections = Vec::new();
11671
11672        while let Some(selection) = selections.next() {
11673            // Find all the selections that span a contiguous row range
11674            let (start_row, end_row) = consume_contiguous_rows(
11675                &mut contiguous_row_selections,
11676                selection,
11677                &display_map,
11678                &mut selections,
11679            );
11680
11681            // Move the text spanned by the row range to be after the last line of the row range
11682            if end_row.0 <= buffer.max_point().row {
11683                let range_to_move =
11684                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11685                let insertion_point = display_map
11686                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11687                    .0;
11688
11689                // Don't move lines across excerpt boundaries
11690                if buffer
11691                    .excerpt_containing(range_to_move.start..insertion_point)
11692                    .is_some()
11693                {
11694                    let mut text = String::from("\n");
11695                    text.extend(buffer.text_for_range(range_to_move.clone()));
11696                    text.pop(); // Drop trailing newline
11697                    edits.push((
11698                        buffer.anchor_after(range_to_move.start)
11699                            ..buffer.anchor_before(range_to_move.end),
11700                        String::new(),
11701                    ));
11702                    let insertion_anchor = buffer.anchor_after(insertion_point);
11703                    edits.push((insertion_anchor..insertion_anchor, text));
11704
11705                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11706
11707                    // Move selections down
11708                    new_selections.extend(contiguous_row_selections.drain(..).map(
11709                        |mut selection| {
11710                            selection.start.row += row_delta;
11711                            selection.end.row += row_delta;
11712                            selection
11713                        },
11714                    ));
11715
11716                    // Move folds down
11717                    unfold_ranges.push(range_to_move.clone());
11718                    for fold in display_map.folds_in_range(
11719                        buffer.anchor_before(range_to_move.start)
11720                            ..buffer.anchor_after(range_to_move.end),
11721                    ) {
11722                        let mut start = fold.range.start.to_point(&buffer);
11723                        let mut end = fold.range.end.to_point(&buffer);
11724                        start.row += row_delta;
11725                        end.row += row_delta;
11726                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11727                    }
11728                }
11729            }
11730
11731            // If we didn't move line(s), preserve the existing selections
11732            new_selections.append(&mut contiguous_row_selections);
11733        }
11734
11735        self.transact(window, cx, |this, window, cx| {
11736            this.unfold_ranges(&unfold_ranges, true, true, cx);
11737            this.buffer.update(cx, |buffer, cx| {
11738                for (range, text) in edits {
11739                    buffer.edit([(range, text)], None, cx);
11740                }
11741            });
11742            this.fold_creases(refold_creases, true, window, cx);
11743            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11744        });
11745    }
11746
11747    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11748        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11749        let text_layout_details = &self.text_layout_details(window);
11750        self.transact(window, cx, |this, window, cx| {
11751            let edits = this.change_selections(Default::default(), window, cx, |s| {
11752                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11753                s.move_with(|display_map, selection| {
11754                    if !selection.is_empty() {
11755                        return;
11756                    }
11757
11758                    let mut head = selection.head();
11759                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11760                    if head.column() == display_map.line_len(head.row()) {
11761                        transpose_offset = display_map
11762                            .buffer_snapshot
11763                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11764                    }
11765
11766                    if transpose_offset == 0 {
11767                        return;
11768                    }
11769
11770                    *head.column_mut() += 1;
11771                    head = display_map.clip_point(head, Bias::Right);
11772                    let goal = SelectionGoal::HorizontalPosition(
11773                        display_map
11774                            .x_for_display_point(head, text_layout_details)
11775                            .into(),
11776                    );
11777                    selection.collapse_to(head, goal);
11778
11779                    let transpose_start = display_map
11780                        .buffer_snapshot
11781                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11782                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11783                        let transpose_end = display_map
11784                            .buffer_snapshot
11785                            .clip_offset(transpose_offset + 1, Bias::Right);
11786                        if let Some(ch) =
11787                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11788                        {
11789                            edits.push((transpose_start..transpose_offset, String::new()));
11790                            edits.push((transpose_end..transpose_end, ch.to_string()));
11791                        }
11792                    }
11793                });
11794                edits
11795            });
11796            this.buffer
11797                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11798            let selections = this.selections.all::<usize>(cx);
11799            this.change_selections(Default::default(), window, cx, |s| {
11800                s.select(selections);
11801            });
11802        });
11803    }
11804
11805    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11806        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11807        if self.mode.is_single_line() {
11808            cx.propagate();
11809            return;
11810        }
11811
11812        self.rewrap_impl(RewrapOptions::default(), cx)
11813    }
11814
11815    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11816        let buffer = self.buffer.read(cx).snapshot(cx);
11817        let selections = self.selections.all::<Point>(cx);
11818
11819        #[derive(Clone, Debug, PartialEq)]
11820        enum CommentFormat {
11821            /// single line comment, with prefix for line
11822            Line(String),
11823            /// single line within a block comment, with prefix for line
11824            BlockLine(String),
11825            /// a single line of a block comment that includes the initial delimiter
11826            BlockCommentWithStart(BlockCommentConfig),
11827            /// a single line of a block comment that includes the ending delimiter
11828            BlockCommentWithEnd(BlockCommentConfig),
11829        }
11830
11831        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11832        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11833            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11834                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11835                .peekable();
11836
11837            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11838                row
11839            } else {
11840                return Vec::new();
11841            };
11842
11843            let language_settings = buffer.language_settings_at(selection.head(), cx);
11844            let language_scope = buffer.language_scope_at(selection.head());
11845
11846            let indent_and_prefix_for_row =
11847                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11848                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11849                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11850                        &language_scope
11851                    {
11852                        let indent_end = Point::new(row, indent.len);
11853                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11854                        let line_text_after_indent = buffer
11855                            .text_for_range(indent_end..line_end)
11856                            .collect::<String>();
11857
11858                        let is_within_comment_override = buffer
11859                            .language_scope_at(indent_end)
11860                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11861                        let comment_delimiters = if is_within_comment_override {
11862                            // we are within a comment syntax node, but we don't
11863                            // yet know what kind of comment: block, doc or line
11864                            match (
11865                                language_scope.documentation_comment(),
11866                                language_scope.block_comment(),
11867                            ) {
11868                                (Some(config), _) | (_, Some(config))
11869                                    if buffer.contains_str_at(indent_end, &config.start) =>
11870                                {
11871                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11872                                }
11873                                (Some(config), _) | (_, Some(config))
11874                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11875                                {
11876                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11877                                }
11878                                (Some(config), _) | (_, Some(config))
11879                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11880                                {
11881                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11882                                }
11883                                (_, _) => language_scope
11884                                    .line_comment_prefixes()
11885                                    .iter()
11886                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11887                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11888                            }
11889                        } else {
11890                            // we not in an overridden comment node, but we may
11891                            // be within a non-overridden line comment node
11892                            language_scope
11893                                .line_comment_prefixes()
11894                                .iter()
11895                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11896                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11897                        };
11898
11899                        let rewrap_prefix = language_scope
11900                            .rewrap_prefixes()
11901                            .iter()
11902                            .find_map(|prefix_regex| {
11903                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11904                                    if mat.start() == 0 {
11905                                        Some(mat.as_str().to_string())
11906                                    } else {
11907                                        None
11908                                    }
11909                                })
11910                            })
11911                            .flatten();
11912                        (comment_delimiters, rewrap_prefix)
11913                    } else {
11914                        (None, None)
11915                    };
11916                    (indent, comment_prefix, rewrap_prefix)
11917                };
11918
11919            let mut ranges = Vec::new();
11920            let from_empty_selection = selection.is_empty();
11921
11922            let mut current_range_start = first_row;
11923            let mut prev_row = first_row;
11924            let (
11925                mut current_range_indent,
11926                mut current_range_comment_delimiters,
11927                mut current_range_rewrap_prefix,
11928            ) = indent_and_prefix_for_row(first_row);
11929
11930            for row in non_blank_rows_iter.skip(1) {
11931                let has_paragraph_break = row > prev_row + 1;
11932
11933                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
11934                    indent_and_prefix_for_row(row);
11935
11936                let has_indent_change = row_indent != current_range_indent;
11937                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
11938
11939                let has_boundary_change = has_comment_change
11940                    || row_rewrap_prefix.is_some()
11941                    || (has_indent_change && current_range_comment_delimiters.is_some());
11942
11943                if has_paragraph_break || has_boundary_change {
11944                    ranges.push((
11945                        language_settings.clone(),
11946                        Point::new(current_range_start, 0)
11947                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11948                        current_range_indent,
11949                        current_range_comment_delimiters.clone(),
11950                        current_range_rewrap_prefix.clone(),
11951                        from_empty_selection,
11952                    ));
11953                    current_range_start = row;
11954                    current_range_indent = row_indent;
11955                    current_range_comment_delimiters = row_comment_delimiters;
11956                    current_range_rewrap_prefix = row_rewrap_prefix;
11957                }
11958                prev_row = row;
11959            }
11960
11961            ranges.push((
11962                language_settings.clone(),
11963                Point::new(current_range_start, 0)
11964                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11965                current_range_indent,
11966                current_range_comment_delimiters,
11967                current_range_rewrap_prefix,
11968                from_empty_selection,
11969            ));
11970
11971            ranges
11972        });
11973
11974        let mut edits = Vec::new();
11975        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11976
11977        for (
11978            language_settings,
11979            wrap_range,
11980            mut indent_size,
11981            comment_prefix,
11982            rewrap_prefix,
11983            from_empty_selection,
11984        ) in wrap_ranges
11985        {
11986            let mut start_row = wrap_range.start.row;
11987            let mut end_row = wrap_range.end.row;
11988
11989            // Skip selections that overlap with a range that has already been rewrapped.
11990            let selection_range = start_row..end_row;
11991            if rewrapped_row_ranges
11992                .iter()
11993                .any(|range| range.overlaps(&selection_range))
11994            {
11995                continue;
11996            }
11997
11998            let tab_size = language_settings.tab_size;
11999
12000            let (line_prefix, inside_comment) = match &comment_prefix {
12001                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12002                    (Some(prefix.as_str()), true)
12003                }
12004                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12005                    (Some(prefix.as_ref()), true)
12006                }
12007                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12008                    start: _,
12009                    end: _,
12010                    prefix,
12011                    tab_size,
12012                })) => {
12013                    indent_size.len += tab_size;
12014                    (Some(prefix.as_ref()), true)
12015                }
12016                None => (None, false),
12017            };
12018            let indent_prefix = indent_size.chars().collect::<String>();
12019            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12020
12021            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12022                RewrapBehavior::InComments => inside_comment,
12023                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12024                RewrapBehavior::Anywhere => true,
12025            };
12026
12027            let should_rewrap = options.override_language_settings
12028                || allow_rewrap_based_on_language
12029                || self.hard_wrap.is_some();
12030            if !should_rewrap {
12031                continue;
12032            }
12033
12034            if from_empty_selection {
12035                'expand_upwards: while start_row > 0 {
12036                    let prev_row = start_row - 1;
12037                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12038                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12039                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12040                    {
12041                        start_row = prev_row;
12042                    } else {
12043                        break 'expand_upwards;
12044                    }
12045                }
12046
12047                'expand_downwards: while end_row < buffer.max_point().row {
12048                    let next_row = end_row + 1;
12049                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12050                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12051                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12052                    {
12053                        end_row = next_row;
12054                    } else {
12055                        break 'expand_downwards;
12056                    }
12057                }
12058            }
12059
12060            let start = Point::new(start_row, 0);
12061            let start_offset = start.to_offset(&buffer);
12062            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12063            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12064            let mut first_line_delimiter = None;
12065            let mut last_line_delimiter = None;
12066            let Some(lines_without_prefixes) = selection_text
12067                .lines()
12068                .enumerate()
12069                .map(|(ix, line)| {
12070                    let line_trimmed = line.trim_start();
12071                    if rewrap_prefix.is_some() && ix > 0 {
12072                        Ok(line_trimmed)
12073                    } else if let Some(
12074                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12075                            start,
12076                            prefix,
12077                            end,
12078                            tab_size,
12079                        })
12080                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12081                            start,
12082                            prefix,
12083                            end,
12084                            tab_size,
12085                        }),
12086                    ) = &comment_prefix
12087                    {
12088                        let line_trimmed = line_trimmed
12089                            .strip_prefix(start.as_ref())
12090                            .map(|s| {
12091                                let mut indent_size = indent_size;
12092                                indent_size.len -= tab_size;
12093                                let indent_prefix: String = indent_size.chars().collect();
12094                                first_line_delimiter = Some((indent_prefix, start));
12095                                s.trim_start()
12096                            })
12097                            .unwrap_or(line_trimmed);
12098                        let line_trimmed = line_trimmed
12099                            .strip_suffix(end.as_ref())
12100                            .map(|s| {
12101                                last_line_delimiter = Some(end);
12102                                s.trim_end()
12103                            })
12104                            .unwrap_or(line_trimmed);
12105                        let line_trimmed = line_trimmed
12106                            .strip_prefix(prefix.as_ref())
12107                            .unwrap_or(line_trimmed);
12108                        Ok(line_trimmed)
12109                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12110                        line_trimmed.strip_prefix(prefix).with_context(|| {
12111                            format!("line did not start with prefix {prefix:?}: {line:?}")
12112                        })
12113                    } else {
12114                        line_trimmed
12115                            .strip_prefix(&line_prefix.trim_start())
12116                            .with_context(|| {
12117                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12118                            })
12119                    }
12120                })
12121                .collect::<Result<Vec<_>, _>>()
12122                .log_err()
12123            else {
12124                continue;
12125            };
12126
12127            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12128                buffer
12129                    .language_settings_at(Point::new(start_row, 0), cx)
12130                    .preferred_line_length as usize
12131            });
12132
12133            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12134                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12135            } else {
12136                line_prefix.clone()
12137            };
12138
12139            let wrapped_text = {
12140                let mut wrapped_text = wrap_with_prefix(
12141                    line_prefix,
12142                    subsequent_lines_prefix,
12143                    lines_without_prefixes.join("\n"),
12144                    wrap_column,
12145                    tab_size,
12146                    options.preserve_existing_whitespace,
12147                );
12148
12149                if let Some((indent, delimiter)) = first_line_delimiter {
12150                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12151                }
12152                if let Some(last_line) = last_line_delimiter {
12153                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12154                }
12155
12156                wrapped_text
12157            };
12158
12159            // TODO: should always use char-based diff while still supporting cursor behavior that
12160            // matches vim.
12161            let mut diff_options = DiffOptions::default();
12162            if options.override_language_settings {
12163                diff_options.max_word_diff_len = 0;
12164                diff_options.max_word_diff_line_count = 0;
12165            } else {
12166                diff_options.max_word_diff_len = usize::MAX;
12167                diff_options.max_word_diff_line_count = usize::MAX;
12168            }
12169
12170            for (old_range, new_text) in
12171                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12172            {
12173                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12174                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12175                edits.push((edit_start..edit_end, new_text));
12176            }
12177
12178            rewrapped_row_ranges.push(start_row..=end_row);
12179        }
12180
12181        self.buffer
12182            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12183    }
12184
12185    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12186        let mut text = String::new();
12187        let buffer = self.buffer.read(cx).snapshot(cx);
12188        let mut selections = self.selections.all::<Point>(cx);
12189        let mut clipboard_selections = Vec::with_capacity(selections.len());
12190        {
12191            let max_point = buffer.max_point();
12192            let mut is_first = true;
12193            for selection in &mut selections {
12194                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12195                if is_entire_line {
12196                    selection.start = Point::new(selection.start.row, 0);
12197                    if !selection.is_empty() && selection.end.column == 0 {
12198                        selection.end = cmp::min(max_point, selection.end);
12199                    } else {
12200                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12201                    }
12202                    selection.goal = SelectionGoal::None;
12203                }
12204                if is_first {
12205                    is_first = false;
12206                } else {
12207                    text += "\n";
12208                }
12209                let mut len = 0;
12210                for chunk in buffer.text_for_range(selection.start..selection.end) {
12211                    text.push_str(chunk);
12212                    len += chunk.len();
12213                }
12214                clipboard_selections.push(ClipboardSelection {
12215                    len,
12216                    is_entire_line,
12217                    first_line_indent: buffer
12218                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12219                        .len,
12220                });
12221            }
12222        }
12223
12224        self.transact(window, cx, |this, window, cx| {
12225            this.change_selections(Default::default(), window, cx, |s| {
12226                s.select(selections);
12227            });
12228            this.insert("", window, cx);
12229        });
12230        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12231    }
12232
12233    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12234        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12235        let item = self.cut_common(window, cx);
12236        cx.write_to_clipboard(item);
12237    }
12238
12239    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12240        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12241        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12242            s.move_with(|snapshot, sel| {
12243                if sel.is_empty() {
12244                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12245                }
12246            });
12247        });
12248        let item = self.cut_common(window, cx);
12249        cx.set_global(KillRing(item))
12250    }
12251
12252    pub fn kill_ring_yank(
12253        &mut self,
12254        _: &KillRingYank,
12255        window: &mut Window,
12256        cx: &mut Context<Self>,
12257    ) {
12258        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12259        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12260            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12261                (kill_ring.text().to_string(), kill_ring.metadata_json())
12262            } else {
12263                return;
12264            }
12265        } else {
12266            return;
12267        };
12268        self.do_paste(&text, metadata, false, window, cx);
12269    }
12270
12271    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12272        self.do_copy(true, cx);
12273    }
12274
12275    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12276        self.do_copy(false, cx);
12277    }
12278
12279    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12280        let selections = self.selections.all::<Point>(cx);
12281        let buffer = self.buffer.read(cx).read(cx);
12282        let mut text = String::new();
12283
12284        let mut clipboard_selections = Vec::with_capacity(selections.len());
12285        {
12286            let max_point = buffer.max_point();
12287            let mut is_first = true;
12288            for selection in &selections {
12289                let mut start = selection.start;
12290                let mut end = selection.end;
12291                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12292                if is_entire_line {
12293                    start = Point::new(start.row, 0);
12294                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12295                }
12296
12297                let mut trimmed_selections = Vec::new();
12298                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12299                    let row = MultiBufferRow(start.row);
12300                    let first_indent = buffer.indent_size_for_line(row);
12301                    if first_indent.len == 0 || start.column > first_indent.len {
12302                        trimmed_selections.push(start..end);
12303                    } else {
12304                        trimmed_selections.push(
12305                            Point::new(row.0, first_indent.len)
12306                                ..Point::new(row.0, buffer.line_len(row)),
12307                        );
12308                        for row in start.row + 1..=end.row {
12309                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12310                            if row == end.row {
12311                                line_len = end.column;
12312                            }
12313                            if line_len == 0 {
12314                                trimmed_selections
12315                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12316                                continue;
12317                            }
12318                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12319                            if row_indent_size.len >= first_indent.len {
12320                                trimmed_selections.push(
12321                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12322                                );
12323                            } else {
12324                                trimmed_selections.clear();
12325                                trimmed_selections.push(start..end);
12326                                break;
12327                            }
12328                        }
12329                    }
12330                } else {
12331                    trimmed_selections.push(start..end);
12332                }
12333
12334                for trimmed_range in trimmed_selections {
12335                    if is_first {
12336                        is_first = false;
12337                    } else {
12338                        text += "\n";
12339                    }
12340                    let mut len = 0;
12341                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12342                        text.push_str(chunk);
12343                        len += chunk.len();
12344                    }
12345                    clipboard_selections.push(ClipboardSelection {
12346                        len,
12347                        is_entire_line,
12348                        first_line_indent: buffer
12349                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12350                            .len,
12351                    });
12352                }
12353            }
12354        }
12355
12356        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12357            text,
12358            clipboard_selections,
12359        ));
12360    }
12361
12362    pub fn do_paste(
12363        &mut self,
12364        text: &String,
12365        clipboard_selections: Option<Vec<ClipboardSelection>>,
12366        handle_entire_lines: bool,
12367        window: &mut Window,
12368        cx: &mut Context<Self>,
12369    ) {
12370        if self.read_only(cx) {
12371            return;
12372        }
12373
12374        let clipboard_text = Cow::Borrowed(text);
12375
12376        self.transact(window, cx, |this, window, cx| {
12377            let had_active_edit_prediction = this.has_active_edit_prediction();
12378
12379            if let Some(mut clipboard_selections) = clipboard_selections {
12380                let old_selections = this.selections.all::<usize>(cx);
12381                let all_selections_were_entire_line =
12382                    clipboard_selections.iter().all(|s| s.is_entire_line);
12383                let first_selection_indent_column =
12384                    clipboard_selections.first().map(|s| s.first_line_indent);
12385                if clipboard_selections.len() != old_selections.len() {
12386                    clipboard_selections.drain(..);
12387                }
12388                let cursor_offset = this.selections.last::<usize>(cx).head();
12389                let mut auto_indent_on_paste = true;
12390
12391                this.buffer.update(cx, |buffer, cx| {
12392                    let snapshot = buffer.read(cx);
12393                    auto_indent_on_paste = snapshot
12394                        .language_settings_at(cursor_offset, cx)
12395                        .auto_indent_on_paste;
12396
12397                    let mut start_offset = 0;
12398                    let mut edits = Vec::new();
12399                    let mut original_indent_columns = Vec::new();
12400                    for (ix, selection) in old_selections.iter().enumerate() {
12401                        let to_insert;
12402                        let entire_line;
12403                        let original_indent_column;
12404                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12405                            let end_offset = start_offset + clipboard_selection.len;
12406                            to_insert = &clipboard_text[start_offset..end_offset];
12407                            entire_line = clipboard_selection.is_entire_line;
12408                            start_offset = end_offset + 1;
12409                            original_indent_column = Some(clipboard_selection.first_line_indent);
12410                        } else {
12411                            to_insert = clipboard_text.as_str();
12412                            entire_line = all_selections_were_entire_line;
12413                            original_indent_column = first_selection_indent_column
12414                        }
12415
12416                        // If the corresponding selection was empty when this slice of the
12417                        // clipboard text was written, then the entire line containing the
12418                        // selection was copied. If this selection is also currently empty,
12419                        // then paste the line before the current line of the buffer.
12420                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12421                            let column = selection.start.to_point(&snapshot).column as usize;
12422                            let line_start = selection.start - column;
12423                            line_start..line_start
12424                        } else {
12425                            selection.range()
12426                        };
12427
12428                        edits.push((range, to_insert));
12429                        original_indent_columns.push(original_indent_column);
12430                    }
12431                    drop(snapshot);
12432
12433                    buffer.edit(
12434                        edits,
12435                        if auto_indent_on_paste {
12436                            Some(AutoindentMode::Block {
12437                                original_indent_columns,
12438                            })
12439                        } else {
12440                            None
12441                        },
12442                        cx,
12443                    );
12444                });
12445
12446                let selections = this.selections.all::<usize>(cx);
12447                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12448            } else {
12449                this.insert(&clipboard_text, window, cx);
12450            }
12451
12452            let trigger_in_words =
12453                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12454
12455            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12456        });
12457    }
12458
12459    pub fn diff_clipboard_with_selection(
12460        &mut self,
12461        _: &DiffClipboardWithSelection,
12462        window: &mut Window,
12463        cx: &mut Context<Self>,
12464    ) {
12465        let selections = self.selections.all::<usize>(cx);
12466
12467        if selections.is_empty() {
12468            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12469            return;
12470        };
12471
12472        let clipboard_text = match cx.read_from_clipboard() {
12473            Some(item) => match item.entries().first() {
12474                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12475                _ => None,
12476            },
12477            None => None,
12478        };
12479
12480        let Some(clipboard_text) = clipboard_text else {
12481            log::warn!("Clipboard doesn't contain text.");
12482            return;
12483        };
12484
12485        window.dispatch_action(
12486            Box::new(DiffClipboardWithSelectionData {
12487                clipboard_text,
12488                editor: cx.entity(),
12489            }),
12490            cx,
12491        );
12492    }
12493
12494    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12495        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12496        if let Some(item) = cx.read_from_clipboard() {
12497            let entries = item.entries();
12498
12499            match entries.first() {
12500                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12501                // of all the pasted entries.
12502                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12503                    .do_paste(
12504                        clipboard_string.text(),
12505                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12506                        true,
12507                        window,
12508                        cx,
12509                    ),
12510                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12511            }
12512        }
12513    }
12514
12515    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12516        if self.read_only(cx) {
12517            return;
12518        }
12519
12520        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12521
12522        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12523            if let Some((selections, _)) =
12524                self.selection_history.transaction(transaction_id).cloned()
12525            {
12526                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12527                    s.select_anchors(selections.to_vec());
12528                });
12529            } else {
12530                log::error!(
12531                    "No entry in selection_history found for undo. \
12532                     This may correspond to a bug where undo does not update the selection. \
12533                     If this is occurring, please add details to \
12534                     https://github.com/zed-industries/zed/issues/22692"
12535                );
12536            }
12537            self.request_autoscroll(Autoscroll::fit(), cx);
12538            self.unmark_text(window, cx);
12539            self.refresh_edit_prediction(true, false, window, cx);
12540            cx.emit(EditorEvent::Edited { transaction_id });
12541            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12542        }
12543    }
12544
12545    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12546        if self.read_only(cx) {
12547            return;
12548        }
12549
12550        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12551
12552        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12553            if let Some((_, Some(selections))) =
12554                self.selection_history.transaction(transaction_id).cloned()
12555            {
12556                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12557                    s.select_anchors(selections.to_vec());
12558                });
12559            } else {
12560                log::error!(
12561                    "No entry in selection_history found for redo. \
12562                     This may correspond to a bug where undo does not update the selection. \
12563                     If this is occurring, please add details to \
12564                     https://github.com/zed-industries/zed/issues/22692"
12565                );
12566            }
12567            self.request_autoscroll(Autoscroll::fit(), cx);
12568            self.unmark_text(window, cx);
12569            self.refresh_edit_prediction(true, false, window, cx);
12570            cx.emit(EditorEvent::Edited { transaction_id });
12571        }
12572    }
12573
12574    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12575        self.buffer
12576            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12577    }
12578
12579    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12580        self.buffer
12581            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12582    }
12583
12584    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12585        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12586        self.change_selections(Default::default(), window, cx, |s| {
12587            s.move_with(|map, selection| {
12588                let cursor = if selection.is_empty() {
12589                    movement::left(map, selection.start)
12590                } else {
12591                    selection.start
12592                };
12593                selection.collapse_to(cursor, SelectionGoal::None);
12594            });
12595        })
12596    }
12597
12598    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12599        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12600        self.change_selections(Default::default(), window, cx, |s| {
12601            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12602        })
12603    }
12604
12605    pub fn move_right(&mut self, _: &MoveRight, 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::right(map, selection.end)
12611                } else {
12612                    selection.end
12613                };
12614                selection.collapse_to(cursor, SelectionGoal::None)
12615            });
12616        })
12617    }
12618
12619    pub fn select_right(&mut self, _: &SelectRight, 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::right(map, head), SelectionGoal::None));
12623        })
12624    }
12625
12626    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12627        if self.take_rename(true, window, cx).is_some() {
12628            return;
12629        }
12630
12631        if self.mode.is_single_line() {
12632            cx.propagate();
12633            return;
12634        }
12635
12636        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12637
12638        let text_layout_details = &self.text_layout_details(window);
12639        let selection_count = self.selections.count();
12640        let first_selection = self.selections.first_anchor();
12641
12642        self.change_selections(Default::default(), window, cx, |s| {
12643            s.move_with(|map, selection| {
12644                if !selection.is_empty() {
12645                    selection.goal = SelectionGoal::None;
12646                }
12647                let (cursor, goal) = movement::up(
12648                    map,
12649                    selection.start,
12650                    selection.goal,
12651                    false,
12652                    text_layout_details,
12653                );
12654                selection.collapse_to(cursor, goal);
12655            });
12656        });
12657
12658        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12659        {
12660            cx.propagate();
12661        }
12662    }
12663
12664    pub fn move_up_by_lines(
12665        &mut self,
12666        action: &MoveUpByLines,
12667        window: &mut Window,
12668        cx: &mut Context<Self>,
12669    ) {
12670        if self.take_rename(true, window, cx).is_some() {
12671            return;
12672        }
12673
12674        if self.mode.is_single_line() {
12675            cx.propagate();
12676            return;
12677        }
12678
12679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12680
12681        let text_layout_details = &self.text_layout_details(window);
12682
12683        self.change_selections(Default::default(), window, cx, |s| {
12684            s.move_with(|map, selection| {
12685                if !selection.is_empty() {
12686                    selection.goal = SelectionGoal::None;
12687                }
12688                let (cursor, goal) = movement::up_by_rows(
12689                    map,
12690                    selection.start,
12691                    action.lines,
12692                    selection.goal,
12693                    false,
12694                    text_layout_details,
12695                );
12696                selection.collapse_to(cursor, goal);
12697            });
12698        })
12699    }
12700
12701    pub fn move_down_by_lines(
12702        &mut self,
12703        action: &MoveDownByLines,
12704        window: &mut Window,
12705        cx: &mut Context<Self>,
12706    ) {
12707        if self.take_rename(true, window, cx).is_some() {
12708            return;
12709        }
12710
12711        if self.mode.is_single_line() {
12712            cx.propagate();
12713            return;
12714        }
12715
12716        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12717
12718        let text_layout_details = &self.text_layout_details(window);
12719
12720        self.change_selections(Default::default(), window, cx, |s| {
12721            s.move_with(|map, selection| {
12722                if !selection.is_empty() {
12723                    selection.goal = SelectionGoal::None;
12724                }
12725                let (cursor, goal) = movement::down_by_rows(
12726                    map,
12727                    selection.start,
12728                    action.lines,
12729                    selection.goal,
12730                    false,
12731                    text_layout_details,
12732                );
12733                selection.collapse_to(cursor, goal);
12734            });
12735        })
12736    }
12737
12738    pub fn select_down_by_lines(
12739        &mut self,
12740        action: &SelectDownByLines,
12741        window: &mut Window,
12742        cx: &mut Context<Self>,
12743    ) {
12744        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12745        let text_layout_details = &self.text_layout_details(window);
12746        self.change_selections(Default::default(), window, cx, |s| {
12747            s.move_heads_with(|map, head, goal| {
12748                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12749            })
12750        })
12751    }
12752
12753    pub fn select_up_by_lines(
12754        &mut self,
12755        action: &SelectUpByLines,
12756        window: &mut Window,
12757        cx: &mut Context<Self>,
12758    ) {
12759        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12760        let text_layout_details = &self.text_layout_details(window);
12761        self.change_selections(Default::default(), window, cx, |s| {
12762            s.move_heads_with(|map, head, goal| {
12763                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12764            })
12765        })
12766    }
12767
12768    pub fn select_page_up(
12769        &mut self,
12770        _: &SelectPageUp,
12771        window: &mut Window,
12772        cx: &mut Context<Self>,
12773    ) {
12774        let Some(row_count) = self.visible_row_count() else {
12775            return;
12776        };
12777
12778        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12779
12780        let text_layout_details = &self.text_layout_details(window);
12781
12782        self.change_selections(Default::default(), window, cx, |s| {
12783            s.move_heads_with(|map, head, goal| {
12784                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12785            })
12786        })
12787    }
12788
12789    pub fn move_page_up(
12790        &mut self,
12791        action: &MovePageUp,
12792        window: &mut Window,
12793        cx: &mut Context<Self>,
12794    ) {
12795        if self.take_rename(true, window, cx).is_some() {
12796            return;
12797        }
12798
12799        if self
12800            .context_menu
12801            .borrow_mut()
12802            .as_mut()
12803            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12804            .unwrap_or(false)
12805        {
12806            return;
12807        }
12808
12809        if matches!(self.mode, EditorMode::SingleLine) {
12810            cx.propagate();
12811            return;
12812        }
12813
12814        let Some(row_count) = self.visible_row_count() else {
12815            return;
12816        };
12817
12818        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12819
12820        let effects = if action.center_cursor {
12821            SelectionEffects::scroll(Autoscroll::center())
12822        } else {
12823            SelectionEffects::default()
12824        };
12825
12826        let text_layout_details = &self.text_layout_details(window);
12827
12828        self.change_selections(effects, window, cx, |s| {
12829            s.move_with(|map, selection| {
12830                if !selection.is_empty() {
12831                    selection.goal = SelectionGoal::None;
12832                }
12833                let (cursor, goal) = movement::up_by_rows(
12834                    map,
12835                    selection.end,
12836                    row_count,
12837                    selection.goal,
12838                    false,
12839                    text_layout_details,
12840                );
12841                selection.collapse_to(cursor, goal);
12842            });
12843        });
12844    }
12845
12846    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12847        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12848        let text_layout_details = &self.text_layout_details(window);
12849        self.change_selections(Default::default(), window, cx, |s| {
12850            s.move_heads_with(|map, head, goal| {
12851                movement::up(map, head, goal, false, text_layout_details)
12852            })
12853        })
12854    }
12855
12856    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12857        self.take_rename(true, window, cx);
12858
12859        if self.mode.is_single_line() {
12860            cx.propagate();
12861            return;
12862        }
12863
12864        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12865
12866        let text_layout_details = &self.text_layout_details(window);
12867        let selection_count = self.selections.count();
12868        let first_selection = self.selections.first_anchor();
12869
12870        self.change_selections(Default::default(), window, cx, |s| {
12871            s.move_with(|map, selection| {
12872                if !selection.is_empty() {
12873                    selection.goal = SelectionGoal::None;
12874                }
12875                let (cursor, goal) = movement::down(
12876                    map,
12877                    selection.end,
12878                    selection.goal,
12879                    false,
12880                    text_layout_details,
12881                );
12882                selection.collapse_to(cursor, goal);
12883            });
12884        });
12885
12886        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12887        {
12888            cx.propagate();
12889        }
12890    }
12891
12892    pub fn select_page_down(
12893        &mut self,
12894        _: &SelectPageDown,
12895        window: &mut Window,
12896        cx: &mut Context<Self>,
12897    ) {
12898        let Some(row_count) = self.visible_row_count() else {
12899            return;
12900        };
12901
12902        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12903
12904        let text_layout_details = &self.text_layout_details(window);
12905
12906        self.change_selections(Default::default(), window, cx, |s| {
12907            s.move_heads_with(|map, head, goal| {
12908                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12909            })
12910        })
12911    }
12912
12913    pub fn move_page_down(
12914        &mut self,
12915        action: &MovePageDown,
12916        window: &mut Window,
12917        cx: &mut Context<Self>,
12918    ) {
12919        if self.take_rename(true, window, cx).is_some() {
12920            return;
12921        }
12922
12923        if self
12924            .context_menu
12925            .borrow_mut()
12926            .as_mut()
12927            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12928            .unwrap_or(false)
12929        {
12930            return;
12931        }
12932
12933        if matches!(self.mode, EditorMode::SingleLine) {
12934            cx.propagate();
12935            return;
12936        }
12937
12938        let Some(row_count) = self.visible_row_count() else {
12939            return;
12940        };
12941
12942        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12943
12944        let effects = if action.center_cursor {
12945            SelectionEffects::scroll(Autoscroll::center())
12946        } else {
12947            SelectionEffects::default()
12948        };
12949
12950        let text_layout_details = &self.text_layout_details(window);
12951        self.change_selections(effects, window, cx, |s| {
12952            s.move_with(|map, selection| {
12953                if !selection.is_empty() {
12954                    selection.goal = SelectionGoal::None;
12955                }
12956                let (cursor, goal) = movement::down_by_rows(
12957                    map,
12958                    selection.end,
12959                    row_count,
12960                    selection.goal,
12961                    false,
12962                    text_layout_details,
12963                );
12964                selection.collapse_to(cursor, goal);
12965            });
12966        });
12967    }
12968
12969    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12970        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12971        let text_layout_details = &self.text_layout_details(window);
12972        self.change_selections(Default::default(), window, cx, |s| {
12973            s.move_heads_with(|map, head, goal| {
12974                movement::down(map, head, goal, false, text_layout_details)
12975            })
12976        });
12977    }
12978
12979    pub fn context_menu_first(
12980        &mut self,
12981        _: &ContextMenuFirst,
12982        window: &mut Window,
12983        cx: &mut Context<Self>,
12984    ) {
12985        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12986            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12987        }
12988    }
12989
12990    pub fn context_menu_prev(
12991        &mut self,
12992        _: &ContextMenuPrevious,
12993        window: &mut Window,
12994        cx: &mut Context<Self>,
12995    ) {
12996        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12997            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12998        }
12999    }
13000
13001    pub fn context_menu_next(
13002        &mut self,
13003        _: &ContextMenuNext,
13004        window: &mut Window,
13005        cx: &mut Context<Self>,
13006    ) {
13007        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13008            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13009        }
13010    }
13011
13012    pub fn context_menu_last(
13013        &mut self,
13014        _: &ContextMenuLast,
13015        window: &mut Window,
13016        cx: &mut Context<Self>,
13017    ) {
13018        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13019            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13020        }
13021    }
13022
13023    pub fn signature_help_prev(
13024        &mut self,
13025        _: &SignatureHelpPrevious,
13026        _: &mut Window,
13027        cx: &mut Context<Self>,
13028    ) {
13029        if let Some(popover) = self.signature_help_state.popover_mut() {
13030            if popover.current_signature == 0 {
13031                popover.current_signature = popover.signatures.len() - 1;
13032            } else {
13033                popover.current_signature -= 1;
13034            }
13035            cx.notify();
13036        }
13037    }
13038
13039    pub fn signature_help_next(
13040        &mut self,
13041        _: &SignatureHelpNext,
13042        _: &mut Window,
13043        cx: &mut Context<Self>,
13044    ) {
13045        if let Some(popover) = self.signature_help_state.popover_mut() {
13046            if popover.current_signature + 1 == popover.signatures.len() {
13047                popover.current_signature = 0;
13048            } else {
13049                popover.current_signature += 1;
13050            }
13051            cx.notify();
13052        }
13053    }
13054
13055    pub fn move_to_previous_word_start(
13056        &mut self,
13057        _: &MoveToPreviousWordStart,
13058        window: &mut Window,
13059        cx: &mut Context<Self>,
13060    ) {
13061        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13062        self.change_selections(Default::default(), window, cx, |s| {
13063            s.move_cursors_with(|map, head, _| {
13064                (
13065                    movement::previous_word_start(map, head),
13066                    SelectionGoal::None,
13067                )
13068            });
13069        })
13070    }
13071
13072    pub fn move_to_previous_subword_start(
13073        &mut self,
13074        _: &MoveToPreviousSubwordStart,
13075        window: &mut Window,
13076        cx: &mut Context<Self>,
13077    ) {
13078        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13079        self.change_selections(Default::default(), window, cx, |s| {
13080            s.move_cursors_with(|map, head, _| {
13081                (
13082                    movement::previous_subword_start(map, head),
13083                    SelectionGoal::None,
13084                )
13085            });
13086        })
13087    }
13088
13089    pub fn select_to_previous_word_start(
13090        &mut self,
13091        _: &SelectToPreviousWordStart,
13092        window: &mut Window,
13093        cx: &mut Context<Self>,
13094    ) {
13095        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13096        self.change_selections(Default::default(), window, cx, |s| {
13097            s.move_heads_with(|map, head, _| {
13098                (
13099                    movement::previous_word_start(map, head),
13100                    SelectionGoal::None,
13101                )
13102            });
13103        })
13104    }
13105
13106    pub fn select_to_previous_subword_start(
13107        &mut self,
13108        _: &SelectToPreviousSubwordStart,
13109        window: &mut Window,
13110        cx: &mut Context<Self>,
13111    ) {
13112        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13113        self.change_selections(Default::default(), window, cx, |s| {
13114            s.move_heads_with(|map, head, _| {
13115                (
13116                    movement::previous_subword_start(map, head),
13117                    SelectionGoal::None,
13118                )
13119            });
13120        })
13121    }
13122
13123    pub fn delete_to_previous_word_start(
13124        &mut self,
13125        action: &DeleteToPreviousWordStart,
13126        window: &mut Window,
13127        cx: &mut Context<Self>,
13128    ) {
13129        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13130        self.transact(window, cx, |this, window, cx| {
13131            this.select_autoclose_pair(window, cx);
13132            this.change_selections(Default::default(), window, cx, |s| {
13133                s.move_with(|map, selection| {
13134                    if selection.is_empty() {
13135                        let cursor = if action.ignore_newlines {
13136                            movement::previous_word_start(map, selection.head())
13137                        } else {
13138                            movement::previous_word_start_or_newline(map, selection.head())
13139                        };
13140                        selection.set_head(cursor, SelectionGoal::None);
13141                    }
13142                });
13143            });
13144            this.insert("", window, cx);
13145        });
13146    }
13147
13148    pub fn delete_to_previous_subword_start(
13149        &mut self,
13150        _: &DeleteToPreviousSubwordStart,
13151        window: &mut Window,
13152        cx: &mut Context<Self>,
13153    ) {
13154        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13155        self.transact(window, cx, |this, window, cx| {
13156            this.select_autoclose_pair(window, cx);
13157            this.change_selections(Default::default(), window, cx, |s| {
13158                s.move_with(|map, selection| {
13159                    if selection.is_empty() {
13160                        let cursor = movement::previous_subword_start(map, selection.head());
13161                        selection.set_head(cursor, SelectionGoal::None);
13162                    }
13163                });
13164            });
13165            this.insert("", window, cx);
13166        });
13167    }
13168
13169    pub fn move_to_next_word_end(
13170        &mut self,
13171        _: &MoveToNextWordEnd,
13172        window: &mut Window,
13173        cx: &mut Context<Self>,
13174    ) {
13175        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13176        self.change_selections(Default::default(), window, cx, |s| {
13177            s.move_cursors_with(|map, head, _| {
13178                (movement::next_word_end(map, head), SelectionGoal::None)
13179            });
13180        })
13181    }
13182
13183    pub fn move_to_next_subword_end(
13184        &mut self,
13185        _: &MoveToNextSubwordEnd,
13186        window: &mut Window,
13187        cx: &mut Context<Self>,
13188    ) {
13189        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13190        self.change_selections(Default::default(), window, cx, |s| {
13191            s.move_cursors_with(|map, head, _| {
13192                (movement::next_subword_end(map, head), SelectionGoal::None)
13193            });
13194        })
13195    }
13196
13197    pub fn select_to_next_word_end(
13198        &mut self,
13199        _: &SelectToNextWordEnd,
13200        window: &mut Window,
13201        cx: &mut Context<Self>,
13202    ) {
13203        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13204        self.change_selections(Default::default(), window, cx, |s| {
13205            s.move_heads_with(|map, head, _| {
13206                (movement::next_word_end(map, head), SelectionGoal::None)
13207            });
13208        })
13209    }
13210
13211    pub fn select_to_next_subword_end(
13212        &mut self,
13213        _: &SelectToNextSubwordEnd,
13214        window: &mut Window,
13215        cx: &mut Context<Self>,
13216    ) {
13217        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13218        self.change_selections(Default::default(), window, cx, |s| {
13219            s.move_heads_with(|map, head, _| {
13220                (movement::next_subword_end(map, head), SelectionGoal::None)
13221            });
13222        })
13223    }
13224
13225    pub fn delete_to_next_word_end(
13226        &mut self,
13227        action: &DeleteToNextWordEnd,
13228        window: &mut Window,
13229        cx: &mut Context<Self>,
13230    ) {
13231        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13232        self.transact(window, cx, |this, window, cx| {
13233            this.change_selections(Default::default(), window, cx, |s| {
13234                s.move_with(|map, selection| {
13235                    if selection.is_empty() {
13236                        let cursor = if action.ignore_newlines {
13237                            movement::next_word_end(map, selection.head())
13238                        } else {
13239                            movement::next_word_end_or_newline(map, selection.head())
13240                        };
13241                        selection.set_head(cursor, SelectionGoal::None);
13242                    }
13243                });
13244            });
13245            this.insert("", window, cx);
13246        });
13247    }
13248
13249    pub fn delete_to_next_subword_end(
13250        &mut self,
13251        _: &DeleteToNextSubwordEnd,
13252        window: &mut Window,
13253        cx: &mut Context<Self>,
13254    ) {
13255        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13256        self.transact(window, cx, |this, window, cx| {
13257            this.change_selections(Default::default(), window, cx, |s| {
13258                s.move_with(|map, selection| {
13259                    if selection.is_empty() {
13260                        let cursor = movement::next_subword_end(map, selection.head());
13261                        selection.set_head(cursor, SelectionGoal::None);
13262                    }
13263                });
13264            });
13265            this.insert("", window, cx);
13266        });
13267    }
13268
13269    pub fn move_to_beginning_of_line(
13270        &mut self,
13271        action: &MoveToBeginningOfLine,
13272        window: &mut Window,
13273        cx: &mut Context<Self>,
13274    ) {
13275        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13276        self.change_selections(Default::default(), window, cx, |s| {
13277            s.move_cursors_with(|map, head, _| {
13278                (
13279                    movement::indented_line_beginning(
13280                        map,
13281                        head,
13282                        action.stop_at_soft_wraps,
13283                        action.stop_at_indent,
13284                    ),
13285                    SelectionGoal::None,
13286                )
13287            });
13288        })
13289    }
13290
13291    pub fn select_to_beginning_of_line(
13292        &mut self,
13293        action: &SelectToBeginningOfLine,
13294        window: &mut Window,
13295        cx: &mut Context<Self>,
13296    ) {
13297        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13298        self.change_selections(Default::default(), window, cx, |s| {
13299            s.move_heads_with(|map, head, _| {
13300                (
13301                    movement::indented_line_beginning(
13302                        map,
13303                        head,
13304                        action.stop_at_soft_wraps,
13305                        action.stop_at_indent,
13306                    ),
13307                    SelectionGoal::None,
13308                )
13309            });
13310        });
13311    }
13312
13313    pub fn delete_to_beginning_of_line(
13314        &mut self,
13315        action: &DeleteToBeginningOfLine,
13316        window: &mut Window,
13317        cx: &mut Context<Self>,
13318    ) {
13319        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13320        self.transact(window, cx, |this, window, cx| {
13321            this.change_selections(Default::default(), window, cx, |s| {
13322                s.move_with(|_, selection| {
13323                    selection.reversed = true;
13324                });
13325            });
13326
13327            this.select_to_beginning_of_line(
13328                &SelectToBeginningOfLine {
13329                    stop_at_soft_wraps: false,
13330                    stop_at_indent: action.stop_at_indent,
13331                },
13332                window,
13333                cx,
13334            );
13335            this.backspace(&Backspace, window, cx);
13336        });
13337    }
13338
13339    pub fn move_to_end_of_line(
13340        &mut self,
13341        action: &MoveToEndOfLine,
13342        window: &mut Window,
13343        cx: &mut Context<Self>,
13344    ) {
13345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13346        self.change_selections(Default::default(), window, cx, |s| {
13347            s.move_cursors_with(|map, head, _| {
13348                (
13349                    movement::line_end(map, head, action.stop_at_soft_wraps),
13350                    SelectionGoal::None,
13351                )
13352            });
13353        })
13354    }
13355
13356    pub fn select_to_end_of_line(
13357        &mut self,
13358        action: &SelectToEndOfLine,
13359        window: &mut Window,
13360        cx: &mut Context<Self>,
13361    ) {
13362        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13363        self.change_selections(Default::default(), window, cx, |s| {
13364            s.move_heads_with(|map, head, _| {
13365                (
13366                    movement::line_end(map, head, action.stop_at_soft_wraps),
13367                    SelectionGoal::None,
13368                )
13369            });
13370        })
13371    }
13372
13373    pub fn delete_to_end_of_line(
13374        &mut self,
13375        _: &DeleteToEndOfLine,
13376        window: &mut Window,
13377        cx: &mut Context<Self>,
13378    ) {
13379        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13380        self.transact(window, cx, |this, window, cx| {
13381            this.select_to_end_of_line(
13382                &SelectToEndOfLine {
13383                    stop_at_soft_wraps: false,
13384                },
13385                window,
13386                cx,
13387            );
13388            this.delete(&Delete, window, cx);
13389        });
13390    }
13391
13392    pub fn cut_to_end_of_line(
13393        &mut self,
13394        _: &CutToEndOfLine,
13395        window: &mut Window,
13396        cx: &mut Context<Self>,
13397    ) {
13398        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13399        self.transact(window, cx, |this, window, cx| {
13400            this.select_to_end_of_line(
13401                &SelectToEndOfLine {
13402                    stop_at_soft_wraps: false,
13403                },
13404                window,
13405                cx,
13406            );
13407            this.cut(&Cut, window, cx);
13408        });
13409    }
13410
13411    pub fn move_to_start_of_paragraph(
13412        &mut self,
13413        _: &MoveToStartOfParagraph,
13414        window: &mut Window,
13415        cx: &mut Context<Self>,
13416    ) {
13417        if matches!(self.mode, EditorMode::SingleLine) {
13418            cx.propagate();
13419            return;
13420        }
13421        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13422        self.change_selections(Default::default(), window, cx, |s| {
13423            s.move_with(|map, selection| {
13424                selection.collapse_to(
13425                    movement::start_of_paragraph(map, selection.head(), 1),
13426                    SelectionGoal::None,
13427                )
13428            });
13429        })
13430    }
13431
13432    pub fn move_to_end_of_paragraph(
13433        &mut self,
13434        _: &MoveToEndOfParagraph,
13435        window: &mut Window,
13436        cx: &mut Context<Self>,
13437    ) {
13438        if matches!(self.mode, EditorMode::SingleLine) {
13439            cx.propagate();
13440            return;
13441        }
13442        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13443        self.change_selections(Default::default(), window, cx, |s| {
13444            s.move_with(|map, selection| {
13445                selection.collapse_to(
13446                    movement::end_of_paragraph(map, selection.head(), 1),
13447                    SelectionGoal::None,
13448                )
13449            });
13450        })
13451    }
13452
13453    pub fn select_to_start_of_paragraph(
13454        &mut self,
13455        _: &SelectToStartOfParagraph,
13456        window: &mut Window,
13457        cx: &mut Context<Self>,
13458    ) {
13459        if matches!(self.mode, EditorMode::SingleLine) {
13460            cx.propagate();
13461            return;
13462        }
13463        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13464        self.change_selections(Default::default(), window, cx, |s| {
13465            s.move_heads_with(|map, head, _| {
13466                (
13467                    movement::start_of_paragraph(map, head, 1),
13468                    SelectionGoal::None,
13469                )
13470            });
13471        })
13472    }
13473
13474    pub fn select_to_end_of_paragraph(
13475        &mut self,
13476        _: &SelectToEndOfParagraph,
13477        window: &mut Window,
13478        cx: &mut Context<Self>,
13479    ) {
13480        if matches!(self.mode, EditorMode::SingleLine) {
13481            cx.propagate();
13482            return;
13483        }
13484        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13485        self.change_selections(Default::default(), window, cx, |s| {
13486            s.move_heads_with(|map, head, _| {
13487                (
13488                    movement::end_of_paragraph(map, head, 1),
13489                    SelectionGoal::None,
13490                )
13491            });
13492        })
13493    }
13494
13495    pub fn move_to_start_of_excerpt(
13496        &mut self,
13497        _: &MoveToStartOfExcerpt,
13498        window: &mut Window,
13499        cx: &mut Context<Self>,
13500    ) {
13501        if matches!(self.mode, EditorMode::SingleLine) {
13502            cx.propagate();
13503            return;
13504        }
13505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13506        self.change_selections(Default::default(), window, cx, |s| {
13507            s.move_with(|map, selection| {
13508                selection.collapse_to(
13509                    movement::start_of_excerpt(
13510                        map,
13511                        selection.head(),
13512                        workspace::searchable::Direction::Prev,
13513                    ),
13514                    SelectionGoal::None,
13515                )
13516            });
13517        })
13518    }
13519
13520    pub fn move_to_start_of_next_excerpt(
13521        &mut self,
13522        _: &MoveToStartOfNextExcerpt,
13523        window: &mut Window,
13524        cx: &mut Context<Self>,
13525    ) {
13526        if matches!(self.mode, EditorMode::SingleLine) {
13527            cx.propagate();
13528            return;
13529        }
13530
13531        self.change_selections(Default::default(), window, cx, |s| {
13532            s.move_with(|map, selection| {
13533                selection.collapse_to(
13534                    movement::start_of_excerpt(
13535                        map,
13536                        selection.head(),
13537                        workspace::searchable::Direction::Next,
13538                    ),
13539                    SelectionGoal::None,
13540                )
13541            });
13542        })
13543    }
13544
13545    pub fn move_to_end_of_excerpt(
13546        &mut self,
13547        _: &MoveToEndOfExcerpt,
13548        window: &mut Window,
13549        cx: &mut Context<Self>,
13550    ) {
13551        if matches!(self.mode, EditorMode::SingleLine) {
13552            cx.propagate();
13553            return;
13554        }
13555        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13556        self.change_selections(Default::default(), window, cx, |s| {
13557            s.move_with(|map, selection| {
13558                selection.collapse_to(
13559                    movement::end_of_excerpt(
13560                        map,
13561                        selection.head(),
13562                        workspace::searchable::Direction::Next,
13563                    ),
13564                    SelectionGoal::None,
13565                )
13566            });
13567        })
13568    }
13569
13570    pub fn move_to_end_of_previous_excerpt(
13571        &mut self,
13572        _: &MoveToEndOfPreviousExcerpt,
13573        window: &mut Window,
13574        cx: &mut Context<Self>,
13575    ) {
13576        if matches!(self.mode, EditorMode::SingleLine) {
13577            cx.propagate();
13578            return;
13579        }
13580        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13581        self.change_selections(Default::default(), window, cx, |s| {
13582            s.move_with(|map, selection| {
13583                selection.collapse_to(
13584                    movement::end_of_excerpt(
13585                        map,
13586                        selection.head(),
13587                        workspace::searchable::Direction::Prev,
13588                    ),
13589                    SelectionGoal::None,
13590                )
13591            });
13592        })
13593    }
13594
13595    pub fn select_to_start_of_excerpt(
13596        &mut self,
13597        _: &SelectToStartOfExcerpt,
13598        window: &mut Window,
13599        cx: &mut Context<Self>,
13600    ) {
13601        if matches!(self.mode, EditorMode::SingleLine) {
13602            cx.propagate();
13603            return;
13604        }
13605        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13606        self.change_selections(Default::default(), window, cx, |s| {
13607            s.move_heads_with(|map, head, _| {
13608                (
13609                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13610                    SelectionGoal::None,
13611                )
13612            });
13613        })
13614    }
13615
13616    pub fn select_to_start_of_next_excerpt(
13617        &mut self,
13618        _: &SelectToStartOfNextExcerpt,
13619        window: &mut Window,
13620        cx: &mut Context<Self>,
13621    ) {
13622        if matches!(self.mode, EditorMode::SingleLine) {
13623            cx.propagate();
13624            return;
13625        }
13626        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13627        self.change_selections(Default::default(), window, cx, |s| {
13628            s.move_heads_with(|map, head, _| {
13629                (
13630                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13631                    SelectionGoal::None,
13632                )
13633            });
13634        })
13635    }
13636
13637    pub fn select_to_end_of_excerpt(
13638        &mut self,
13639        _: &SelectToEndOfExcerpt,
13640        window: &mut Window,
13641        cx: &mut Context<Self>,
13642    ) {
13643        if matches!(self.mode, EditorMode::SingleLine) {
13644            cx.propagate();
13645            return;
13646        }
13647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13648        self.change_selections(Default::default(), window, cx, |s| {
13649            s.move_heads_with(|map, head, _| {
13650                (
13651                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13652                    SelectionGoal::None,
13653                )
13654            });
13655        })
13656    }
13657
13658    pub fn select_to_end_of_previous_excerpt(
13659        &mut self,
13660        _: &SelectToEndOfPreviousExcerpt,
13661        window: &mut Window,
13662        cx: &mut Context<Self>,
13663    ) {
13664        if matches!(self.mode, EditorMode::SingleLine) {
13665            cx.propagate();
13666            return;
13667        }
13668        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13669        self.change_selections(Default::default(), window, cx, |s| {
13670            s.move_heads_with(|map, head, _| {
13671                (
13672                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13673                    SelectionGoal::None,
13674                )
13675            });
13676        })
13677    }
13678
13679    pub fn move_to_beginning(
13680        &mut self,
13681        _: &MoveToBeginning,
13682        window: &mut Window,
13683        cx: &mut Context<Self>,
13684    ) {
13685        if matches!(self.mode, EditorMode::SingleLine) {
13686            cx.propagate();
13687            return;
13688        }
13689        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13690        self.change_selections(Default::default(), window, cx, |s| {
13691            s.select_ranges(vec![0..0]);
13692        });
13693    }
13694
13695    pub fn select_to_beginning(
13696        &mut self,
13697        _: &SelectToBeginning,
13698        window: &mut Window,
13699        cx: &mut Context<Self>,
13700    ) {
13701        let mut selection = self.selections.last::<Point>(cx);
13702        selection.set_head(Point::zero(), SelectionGoal::None);
13703        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13704        self.change_selections(Default::default(), window, cx, |s| {
13705            s.select(vec![selection]);
13706        });
13707    }
13708
13709    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13710        if matches!(self.mode, EditorMode::SingleLine) {
13711            cx.propagate();
13712            return;
13713        }
13714        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13715        let cursor = self.buffer.read(cx).read(cx).len();
13716        self.change_selections(Default::default(), window, cx, |s| {
13717            s.select_ranges(vec![cursor..cursor])
13718        });
13719    }
13720
13721    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13722        self.nav_history = nav_history;
13723    }
13724
13725    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13726        self.nav_history.as_ref()
13727    }
13728
13729    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13730        self.push_to_nav_history(
13731            self.selections.newest_anchor().head(),
13732            None,
13733            false,
13734            true,
13735            cx,
13736        );
13737    }
13738
13739    fn push_to_nav_history(
13740        &mut self,
13741        cursor_anchor: Anchor,
13742        new_position: Option<Point>,
13743        is_deactivate: bool,
13744        always: bool,
13745        cx: &mut Context<Self>,
13746    ) {
13747        if let Some(nav_history) = self.nav_history.as_mut() {
13748            let buffer = self.buffer.read(cx).read(cx);
13749            let cursor_position = cursor_anchor.to_point(&buffer);
13750            let scroll_state = self.scroll_manager.anchor();
13751            let scroll_top_row = scroll_state.top_row(&buffer);
13752            drop(buffer);
13753
13754            if let Some(new_position) = new_position {
13755                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13756                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13757                    return;
13758                }
13759            }
13760
13761            nav_history.push(
13762                Some(NavigationData {
13763                    cursor_anchor,
13764                    cursor_position,
13765                    scroll_anchor: scroll_state,
13766                    scroll_top_row,
13767                }),
13768                cx,
13769            );
13770            cx.emit(EditorEvent::PushedToNavHistory {
13771                anchor: cursor_anchor,
13772                is_deactivate,
13773            })
13774        }
13775    }
13776
13777    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13778        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13779        let buffer = self.buffer.read(cx).snapshot(cx);
13780        let mut selection = self.selections.first::<usize>(cx);
13781        selection.set_head(buffer.len(), SelectionGoal::None);
13782        self.change_selections(Default::default(), window, cx, |s| {
13783            s.select(vec![selection]);
13784        });
13785    }
13786
13787    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13788        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13789        let end = self.buffer.read(cx).read(cx).len();
13790        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13791            s.select_ranges(vec![0..end]);
13792        });
13793    }
13794
13795    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13796        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13797        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13798        let mut selections = self.selections.all::<Point>(cx);
13799        let max_point = display_map.buffer_snapshot.max_point();
13800        for selection in &mut selections {
13801            let rows = selection.spanned_rows(true, &display_map);
13802            selection.start = Point::new(rows.start.0, 0);
13803            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13804            selection.reversed = false;
13805        }
13806        self.change_selections(Default::default(), window, cx, |s| {
13807            s.select(selections);
13808        });
13809    }
13810
13811    pub fn split_selection_into_lines(
13812        &mut self,
13813        action: &SplitSelectionIntoLines,
13814        window: &mut Window,
13815        cx: &mut Context<Self>,
13816    ) {
13817        let selections = self
13818            .selections
13819            .all::<Point>(cx)
13820            .into_iter()
13821            .map(|selection| selection.start..selection.end)
13822            .collect::<Vec<_>>();
13823        self.unfold_ranges(&selections, true, true, cx);
13824
13825        let mut new_selection_ranges = Vec::new();
13826        {
13827            let buffer = self.buffer.read(cx).read(cx);
13828            for selection in selections {
13829                for row in selection.start.row..selection.end.row {
13830                    let line_start = Point::new(row, 0);
13831                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13832
13833                    if action.keep_selections {
13834                        // Keep the selection range for each line
13835                        let selection_start = if row == selection.start.row {
13836                            selection.start
13837                        } else {
13838                            line_start
13839                        };
13840                        new_selection_ranges.push(selection_start..line_end);
13841                    } else {
13842                        // Collapse to cursor at end of line
13843                        new_selection_ranges.push(line_end..line_end);
13844                    }
13845                }
13846
13847                let is_multiline_selection = selection.start.row != selection.end.row;
13848                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13849                // so this action feels more ergonomic when paired with other selection operations
13850                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13851                if !should_skip_last {
13852                    if action.keep_selections {
13853                        if is_multiline_selection {
13854                            let line_start = Point::new(selection.end.row, 0);
13855                            new_selection_ranges.push(line_start..selection.end);
13856                        } else {
13857                            new_selection_ranges.push(selection.start..selection.end);
13858                        }
13859                    } else {
13860                        new_selection_ranges.push(selection.end..selection.end);
13861                    }
13862                }
13863            }
13864        }
13865        self.change_selections(Default::default(), window, cx, |s| {
13866            s.select_ranges(new_selection_ranges);
13867        });
13868    }
13869
13870    pub fn add_selection_above(
13871        &mut self,
13872        _: &AddSelectionAbove,
13873        window: &mut Window,
13874        cx: &mut Context<Self>,
13875    ) {
13876        self.add_selection(true, window, cx);
13877    }
13878
13879    pub fn add_selection_below(
13880        &mut self,
13881        _: &AddSelectionBelow,
13882        window: &mut Window,
13883        cx: &mut Context<Self>,
13884    ) {
13885        self.add_selection(false, window, cx);
13886    }
13887
13888    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13889        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13890
13891        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13892        let all_selections = self.selections.all::<Point>(cx);
13893        let text_layout_details = self.text_layout_details(window);
13894
13895        let (mut columnar_selections, new_selections_to_columnarize) = {
13896            if let Some(state) = self.add_selections_state.as_ref() {
13897                let columnar_selection_ids: HashSet<_> = state
13898                    .groups
13899                    .iter()
13900                    .flat_map(|group| group.stack.iter())
13901                    .copied()
13902                    .collect();
13903
13904                all_selections
13905                    .into_iter()
13906                    .partition(|s| columnar_selection_ids.contains(&s.id))
13907            } else {
13908                (Vec::new(), all_selections)
13909            }
13910        };
13911
13912        let mut state = self
13913            .add_selections_state
13914            .take()
13915            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13916
13917        for selection in new_selections_to_columnarize {
13918            let range = selection.display_range(&display_map).sorted();
13919            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13920            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13921            let positions = start_x.min(end_x)..start_x.max(end_x);
13922            let mut stack = Vec::new();
13923            for row in range.start.row().0..=range.end.row().0 {
13924                if let Some(selection) = self.selections.build_columnar_selection(
13925                    &display_map,
13926                    DisplayRow(row),
13927                    &positions,
13928                    selection.reversed,
13929                    &text_layout_details,
13930                ) {
13931                    stack.push(selection.id);
13932                    columnar_selections.push(selection);
13933                }
13934            }
13935            if !stack.is_empty() {
13936                if above {
13937                    stack.reverse();
13938                }
13939                state.groups.push(AddSelectionsGroup { above, stack });
13940            }
13941        }
13942
13943        let mut final_selections = Vec::new();
13944        let end_row = if above {
13945            DisplayRow(0)
13946        } else {
13947            display_map.max_point().row()
13948        };
13949
13950        let mut last_added_item_per_group = HashMap::default();
13951        for group in state.groups.iter_mut() {
13952            if let Some(last_id) = group.stack.last() {
13953                last_added_item_per_group.insert(*last_id, group);
13954            }
13955        }
13956
13957        for selection in columnar_selections {
13958            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13959                if above == group.above {
13960                    let range = selection.display_range(&display_map).sorted();
13961                    debug_assert_eq!(range.start.row(), range.end.row());
13962                    let mut row = range.start.row();
13963                    let positions =
13964                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13965                            px(start)..px(end)
13966                        } else {
13967                            let start_x =
13968                                display_map.x_for_display_point(range.start, &text_layout_details);
13969                            let end_x =
13970                                display_map.x_for_display_point(range.end, &text_layout_details);
13971                            start_x.min(end_x)..start_x.max(end_x)
13972                        };
13973
13974                    let mut maybe_new_selection = None;
13975                    while row != end_row {
13976                        if above {
13977                            row.0 -= 1;
13978                        } else {
13979                            row.0 += 1;
13980                        }
13981                        if let Some(new_selection) = self.selections.build_columnar_selection(
13982                            &display_map,
13983                            row,
13984                            &positions,
13985                            selection.reversed,
13986                            &text_layout_details,
13987                        ) {
13988                            maybe_new_selection = Some(new_selection);
13989                            break;
13990                        }
13991                    }
13992
13993                    if let Some(new_selection) = maybe_new_selection {
13994                        group.stack.push(new_selection.id);
13995                        if above {
13996                            final_selections.push(new_selection);
13997                            final_selections.push(selection);
13998                        } else {
13999                            final_selections.push(selection);
14000                            final_selections.push(new_selection);
14001                        }
14002                    } else {
14003                        final_selections.push(selection);
14004                    }
14005                } else {
14006                    group.stack.pop();
14007                }
14008            } else {
14009                final_selections.push(selection);
14010            }
14011        }
14012
14013        self.change_selections(Default::default(), window, cx, |s| {
14014            s.select(final_selections);
14015        });
14016
14017        let final_selection_ids: HashSet<_> = self
14018            .selections
14019            .all::<Point>(cx)
14020            .iter()
14021            .map(|s| s.id)
14022            .collect();
14023        state.groups.retain_mut(|group| {
14024            // selections might get merged above so we remove invalid items from stacks
14025            group.stack.retain(|id| final_selection_ids.contains(id));
14026
14027            // single selection in stack can be treated as initial state
14028            group.stack.len() > 1
14029        });
14030
14031        if !state.groups.is_empty() {
14032            self.add_selections_state = Some(state);
14033        }
14034    }
14035
14036    fn select_match_ranges(
14037        &mut self,
14038        range: Range<usize>,
14039        reversed: bool,
14040        replace_newest: bool,
14041        auto_scroll: Option<Autoscroll>,
14042        window: &mut Window,
14043        cx: &mut Context<Editor>,
14044    ) {
14045        self.unfold_ranges(
14046            std::slice::from_ref(&range),
14047            false,
14048            auto_scroll.is_some(),
14049            cx,
14050        );
14051        let effects = if let Some(scroll) = auto_scroll {
14052            SelectionEffects::scroll(scroll)
14053        } else {
14054            SelectionEffects::no_scroll()
14055        };
14056        self.change_selections(effects, window, cx, |s| {
14057            if replace_newest {
14058                s.delete(s.newest_anchor().id);
14059            }
14060            if reversed {
14061                s.insert_range(range.end..range.start);
14062            } else {
14063                s.insert_range(range);
14064            }
14065        });
14066    }
14067
14068    pub fn select_next_match_internal(
14069        &mut self,
14070        display_map: &DisplaySnapshot,
14071        replace_newest: bool,
14072        autoscroll: Option<Autoscroll>,
14073        window: &mut Window,
14074        cx: &mut Context<Self>,
14075    ) -> Result<()> {
14076        let buffer = &display_map.buffer_snapshot;
14077        let mut selections = self.selections.all::<usize>(cx);
14078        if let Some(mut select_next_state) = self.select_next_state.take() {
14079            let query = &select_next_state.query;
14080            if !select_next_state.done {
14081                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14082                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14083                let mut next_selected_range = None;
14084
14085                let bytes_after_last_selection =
14086                    buffer.bytes_in_range(last_selection.end..buffer.len());
14087                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14088                let query_matches = query
14089                    .stream_find_iter(bytes_after_last_selection)
14090                    .map(|result| (last_selection.end, result))
14091                    .chain(
14092                        query
14093                            .stream_find_iter(bytes_before_first_selection)
14094                            .map(|result| (0, result)),
14095                    );
14096
14097                for (start_offset, query_match) in query_matches {
14098                    let query_match = query_match.unwrap(); // can only fail due to I/O
14099                    let offset_range =
14100                        start_offset + query_match.start()..start_offset + query_match.end();
14101
14102                    if !select_next_state.wordwise
14103                        || (!buffer.is_inside_word(offset_range.start, false)
14104                            && !buffer.is_inside_word(offset_range.end, false))
14105                    {
14106                        // TODO: This is n^2, because we might check all the selections
14107                        if !selections
14108                            .iter()
14109                            .any(|selection| selection.range().overlaps(&offset_range))
14110                        {
14111                            next_selected_range = Some(offset_range);
14112                            break;
14113                        }
14114                    }
14115                }
14116
14117                if let Some(next_selected_range) = next_selected_range {
14118                    self.select_match_ranges(
14119                        next_selected_range,
14120                        last_selection.reversed,
14121                        replace_newest,
14122                        autoscroll,
14123                        window,
14124                        cx,
14125                    );
14126                } else {
14127                    select_next_state.done = true;
14128                }
14129            }
14130
14131            self.select_next_state = Some(select_next_state);
14132        } else {
14133            let mut only_carets = true;
14134            let mut same_text_selected = true;
14135            let mut selected_text = None;
14136
14137            let mut selections_iter = selections.iter().peekable();
14138            while let Some(selection) = selections_iter.next() {
14139                if selection.start != selection.end {
14140                    only_carets = false;
14141                }
14142
14143                if same_text_selected {
14144                    if selected_text.is_none() {
14145                        selected_text =
14146                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14147                    }
14148
14149                    if let Some(next_selection) = selections_iter.peek() {
14150                        if next_selection.range().len() == selection.range().len() {
14151                            let next_selected_text = buffer
14152                                .text_for_range(next_selection.range())
14153                                .collect::<String>();
14154                            if Some(next_selected_text) != selected_text {
14155                                same_text_selected = false;
14156                                selected_text = None;
14157                            }
14158                        } else {
14159                            same_text_selected = false;
14160                            selected_text = None;
14161                        }
14162                    }
14163                }
14164            }
14165
14166            if only_carets {
14167                for selection in &mut selections {
14168                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14169                    selection.start = word_range.start;
14170                    selection.end = word_range.end;
14171                    selection.goal = SelectionGoal::None;
14172                    selection.reversed = false;
14173                    self.select_match_ranges(
14174                        selection.start..selection.end,
14175                        selection.reversed,
14176                        replace_newest,
14177                        autoscroll,
14178                        window,
14179                        cx,
14180                    );
14181                }
14182
14183                if selections.len() == 1 {
14184                    let selection = selections
14185                        .last()
14186                        .expect("ensured that there's only one selection");
14187                    let query = buffer
14188                        .text_for_range(selection.start..selection.end)
14189                        .collect::<String>();
14190                    let is_empty = query.is_empty();
14191                    let select_state = SelectNextState {
14192                        query: AhoCorasick::new(&[query])?,
14193                        wordwise: true,
14194                        done: is_empty,
14195                    };
14196                    self.select_next_state = Some(select_state);
14197                } else {
14198                    self.select_next_state = None;
14199                }
14200            } else if let Some(selected_text) = selected_text {
14201                self.select_next_state = Some(SelectNextState {
14202                    query: AhoCorasick::new(&[selected_text])?,
14203                    wordwise: false,
14204                    done: false,
14205                });
14206                self.select_next_match_internal(
14207                    display_map,
14208                    replace_newest,
14209                    autoscroll,
14210                    window,
14211                    cx,
14212                )?;
14213            }
14214        }
14215        Ok(())
14216    }
14217
14218    pub fn select_all_matches(
14219        &mut self,
14220        _action: &SelectAllMatches,
14221        window: &mut Window,
14222        cx: &mut Context<Self>,
14223    ) -> Result<()> {
14224        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14225
14226        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14227
14228        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14229        let Some(select_next_state) = self.select_next_state.as_mut() else {
14230            return Ok(());
14231        };
14232        if select_next_state.done {
14233            return Ok(());
14234        }
14235
14236        let mut new_selections = Vec::new();
14237
14238        let reversed = self.selections.oldest::<usize>(cx).reversed;
14239        let buffer = &display_map.buffer_snapshot;
14240        let query_matches = select_next_state
14241            .query
14242            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14243
14244        for query_match in query_matches.into_iter() {
14245            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14246            let offset_range = if reversed {
14247                query_match.end()..query_match.start()
14248            } else {
14249                query_match.start()..query_match.end()
14250            };
14251
14252            if !select_next_state.wordwise
14253                || (!buffer.is_inside_word(offset_range.start, false)
14254                    && !buffer.is_inside_word(offset_range.end, false))
14255            {
14256                new_selections.push(offset_range.start..offset_range.end);
14257            }
14258        }
14259
14260        select_next_state.done = true;
14261
14262        if new_selections.is_empty() {
14263            log::error!("bug: new_selections is empty in select_all_matches");
14264            return Ok(());
14265        }
14266
14267        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14268        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14269            selections.select_ranges(new_selections)
14270        });
14271
14272        Ok(())
14273    }
14274
14275    pub fn select_next(
14276        &mut self,
14277        action: &SelectNext,
14278        window: &mut Window,
14279        cx: &mut Context<Self>,
14280    ) -> Result<()> {
14281        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14282        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14283        self.select_next_match_internal(
14284            &display_map,
14285            action.replace_newest,
14286            Some(Autoscroll::newest()),
14287            window,
14288            cx,
14289        )?;
14290        Ok(())
14291    }
14292
14293    pub fn select_previous(
14294        &mut self,
14295        action: &SelectPrevious,
14296        window: &mut Window,
14297        cx: &mut Context<Self>,
14298    ) -> Result<()> {
14299        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14300        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14301        let buffer = &display_map.buffer_snapshot;
14302        let mut selections = self.selections.all::<usize>(cx);
14303        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14304            let query = &select_prev_state.query;
14305            if !select_prev_state.done {
14306                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14307                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14308                let mut next_selected_range = None;
14309                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14310                let bytes_before_last_selection =
14311                    buffer.reversed_bytes_in_range(0..last_selection.start);
14312                let bytes_after_first_selection =
14313                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14314                let query_matches = query
14315                    .stream_find_iter(bytes_before_last_selection)
14316                    .map(|result| (last_selection.start, result))
14317                    .chain(
14318                        query
14319                            .stream_find_iter(bytes_after_first_selection)
14320                            .map(|result| (buffer.len(), result)),
14321                    );
14322                for (end_offset, query_match) in query_matches {
14323                    let query_match = query_match.unwrap(); // can only fail due to I/O
14324                    let offset_range =
14325                        end_offset - query_match.end()..end_offset - query_match.start();
14326
14327                    if !select_prev_state.wordwise
14328                        || (!buffer.is_inside_word(offset_range.start, false)
14329                            && !buffer.is_inside_word(offset_range.end, false))
14330                    {
14331                        next_selected_range = Some(offset_range);
14332                        break;
14333                    }
14334                }
14335
14336                if let Some(next_selected_range) = next_selected_range {
14337                    self.select_match_ranges(
14338                        next_selected_range,
14339                        last_selection.reversed,
14340                        action.replace_newest,
14341                        Some(Autoscroll::newest()),
14342                        window,
14343                        cx,
14344                    );
14345                } else {
14346                    select_prev_state.done = true;
14347                }
14348            }
14349
14350            self.select_prev_state = Some(select_prev_state);
14351        } else {
14352            let mut only_carets = true;
14353            let mut same_text_selected = true;
14354            let mut selected_text = None;
14355
14356            let mut selections_iter = selections.iter().peekable();
14357            while let Some(selection) = selections_iter.next() {
14358                if selection.start != selection.end {
14359                    only_carets = false;
14360                }
14361
14362                if same_text_selected {
14363                    if selected_text.is_none() {
14364                        selected_text =
14365                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14366                    }
14367
14368                    if let Some(next_selection) = selections_iter.peek() {
14369                        if next_selection.range().len() == selection.range().len() {
14370                            let next_selected_text = buffer
14371                                .text_for_range(next_selection.range())
14372                                .collect::<String>();
14373                            if Some(next_selected_text) != selected_text {
14374                                same_text_selected = false;
14375                                selected_text = None;
14376                            }
14377                        } else {
14378                            same_text_selected = false;
14379                            selected_text = None;
14380                        }
14381                    }
14382                }
14383            }
14384
14385            if only_carets {
14386                for selection in &mut selections {
14387                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14388                    selection.start = word_range.start;
14389                    selection.end = word_range.end;
14390                    selection.goal = SelectionGoal::None;
14391                    selection.reversed = false;
14392                    self.select_match_ranges(
14393                        selection.start..selection.end,
14394                        selection.reversed,
14395                        action.replace_newest,
14396                        Some(Autoscroll::newest()),
14397                        window,
14398                        cx,
14399                    );
14400                }
14401                if selections.len() == 1 {
14402                    let selection = selections
14403                        .last()
14404                        .expect("ensured that there's only one selection");
14405                    let query = buffer
14406                        .text_for_range(selection.start..selection.end)
14407                        .collect::<String>();
14408                    let is_empty = query.is_empty();
14409                    let select_state = SelectNextState {
14410                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14411                        wordwise: true,
14412                        done: is_empty,
14413                    };
14414                    self.select_prev_state = Some(select_state);
14415                } else {
14416                    self.select_prev_state = None;
14417                }
14418            } else if let Some(selected_text) = selected_text {
14419                self.select_prev_state = Some(SelectNextState {
14420                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14421                    wordwise: false,
14422                    done: false,
14423                });
14424                self.select_previous(action, window, cx)?;
14425            }
14426        }
14427        Ok(())
14428    }
14429
14430    pub fn find_next_match(
14431        &mut self,
14432        _: &FindNextMatch,
14433        window: &mut Window,
14434        cx: &mut Context<Self>,
14435    ) -> Result<()> {
14436        let selections = self.selections.disjoint_anchors();
14437        match selections.first() {
14438            Some(first) if selections.len() >= 2 => {
14439                self.change_selections(Default::default(), window, cx, |s| {
14440                    s.select_ranges([first.range()]);
14441                });
14442            }
14443            _ => self.select_next(
14444                &SelectNext {
14445                    replace_newest: true,
14446                },
14447                window,
14448                cx,
14449            )?,
14450        }
14451        Ok(())
14452    }
14453
14454    pub fn find_previous_match(
14455        &mut self,
14456        _: &FindPreviousMatch,
14457        window: &mut Window,
14458        cx: &mut Context<Self>,
14459    ) -> Result<()> {
14460        let selections = self.selections.disjoint_anchors();
14461        match selections.last() {
14462            Some(last) if selections.len() >= 2 => {
14463                self.change_selections(Default::default(), window, cx, |s| {
14464                    s.select_ranges([last.range()]);
14465                });
14466            }
14467            _ => self.select_previous(
14468                &SelectPrevious {
14469                    replace_newest: true,
14470                },
14471                window,
14472                cx,
14473            )?,
14474        }
14475        Ok(())
14476    }
14477
14478    pub fn toggle_comments(
14479        &mut self,
14480        action: &ToggleComments,
14481        window: &mut Window,
14482        cx: &mut Context<Self>,
14483    ) {
14484        if self.read_only(cx) {
14485            return;
14486        }
14487        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14488        let text_layout_details = &self.text_layout_details(window);
14489        self.transact(window, cx, |this, window, cx| {
14490            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14491            let mut edits = Vec::new();
14492            let mut selection_edit_ranges = Vec::new();
14493            let mut last_toggled_row = None;
14494            let snapshot = this.buffer.read(cx).read(cx);
14495            let empty_str: Arc<str> = Arc::default();
14496            let mut suffixes_inserted = Vec::new();
14497            let ignore_indent = action.ignore_indent;
14498
14499            fn comment_prefix_range(
14500                snapshot: &MultiBufferSnapshot,
14501                row: MultiBufferRow,
14502                comment_prefix: &str,
14503                comment_prefix_whitespace: &str,
14504                ignore_indent: bool,
14505            ) -> Range<Point> {
14506                let indent_size = if ignore_indent {
14507                    0
14508                } else {
14509                    snapshot.indent_size_for_line(row).len
14510                };
14511
14512                let start = Point::new(row.0, indent_size);
14513
14514                let mut line_bytes = snapshot
14515                    .bytes_in_range(start..snapshot.max_point())
14516                    .flatten()
14517                    .copied();
14518
14519                // If this line currently begins with the line comment prefix, then record
14520                // the range containing the prefix.
14521                if line_bytes
14522                    .by_ref()
14523                    .take(comment_prefix.len())
14524                    .eq(comment_prefix.bytes())
14525                {
14526                    // Include any whitespace that matches the comment prefix.
14527                    let matching_whitespace_len = line_bytes
14528                        .zip(comment_prefix_whitespace.bytes())
14529                        .take_while(|(a, b)| a == b)
14530                        .count() as u32;
14531                    let end = Point::new(
14532                        start.row,
14533                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14534                    );
14535                    start..end
14536                } else {
14537                    start..start
14538                }
14539            }
14540
14541            fn comment_suffix_range(
14542                snapshot: &MultiBufferSnapshot,
14543                row: MultiBufferRow,
14544                comment_suffix: &str,
14545                comment_suffix_has_leading_space: bool,
14546            ) -> Range<Point> {
14547                let end = Point::new(row.0, snapshot.line_len(row));
14548                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14549
14550                let mut line_end_bytes = snapshot
14551                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14552                    .flatten()
14553                    .copied();
14554
14555                let leading_space_len = if suffix_start_column > 0
14556                    && line_end_bytes.next() == Some(b' ')
14557                    && comment_suffix_has_leading_space
14558                {
14559                    1
14560                } else {
14561                    0
14562                };
14563
14564                // If this line currently begins with the line comment prefix, then record
14565                // the range containing the prefix.
14566                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14567                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14568                    start..end
14569                } else {
14570                    end..end
14571                }
14572            }
14573
14574            // TODO: Handle selections that cross excerpts
14575            for selection in &mut selections {
14576                let start_column = snapshot
14577                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14578                    .len;
14579                let language = if let Some(language) =
14580                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14581                {
14582                    language
14583                } else {
14584                    continue;
14585                };
14586
14587                selection_edit_ranges.clear();
14588
14589                // If multiple selections contain a given row, avoid processing that
14590                // row more than once.
14591                let mut start_row = MultiBufferRow(selection.start.row);
14592                if last_toggled_row == Some(start_row) {
14593                    start_row = start_row.next_row();
14594                }
14595                let end_row =
14596                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14597                        MultiBufferRow(selection.end.row - 1)
14598                    } else {
14599                        MultiBufferRow(selection.end.row)
14600                    };
14601                last_toggled_row = Some(end_row);
14602
14603                if start_row > end_row {
14604                    continue;
14605                }
14606
14607                // If the language has line comments, toggle those.
14608                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14609
14610                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14611                if ignore_indent {
14612                    full_comment_prefixes = full_comment_prefixes
14613                        .into_iter()
14614                        .map(|s| Arc::from(s.trim_end()))
14615                        .collect();
14616                }
14617
14618                if !full_comment_prefixes.is_empty() {
14619                    let first_prefix = full_comment_prefixes
14620                        .first()
14621                        .expect("prefixes is non-empty");
14622                    let prefix_trimmed_lengths = full_comment_prefixes
14623                        .iter()
14624                        .map(|p| p.trim_end_matches(' ').len())
14625                        .collect::<SmallVec<[usize; 4]>>();
14626
14627                    let mut all_selection_lines_are_comments = true;
14628
14629                    for row in start_row.0..=end_row.0 {
14630                        let row = MultiBufferRow(row);
14631                        if start_row < end_row && snapshot.is_line_blank(row) {
14632                            continue;
14633                        }
14634
14635                        let prefix_range = full_comment_prefixes
14636                            .iter()
14637                            .zip(prefix_trimmed_lengths.iter().copied())
14638                            .map(|(prefix, trimmed_prefix_len)| {
14639                                comment_prefix_range(
14640                                    snapshot.deref(),
14641                                    row,
14642                                    &prefix[..trimmed_prefix_len],
14643                                    &prefix[trimmed_prefix_len..],
14644                                    ignore_indent,
14645                                )
14646                            })
14647                            .max_by_key(|range| range.end.column - range.start.column)
14648                            .expect("prefixes is non-empty");
14649
14650                        if prefix_range.is_empty() {
14651                            all_selection_lines_are_comments = false;
14652                        }
14653
14654                        selection_edit_ranges.push(prefix_range);
14655                    }
14656
14657                    if all_selection_lines_are_comments {
14658                        edits.extend(
14659                            selection_edit_ranges
14660                                .iter()
14661                                .cloned()
14662                                .map(|range| (range, empty_str.clone())),
14663                        );
14664                    } else {
14665                        let min_column = selection_edit_ranges
14666                            .iter()
14667                            .map(|range| range.start.column)
14668                            .min()
14669                            .unwrap_or(0);
14670                        edits.extend(selection_edit_ranges.iter().map(|range| {
14671                            let position = Point::new(range.start.row, min_column);
14672                            (position..position, first_prefix.clone())
14673                        }));
14674                    }
14675                } else if let Some(BlockCommentConfig {
14676                    start: full_comment_prefix,
14677                    end: comment_suffix,
14678                    ..
14679                }) = language.block_comment()
14680                {
14681                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14682                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14683                    let prefix_range = comment_prefix_range(
14684                        snapshot.deref(),
14685                        start_row,
14686                        comment_prefix,
14687                        comment_prefix_whitespace,
14688                        ignore_indent,
14689                    );
14690                    let suffix_range = comment_suffix_range(
14691                        snapshot.deref(),
14692                        end_row,
14693                        comment_suffix.trim_start_matches(' '),
14694                        comment_suffix.starts_with(' '),
14695                    );
14696
14697                    if prefix_range.is_empty() || suffix_range.is_empty() {
14698                        edits.push((
14699                            prefix_range.start..prefix_range.start,
14700                            full_comment_prefix.clone(),
14701                        ));
14702                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14703                        suffixes_inserted.push((end_row, comment_suffix.len()));
14704                    } else {
14705                        edits.push((prefix_range, empty_str.clone()));
14706                        edits.push((suffix_range, empty_str.clone()));
14707                    }
14708                } else {
14709                    continue;
14710                }
14711            }
14712
14713            drop(snapshot);
14714            this.buffer.update(cx, |buffer, cx| {
14715                buffer.edit(edits, None, cx);
14716            });
14717
14718            // Adjust selections so that they end before any comment suffixes that
14719            // were inserted.
14720            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14721            let mut selections = this.selections.all::<Point>(cx);
14722            let snapshot = this.buffer.read(cx).read(cx);
14723            for selection in &mut selections {
14724                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14725                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14726                        Ordering::Less => {
14727                            suffixes_inserted.next();
14728                            continue;
14729                        }
14730                        Ordering::Greater => break,
14731                        Ordering::Equal => {
14732                            if selection.end.column == snapshot.line_len(row) {
14733                                if selection.is_empty() {
14734                                    selection.start.column -= suffix_len as u32;
14735                                }
14736                                selection.end.column -= suffix_len as u32;
14737                            }
14738                            break;
14739                        }
14740                    }
14741                }
14742            }
14743
14744            drop(snapshot);
14745            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14746
14747            let selections = this.selections.all::<Point>(cx);
14748            let selections_on_single_row = selections.windows(2).all(|selections| {
14749                selections[0].start.row == selections[1].start.row
14750                    && selections[0].end.row == selections[1].end.row
14751                    && selections[0].start.row == selections[0].end.row
14752            });
14753            let selections_selecting = selections
14754                .iter()
14755                .any(|selection| selection.start != selection.end);
14756            let advance_downwards = action.advance_downwards
14757                && selections_on_single_row
14758                && !selections_selecting
14759                && !matches!(this.mode, EditorMode::SingleLine);
14760
14761            if advance_downwards {
14762                let snapshot = this.buffer.read(cx).snapshot(cx);
14763
14764                this.change_selections(Default::default(), window, cx, |s| {
14765                    s.move_cursors_with(|display_snapshot, display_point, _| {
14766                        let mut point = display_point.to_point(display_snapshot);
14767                        point.row += 1;
14768                        point = snapshot.clip_point(point, Bias::Left);
14769                        let display_point = point.to_display_point(display_snapshot);
14770                        let goal = SelectionGoal::HorizontalPosition(
14771                            display_snapshot
14772                                .x_for_display_point(display_point, text_layout_details)
14773                                .into(),
14774                        );
14775                        (display_point, goal)
14776                    })
14777                });
14778            }
14779        });
14780    }
14781
14782    pub fn select_enclosing_symbol(
14783        &mut self,
14784        _: &SelectEnclosingSymbol,
14785        window: &mut Window,
14786        cx: &mut Context<Self>,
14787    ) {
14788        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14789
14790        let buffer = self.buffer.read(cx).snapshot(cx);
14791        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14792
14793        fn update_selection(
14794            selection: &Selection<usize>,
14795            buffer_snap: &MultiBufferSnapshot,
14796        ) -> Option<Selection<usize>> {
14797            let cursor = selection.head();
14798            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14799            for symbol in symbols.iter().rev() {
14800                let start = symbol.range.start.to_offset(buffer_snap);
14801                let end = symbol.range.end.to_offset(buffer_snap);
14802                let new_range = start..end;
14803                if start < selection.start || end > selection.end {
14804                    return Some(Selection {
14805                        id: selection.id,
14806                        start: new_range.start,
14807                        end: new_range.end,
14808                        goal: SelectionGoal::None,
14809                        reversed: selection.reversed,
14810                    });
14811                }
14812            }
14813            None
14814        }
14815
14816        let mut selected_larger_symbol = false;
14817        let new_selections = old_selections
14818            .iter()
14819            .map(|selection| match update_selection(selection, &buffer) {
14820                Some(new_selection) => {
14821                    if new_selection.range() != selection.range() {
14822                        selected_larger_symbol = true;
14823                    }
14824                    new_selection
14825                }
14826                None => selection.clone(),
14827            })
14828            .collect::<Vec<_>>();
14829
14830        if selected_larger_symbol {
14831            self.change_selections(Default::default(), window, cx, |s| {
14832                s.select(new_selections);
14833            });
14834        }
14835    }
14836
14837    pub fn select_larger_syntax_node(
14838        &mut self,
14839        _: &SelectLargerSyntaxNode,
14840        window: &mut Window,
14841        cx: &mut Context<Self>,
14842    ) {
14843        let Some(visible_row_count) = self.visible_row_count() else {
14844            return;
14845        };
14846        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14847        if old_selections.is_empty() {
14848            return;
14849        }
14850
14851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14852
14853        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14854        let buffer = self.buffer.read(cx).snapshot(cx);
14855
14856        let mut selected_larger_node = false;
14857        let mut new_selections = old_selections
14858            .iter()
14859            .map(|selection| {
14860                let old_range = selection.start..selection.end;
14861
14862                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14863                    // manually select word at selection
14864                    if ["string_content", "inline"].contains(&node.kind()) {
14865                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14866                        // ignore if word is already selected
14867                        if !word_range.is_empty() && old_range != word_range {
14868                            let (last_word_range, _) =
14869                                buffer.surrounding_word(old_range.end, false);
14870                            // only select word if start and end point belongs to same word
14871                            if word_range == last_word_range {
14872                                selected_larger_node = true;
14873                                return Selection {
14874                                    id: selection.id,
14875                                    start: word_range.start,
14876                                    end: word_range.end,
14877                                    goal: SelectionGoal::None,
14878                                    reversed: selection.reversed,
14879                                };
14880                            }
14881                        }
14882                    }
14883                }
14884
14885                let mut new_range = old_range.clone();
14886                while let Some((_node, containing_range)) =
14887                    buffer.syntax_ancestor(new_range.clone())
14888                {
14889                    new_range = match containing_range {
14890                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14891                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14892                    };
14893                    if !display_map.intersects_fold(new_range.start)
14894                        && !display_map.intersects_fold(new_range.end)
14895                    {
14896                        break;
14897                    }
14898                }
14899
14900                selected_larger_node |= new_range != old_range;
14901                Selection {
14902                    id: selection.id,
14903                    start: new_range.start,
14904                    end: new_range.end,
14905                    goal: SelectionGoal::None,
14906                    reversed: selection.reversed,
14907                }
14908            })
14909            .collect::<Vec<_>>();
14910
14911        if !selected_larger_node {
14912            return; // don't put this call in the history
14913        }
14914
14915        // scroll based on transformation done to the last selection created by the user
14916        let (last_old, last_new) = old_selections
14917            .last()
14918            .zip(new_selections.last().cloned())
14919            .expect("old_selections isn't empty");
14920
14921        // revert selection
14922        let is_selection_reversed = {
14923            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14924            new_selections.last_mut().expect("checked above").reversed =
14925                should_newest_selection_be_reversed;
14926            should_newest_selection_be_reversed
14927        };
14928
14929        if selected_larger_node {
14930            self.select_syntax_node_history.disable_clearing = true;
14931            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14932                s.select(new_selections.clone());
14933            });
14934            self.select_syntax_node_history.disable_clearing = false;
14935        }
14936
14937        let start_row = last_new.start.to_display_point(&display_map).row().0;
14938        let end_row = last_new.end.to_display_point(&display_map).row().0;
14939        let selection_height = end_row - start_row + 1;
14940        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14941
14942        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14943        let scroll_behavior = if fits_on_the_screen {
14944            self.request_autoscroll(Autoscroll::fit(), cx);
14945            SelectSyntaxNodeScrollBehavior::FitSelection
14946        } else if is_selection_reversed {
14947            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14948            SelectSyntaxNodeScrollBehavior::CursorTop
14949        } else {
14950            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14951            SelectSyntaxNodeScrollBehavior::CursorBottom
14952        };
14953
14954        self.select_syntax_node_history.push((
14955            old_selections,
14956            scroll_behavior,
14957            is_selection_reversed,
14958        ));
14959    }
14960
14961    pub fn select_smaller_syntax_node(
14962        &mut self,
14963        _: &SelectSmallerSyntaxNode,
14964        window: &mut Window,
14965        cx: &mut Context<Self>,
14966    ) {
14967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14968
14969        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14970            self.select_syntax_node_history.pop()
14971        {
14972            if let Some(selection) = selections.last_mut() {
14973                selection.reversed = is_selection_reversed;
14974            }
14975
14976            self.select_syntax_node_history.disable_clearing = true;
14977            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14978                s.select(selections.to_vec());
14979            });
14980            self.select_syntax_node_history.disable_clearing = false;
14981
14982            match scroll_behavior {
14983                SelectSyntaxNodeScrollBehavior::CursorTop => {
14984                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14985                }
14986                SelectSyntaxNodeScrollBehavior::FitSelection => {
14987                    self.request_autoscroll(Autoscroll::fit(), cx);
14988                }
14989                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14990                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14991                }
14992            }
14993        }
14994    }
14995
14996    pub fn unwrap_syntax_node(
14997        &mut self,
14998        _: &UnwrapSyntaxNode,
14999        window: &mut Window,
15000        cx: &mut Context<Self>,
15001    ) {
15002        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15003
15004        let buffer = self.buffer.read(cx).snapshot(cx);
15005        let selections = self
15006            .selections
15007            .all::<usize>(cx)
15008            .into_iter()
15009            // subtracting the offset requires sorting
15010            .sorted_by_key(|i| i.start);
15011
15012        let full_edits = selections
15013            .into_iter()
15014            .filter_map(|selection| {
15015                // Only requires two branches once if-let-chains stabilize (#53667)
15016                let child = if !selection.is_empty() {
15017                    selection.range()
15018                } else if let Some((_, ancestor_range)) =
15019                    buffer.syntax_ancestor(selection.start..selection.end)
15020                {
15021                    match ancestor_range {
15022                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15023                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15024                    }
15025                } else {
15026                    selection.range()
15027                };
15028
15029                let mut parent = child.clone();
15030                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15031                    parent = match ancestor_range {
15032                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15033                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15034                    };
15035                    if parent.start < child.start || parent.end > child.end {
15036                        break;
15037                    }
15038                }
15039
15040                if parent == child {
15041                    return None;
15042                }
15043                let text = buffer.text_for_range(child).collect::<String>();
15044                Some((selection.id, parent, text))
15045            })
15046            .collect::<Vec<_>>();
15047
15048        self.transact(window, cx, |this, window, cx| {
15049            this.buffer.update(cx, |buffer, cx| {
15050                buffer.edit(
15051                    full_edits
15052                        .iter()
15053                        .map(|(_, p, t)| (p.clone(), t.clone()))
15054                        .collect::<Vec<_>>(),
15055                    None,
15056                    cx,
15057                );
15058            });
15059            this.change_selections(Default::default(), window, cx, |s| {
15060                let mut offset = 0;
15061                let mut selections = vec![];
15062                for (id, parent, text) in full_edits {
15063                    let start = parent.start - offset;
15064                    offset += parent.len() - text.len();
15065                    selections.push(Selection {
15066                        id,
15067                        start,
15068                        end: start + text.len(),
15069                        reversed: false,
15070                        goal: Default::default(),
15071                    });
15072                }
15073                s.select(selections);
15074            });
15075        });
15076    }
15077
15078    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15079        if !EditorSettings::get_global(cx).gutter.runnables {
15080            self.clear_tasks();
15081            return Task::ready(());
15082        }
15083        let project = self.project().map(Entity::downgrade);
15084        let task_sources = self.lsp_task_sources(cx);
15085        let multi_buffer = self.buffer.downgrade();
15086        cx.spawn_in(window, async move |editor, cx| {
15087            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15088            let Some(project) = project.and_then(|p| p.upgrade()) else {
15089                return;
15090            };
15091            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15092                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15093            }) else {
15094                return;
15095            };
15096
15097            let hide_runnables = project
15098                .update(cx, |project, _| project.is_via_collab())
15099                .unwrap_or(true);
15100            if hide_runnables {
15101                return;
15102            }
15103            let new_rows =
15104                cx.background_spawn({
15105                    let snapshot = display_snapshot.clone();
15106                    async move {
15107                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15108                    }
15109                })
15110                    .await;
15111            let Ok(lsp_tasks) =
15112                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15113            else {
15114                return;
15115            };
15116            let lsp_tasks = lsp_tasks.await;
15117
15118            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15119                lsp_tasks
15120                    .into_iter()
15121                    .flat_map(|(kind, tasks)| {
15122                        tasks.into_iter().filter_map(move |(location, task)| {
15123                            Some((kind.clone(), location?, task))
15124                        })
15125                    })
15126                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15127                        let buffer = location.target.buffer;
15128                        let buffer_snapshot = buffer.read(cx).snapshot();
15129                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15130                            |(excerpt_id, snapshot, _)| {
15131                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15132                                    display_snapshot
15133                                        .buffer_snapshot
15134                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15135                                } else {
15136                                    None
15137                                }
15138                            },
15139                        );
15140                        if let Some(offset) = offset {
15141                            let task_buffer_range =
15142                                location.target.range.to_point(&buffer_snapshot);
15143                            let context_buffer_range =
15144                                task_buffer_range.to_offset(&buffer_snapshot);
15145                            let context_range = BufferOffset(context_buffer_range.start)
15146                                ..BufferOffset(context_buffer_range.end);
15147
15148                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15149                                .or_insert_with(|| RunnableTasks {
15150                                    templates: Vec::new(),
15151                                    offset,
15152                                    column: task_buffer_range.start.column,
15153                                    extra_variables: HashMap::default(),
15154                                    context_range,
15155                                })
15156                                .templates
15157                                .push((kind, task.original_task().clone()));
15158                        }
15159
15160                        acc
15161                    })
15162            }) else {
15163                return;
15164            };
15165
15166            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15167                buffer.language_settings(cx).tasks.prefer_lsp
15168            }) else {
15169                return;
15170            };
15171
15172            let rows = Self::runnable_rows(
15173                project,
15174                display_snapshot,
15175                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15176                new_rows,
15177                cx.clone(),
15178            )
15179            .await;
15180            editor
15181                .update(cx, |editor, _| {
15182                    editor.clear_tasks();
15183                    for (key, mut value) in rows {
15184                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15185                            value.templates.extend(lsp_tasks.templates);
15186                        }
15187
15188                        editor.insert_tasks(key, value);
15189                    }
15190                    for (key, value) in lsp_tasks_by_rows {
15191                        editor.insert_tasks(key, value);
15192                    }
15193                })
15194                .ok();
15195        })
15196    }
15197    fn fetch_runnable_ranges(
15198        snapshot: &DisplaySnapshot,
15199        range: Range<Anchor>,
15200    ) -> Vec<language::RunnableRange> {
15201        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15202    }
15203
15204    fn runnable_rows(
15205        project: Entity<Project>,
15206        snapshot: DisplaySnapshot,
15207        prefer_lsp: bool,
15208        runnable_ranges: Vec<RunnableRange>,
15209        cx: AsyncWindowContext,
15210    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15211        cx.spawn(async move |cx| {
15212            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15213            for mut runnable in runnable_ranges {
15214                let Some(tasks) = cx
15215                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15216                    .ok()
15217                else {
15218                    continue;
15219                };
15220                let mut tasks = tasks.await;
15221
15222                if prefer_lsp {
15223                    tasks.retain(|(task_kind, _)| {
15224                        !matches!(task_kind, TaskSourceKind::Language { .. })
15225                    });
15226                }
15227                if tasks.is_empty() {
15228                    continue;
15229                }
15230
15231                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15232                let Some(row) = snapshot
15233                    .buffer_snapshot
15234                    .buffer_line_for_row(MultiBufferRow(point.row))
15235                    .map(|(_, range)| range.start.row)
15236                else {
15237                    continue;
15238                };
15239
15240                let context_range =
15241                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15242                runnable_rows.push((
15243                    (runnable.buffer_id, row),
15244                    RunnableTasks {
15245                        templates: tasks,
15246                        offset: snapshot
15247                            .buffer_snapshot
15248                            .anchor_before(runnable.run_range.start),
15249                        context_range,
15250                        column: point.column,
15251                        extra_variables: runnable.extra_captures,
15252                    },
15253                ));
15254            }
15255            runnable_rows
15256        })
15257    }
15258
15259    fn templates_with_tags(
15260        project: &Entity<Project>,
15261        runnable: &mut Runnable,
15262        cx: &mut App,
15263    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15264        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15265            let (worktree_id, file) = project
15266                .buffer_for_id(runnable.buffer, cx)
15267                .and_then(|buffer| buffer.read(cx).file())
15268                .map(|file| (file.worktree_id(cx), file.clone()))
15269                .unzip();
15270
15271            (
15272                project.task_store().read(cx).task_inventory().cloned(),
15273                worktree_id,
15274                file,
15275            )
15276        });
15277
15278        let tags = mem::take(&mut runnable.tags);
15279        let language = runnable.language.clone();
15280        cx.spawn(async move |cx| {
15281            let mut templates_with_tags = Vec::new();
15282            if let Some(inventory) = inventory {
15283                for RunnableTag(tag) in tags {
15284                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15285                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15286                    }) else {
15287                        return templates_with_tags;
15288                    };
15289                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15290                        move |(_, template)| {
15291                            template.tags.iter().any(|source_tag| source_tag == &tag)
15292                        },
15293                    ));
15294                }
15295            }
15296            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15297
15298            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15299                // Strongest source wins; if we have worktree tag binding, prefer that to
15300                // global and language bindings;
15301                // if we have a global binding, prefer that to language binding.
15302                let first_mismatch = templates_with_tags
15303                    .iter()
15304                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15305                if let Some(index) = first_mismatch {
15306                    templates_with_tags.truncate(index);
15307                }
15308            }
15309
15310            templates_with_tags
15311        })
15312    }
15313
15314    pub fn move_to_enclosing_bracket(
15315        &mut self,
15316        _: &MoveToEnclosingBracket,
15317        window: &mut Window,
15318        cx: &mut Context<Self>,
15319    ) {
15320        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15321        self.change_selections(Default::default(), window, cx, |s| {
15322            s.move_offsets_with(|snapshot, selection| {
15323                let Some(enclosing_bracket_ranges) =
15324                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15325                else {
15326                    return;
15327                };
15328
15329                let mut best_length = usize::MAX;
15330                let mut best_inside = false;
15331                let mut best_in_bracket_range = false;
15332                let mut best_destination = None;
15333                for (open, close) in enclosing_bracket_ranges {
15334                    let close = close.to_inclusive();
15335                    let length = close.end() - open.start;
15336                    let inside = selection.start >= open.end && selection.end <= *close.start();
15337                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15338                        || close.contains(&selection.head());
15339
15340                    // If best is next to a bracket and current isn't, skip
15341                    if !in_bracket_range && best_in_bracket_range {
15342                        continue;
15343                    }
15344
15345                    // Prefer smaller lengths unless best is inside and current isn't
15346                    if length > best_length && (best_inside || !inside) {
15347                        continue;
15348                    }
15349
15350                    best_length = length;
15351                    best_inside = inside;
15352                    best_in_bracket_range = in_bracket_range;
15353                    best_destination = Some(
15354                        if close.contains(&selection.start) && close.contains(&selection.end) {
15355                            if inside { open.end } else { open.start }
15356                        } else if inside {
15357                            *close.start()
15358                        } else {
15359                            *close.end()
15360                        },
15361                    );
15362                }
15363
15364                if let Some(destination) = best_destination {
15365                    selection.collapse_to(destination, SelectionGoal::None);
15366                }
15367            })
15368        });
15369    }
15370
15371    pub fn undo_selection(
15372        &mut self,
15373        _: &UndoSelection,
15374        window: &mut Window,
15375        cx: &mut Context<Self>,
15376    ) {
15377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15378        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15379            self.selection_history.mode = SelectionHistoryMode::Undoing;
15380            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15381                this.end_selection(window, cx);
15382                this.change_selections(
15383                    SelectionEffects::scroll(Autoscroll::newest()),
15384                    window,
15385                    cx,
15386                    |s| s.select_anchors(entry.selections.to_vec()),
15387                );
15388            });
15389            self.selection_history.mode = SelectionHistoryMode::Normal;
15390
15391            self.select_next_state = entry.select_next_state;
15392            self.select_prev_state = entry.select_prev_state;
15393            self.add_selections_state = entry.add_selections_state;
15394        }
15395    }
15396
15397    pub fn redo_selection(
15398        &mut self,
15399        _: &RedoSelection,
15400        window: &mut Window,
15401        cx: &mut Context<Self>,
15402    ) {
15403        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15404        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15405            self.selection_history.mode = SelectionHistoryMode::Redoing;
15406            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15407                this.end_selection(window, cx);
15408                this.change_selections(
15409                    SelectionEffects::scroll(Autoscroll::newest()),
15410                    window,
15411                    cx,
15412                    |s| s.select_anchors(entry.selections.to_vec()),
15413                );
15414            });
15415            self.selection_history.mode = SelectionHistoryMode::Normal;
15416
15417            self.select_next_state = entry.select_next_state;
15418            self.select_prev_state = entry.select_prev_state;
15419            self.add_selections_state = entry.add_selections_state;
15420        }
15421    }
15422
15423    pub fn expand_excerpts(
15424        &mut self,
15425        action: &ExpandExcerpts,
15426        _: &mut Window,
15427        cx: &mut Context<Self>,
15428    ) {
15429        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15430    }
15431
15432    pub fn expand_excerpts_down(
15433        &mut self,
15434        action: &ExpandExcerptsDown,
15435        _: &mut Window,
15436        cx: &mut Context<Self>,
15437    ) {
15438        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15439    }
15440
15441    pub fn expand_excerpts_up(
15442        &mut self,
15443        action: &ExpandExcerptsUp,
15444        _: &mut Window,
15445        cx: &mut Context<Self>,
15446    ) {
15447        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15448    }
15449
15450    pub fn expand_excerpts_for_direction(
15451        &mut self,
15452        lines: u32,
15453        direction: ExpandExcerptDirection,
15454
15455        cx: &mut Context<Self>,
15456    ) {
15457        let selections = self.selections.disjoint_anchors();
15458
15459        let lines = if lines == 0 {
15460            EditorSettings::get_global(cx).expand_excerpt_lines
15461        } else {
15462            lines
15463        };
15464
15465        self.buffer.update(cx, |buffer, cx| {
15466            let snapshot = buffer.snapshot(cx);
15467            let mut excerpt_ids = selections
15468                .iter()
15469                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15470                .collect::<Vec<_>>();
15471            excerpt_ids.sort();
15472            excerpt_ids.dedup();
15473            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15474        })
15475    }
15476
15477    pub fn expand_excerpt(
15478        &mut self,
15479        excerpt: ExcerptId,
15480        direction: ExpandExcerptDirection,
15481        window: &mut Window,
15482        cx: &mut Context<Self>,
15483    ) {
15484        let current_scroll_position = self.scroll_position(cx);
15485        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15486        let mut should_scroll_up = false;
15487
15488        if direction == ExpandExcerptDirection::Down {
15489            let multi_buffer = self.buffer.read(cx);
15490            let snapshot = multi_buffer.snapshot(cx);
15491            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15492                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15493                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15494            {
15495                let buffer_snapshot = buffer.read(cx).snapshot();
15496                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15497                let last_row = buffer_snapshot.max_point().row;
15498                let lines_below = last_row.saturating_sub(excerpt_end_row);
15499                should_scroll_up = lines_below >= lines_to_expand;
15500            }
15501        }
15502
15503        self.buffer.update(cx, |buffer, cx| {
15504            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15505        });
15506
15507        if should_scroll_up {
15508            let new_scroll_position =
15509                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15510            self.set_scroll_position(new_scroll_position, window, cx);
15511        }
15512    }
15513
15514    pub fn go_to_singleton_buffer_point(
15515        &mut self,
15516        point: Point,
15517        window: &mut Window,
15518        cx: &mut Context<Self>,
15519    ) {
15520        self.go_to_singleton_buffer_range(point..point, window, cx);
15521    }
15522
15523    pub fn go_to_singleton_buffer_range(
15524        &mut self,
15525        range: Range<Point>,
15526        window: &mut Window,
15527        cx: &mut Context<Self>,
15528    ) {
15529        let multibuffer = self.buffer().read(cx);
15530        let Some(buffer) = multibuffer.as_singleton() else {
15531            return;
15532        };
15533        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15534            return;
15535        };
15536        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15537            return;
15538        };
15539        self.change_selections(
15540            SelectionEffects::default().nav_history(true),
15541            window,
15542            cx,
15543            |s| s.select_anchor_ranges([start..end]),
15544        );
15545    }
15546
15547    pub fn go_to_diagnostic(
15548        &mut self,
15549        action: &GoToDiagnostic,
15550        window: &mut Window,
15551        cx: &mut Context<Self>,
15552    ) {
15553        if !self.diagnostics_enabled() {
15554            return;
15555        }
15556        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15557        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15558    }
15559
15560    pub fn go_to_prev_diagnostic(
15561        &mut self,
15562        action: &GoToPreviousDiagnostic,
15563        window: &mut Window,
15564        cx: &mut Context<Self>,
15565    ) {
15566        if !self.diagnostics_enabled() {
15567            return;
15568        }
15569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15570        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15571    }
15572
15573    pub fn go_to_diagnostic_impl(
15574        &mut self,
15575        direction: Direction,
15576        severity: GoToDiagnosticSeverityFilter,
15577        window: &mut Window,
15578        cx: &mut Context<Self>,
15579    ) {
15580        let buffer = self.buffer.read(cx).snapshot(cx);
15581        let selection = self.selections.newest::<usize>(cx);
15582
15583        let mut active_group_id = None;
15584        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15585            && active_group.active_range.start.to_offset(&buffer) == selection.start
15586        {
15587            active_group_id = Some(active_group.group_id);
15588        }
15589
15590        fn filtered(
15591            snapshot: EditorSnapshot,
15592            severity: GoToDiagnosticSeverityFilter,
15593            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15594        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15595            diagnostics
15596                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15597                .filter(|entry| entry.range.start != entry.range.end)
15598                .filter(|entry| !entry.diagnostic.is_unnecessary)
15599                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15600        }
15601
15602        let snapshot = self.snapshot(window, cx);
15603        let before = filtered(
15604            snapshot.clone(),
15605            severity,
15606            buffer
15607                .diagnostics_in_range(0..selection.start)
15608                .filter(|entry| entry.range.start <= selection.start),
15609        );
15610        let after = filtered(
15611            snapshot,
15612            severity,
15613            buffer
15614                .diagnostics_in_range(selection.start..buffer.len())
15615                .filter(|entry| entry.range.start >= selection.start),
15616        );
15617
15618        let mut found: Option<DiagnosticEntry<usize>> = None;
15619        if direction == Direction::Prev {
15620            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15621            {
15622                for diagnostic in prev_diagnostics.into_iter().rev() {
15623                    if diagnostic.range.start != selection.start
15624                        || active_group_id
15625                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15626                    {
15627                        found = Some(diagnostic);
15628                        break 'outer;
15629                    }
15630                }
15631            }
15632        } else {
15633            for diagnostic in after.chain(before) {
15634                if diagnostic.range.start != selection.start
15635                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15636                {
15637                    found = Some(diagnostic);
15638                    break;
15639                }
15640            }
15641        }
15642        let Some(next_diagnostic) = found else {
15643            return;
15644        };
15645
15646        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15647        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15648            return;
15649        };
15650        self.change_selections(Default::default(), window, cx, |s| {
15651            s.select_ranges(vec![
15652                next_diagnostic.range.start..next_diagnostic.range.start,
15653            ])
15654        });
15655        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15656        self.refresh_edit_prediction(false, true, window, cx);
15657    }
15658
15659    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15660        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15661        let snapshot = self.snapshot(window, cx);
15662        let selection = self.selections.newest::<Point>(cx);
15663        self.go_to_hunk_before_or_after_position(
15664            &snapshot,
15665            selection.head(),
15666            Direction::Next,
15667            window,
15668            cx,
15669        );
15670    }
15671
15672    pub fn go_to_hunk_before_or_after_position(
15673        &mut self,
15674        snapshot: &EditorSnapshot,
15675        position: Point,
15676        direction: Direction,
15677        window: &mut Window,
15678        cx: &mut Context<Editor>,
15679    ) {
15680        let row = if direction == Direction::Next {
15681            self.hunk_after_position(snapshot, position)
15682                .map(|hunk| hunk.row_range.start)
15683        } else {
15684            self.hunk_before_position(snapshot, position)
15685        };
15686
15687        if let Some(row) = row {
15688            let destination = Point::new(row.0, 0);
15689            let autoscroll = Autoscroll::center();
15690
15691            self.unfold_ranges(&[destination..destination], false, false, cx);
15692            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15693                s.select_ranges([destination..destination]);
15694            });
15695        }
15696    }
15697
15698    fn hunk_after_position(
15699        &mut self,
15700        snapshot: &EditorSnapshot,
15701        position: Point,
15702    ) -> Option<MultiBufferDiffHunk> {
15703        snapshot
15704            .buffer_snapshot
15705            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15706            .find(|hunk| hunk.row_range.start.0 > position.row)
15707            .or_else(|| {
15708                snapshot
15709                    .buffer_snapshot
15710                    .diff_hunks_in_range(Point::zero()..position)
15711                    .find(|hunk| hunk.row_range.end.0 < position.row)
15712            })
15713    }
15714
15715    fn go_to_prev_hunk(
15716        &mut self,
15717        _: &GoToPreviousHunk,
15718        window: &mut Window,
15719        cx: &mut Context<Self>,
15720    ) {
15721        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15722        let snapshot = self.snapshot(window, cx);
15723        let selection = self.selections.newest::<Point>(cx);
15724        self.go_to_hunk_before_or_after_position(
15725            &snapshot,
15726            selection.head(),
15727            Direction::Prev,
15728            window,
15729            cx,
15730        );
15731    }
15732
15733    fn hunk_before_position(
15734        &mut self,
15735        snapshot: &EditorSnapshot,
15736        position: Point,
15737    ) -> Option<MultiBufferRow> {
15738        snapshot
15739            .buffer_snapshot
15740            .diff_hunk_before(position)
15741            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15742    }
15743
15744    fn go_to_next_change(
15745        &mut self,
15746        _: &GoToNextChange,
15747        window: &mut Window,
15748        cx: &mut Context<Self>,
15749    ) {
15750        if let Some(selections) = self
15751            .change_list
15752            .next_change(1, Direction::Next)
15753            .map(|s| s.to_vec())
15754        {
15755            self.change_selections(Default::default(), window, cx, |s| {
15756                let map = s.display_map();
15757                s.select_display_ranges(selections.iter().map(|a| {
15758                    let point = a.to_display_point(&map);
15759                    point..point
15760                }))
15761            })
15762        }
15763    }
15764
15765    fn go_to_previous_change(
15766        &mut self,
15767        _: &GoToPreviousChange,
15768        window: &mut Window,
15769        cx: &mut Context<Self>,
15770    ) {
15771        if let Some(selections) = self
15772            .change_list
15773            .next_change(1, Direction::Prev)
15774            .map(|s| s.to_vec())
15775        {
15776            self.change_selections(Default::default(), window, cx, |s| {
15777                let map = s.display_map();
15778                s.select_display_ranges(selections.iter().map(|a| {
15779                    let point = a.to_display_point(&map);
15780                    point..point
15781                }))
15782            })
15783        }
15784    }
15785
15786    fn go_to_line<T: 'static>(
15787        &mut self,
15788        position: Anchor,
15789        highlight_color: Option<Hsla>,
15790        window: &mut Window,
15791        cx: &mut Context<Self>,
15792    ) {
15793        let snapshot = self.snapshot(window, cx).display_snapshot;
15794        let position = position.to_point(&snapshot.buffer_snapshot);
15795        let start = snapshot
15796            .buffer_snapshot
15797            .clip_point(Point::new(position.row, 0), Bias::Left);
15798        let end = start + Point::new(1, 0);
15799        let start = snapshot.buffer_snapshot.anchor_before(start);
15800        let end = snapshot.buffer_snapshot.anchor_before(end);
15801
15802        self.highlight_rows::<T>(
15803            start..end,
15804            highlight_color
15805                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15806            Default::default(),
15807            cx,
15808        );
15809
15810        if self.buffer.read(cx).is_singleton() {
15811            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15812        }
15813    }
15814
15815    pub fn go_to_definition(
15816        &mut self,
15817        _: &GoToDefinition,
15818        window: &mut Window,
15819        cx: &mut Context<Self>,
15820    ) -> Task<Result<Navigated>> {
15821        let definition =
15822            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15823        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15824        cx.spawn_in(window, async move |editor, cx| {
15825            if definition.await? == Navigated::Yes {
15826                return Ok(Navigated::Yes);
15827            }
15828            match fallback_strategy {
15829                GoToDefinitionFallback::None => Ok(Navigated::No),
15830                GoToDefinitionFallback::FindAllReferences => {
15831                    match editor.update_in(cx, |editor, window, cx| {
15832                        editor.find_all_references(&FindAllReferences, window, cx)
15833                    })? {
15834                        Some(references) => references.await,
15835                        None => Ok(Navigated::No),
15836                    }
15837                }
15838            }
15839        })
15840    }
15841
15842    pub fn go_to_declaration(
15843        &mut self,
15844        _: &GoToDeclaration,
15845        window: &mut Window,
15846        cx: &mut Context<Self>,
15847    ) -> Task<Result<Navigated>> {
15848        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15849    }
15850
15851    pub fn go_to_declaration_split(
15852        &mut self,
15853        _: &GoToDeclaration,
15854        window: &mut Window,
15855        cx: &mut Context<Self>,
15856    ) -> Task<Result<Navigated>> {
15857        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15858    }
15859
15860    pub fn go_to_implementation(
15861        &mut self,
15862        _: &GoToImplementation,
15863        window: &mut Window,
15864        cx: &mut Context<Self>,
15865    ) -> Task<Result<Navigated>> {
15866        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15867    }
15868
15869    pub fn go_to_implementation_split(
15870        &mut self,
15871        _: &GoToImplementationSplit,
15872        window: &mut Window,
15873        cx: &mut Context<Self>,
15874    ) -> Task<Result<Navigated>> {
15875        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15876    }
15877
15878    pub fn go_to_type_definition(
15879        &mut self,
15880        _: &GoToTypeDefinition,
15881        window: &mut Window,
15882        cx: &mut Context<Self>,
15883    ) -> Task<Result<Navigated>> {
15884        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15885    }
15886
15887    pub fn go_to_definition_split(
15888        &mut self,
15889        _: &GoToDefinitionSplit,
15890        window: &mut Window,
15891        cx: &mut Context<Self>,
15892    ) -> Task<Result<Navigated>> {
15893        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15894    }
15895
15896    pub fn go_to_type_definition_split(
15897        &mut self,
15898        _: &GoToTypeDefinitionSplit,
15899        window: &mut Window,
15900        cx: &mut Context<Self>,
15901    ) -> Task<Result<Navigated>> {
15902        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15903    }
15904
15905    fn go_to_definition_of_kind(
15906        &mut self,
15907        kind: GotoDefinitionKind,
15908        split: bool,
15909        window: &mut Window,
15910        cx: &mut Context<Self>,
15911    ) -> Task<Result<Navigated>> {
15912        let Some(provider) = self.semantics_provider.clone() else {
15913            return Task::ready(Ok(Navigated::No));
15914        };
15915        let head = self.selections.newest::<usize>(cx).head();
15916        let buffer = self.buffer.read(cx);
15917        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15918            return Task::ready(Ok(Navigated::No));
15919        };
15920        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15921            return Task::ready(Ok(Navigated::No));
15922        };
15923
15924        cx.spawn_in(window, async move |editor, cx| {
15925            let Some(definitions) = definitions.await? else {
15926                return Ok(Navigated::No);
15927            };
15928            let navigated = editor
15929                .update_in(cx, |editor, window, cx| {
15930                    editor.navigate_to_hover_links(
15931                        Some(kind),
15932                        definitions
15933                            .into_iter()
15934                            .filter(|location| {
15935                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15936                            })
15937                            .map(HoverLink::Text)
15938                            .collect::<Vec<_>>(),
15939                        split,
15940                        window,
15941                        cx,
15942                    )
15943                })?
15944                .await?;
15945            anyhow::Ok(navigated)
15946        })
15947    }
15948
15949    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15950        let selection = self.selections.newest_anchor();
15951        let head = selection.head();
15952        let tail = selection.tail();
15953
15954        let Some((buffer, start_position)) =
15955            self.buffer.read(cx).text_anchor_for_position(head, cx)
15956        else {
15957            return;
15958        };
15959
15960        let end_position = if head != tail {
15961            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15962                return;
15963            };
15964            Some(pos)
15965        } else {
15966            None
15967        };
15968
15969        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15970            let url = if let Some(end_pos) = end_position {
15971                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15972            } else {
15973                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15974            };
15975
15976            if let Some(url) = url {
15977                editor.update(cx, |_, cx| {
15978                    cx.open_url(&url);
15979                })
15980            } else {
15981                Ok(())
15982            }
15983        });
15984
15985        url_finder.detach();
15986    }
15987
15988    pub fn open_selected_filename(
15989        &mut self,
15990        _: &OpenSelectedFilename,
15991        window: &mut Window,
15992        cx: &mut Context<Self>,
15993    ) {
15994        let Some(workspace) = self.workspace() else {
15995            return;
15996        };
15997
15998        let position = self.selections.newest_anchor().head();
15999
16000        let Some((buffer, buffer_position)) =
16001            self.buffer.read(cx).text_anchor_for_position(position, cx)
16002        else {
16003            return;
16004        };
16005
16006        let project = self.project.clone();
16007
16008        cx.spawn_in(window, async move |_, cx| {
16009            let result = find_file(&buffer, project, buffer_position, cx).await;
16010
16011            if let Some((_, path)) = result {
16012                workspace
16013                    .update_in(cx, |workspace, window, cx| {
16014                        workspace.open_resolved_path(path, window, cx)
16015                    })?
16016                    .await?;
16017            }
16018            anyhow::Ok(())
16019        })
16020        .detach();
16021    }
16022
16023    pub(crate) fn navigate_to_hover_links(
16024        &mut self,
16025        kind: Option<GotoDefinitionKind>,
16026        definitions: Vec<HoverLink>,
16027        split: bool,
16028        window: &mut Window,
16029        cx: &mut Context<Editor>,
16030    ) -> Task<Result<Navigated>> {
16031        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16032        let mut first_url_or_file = None;
16033        let definitions: Vec<_> = definitions
16034            .into_iter()
16035            .filter_map(|def| match def {
16036                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16037                HoverLink::InlayHint(lsp_location, server_id) => {
16038                    let computation =
16039                        self.compute_target_location(lsp_location, server_id, window, cx);
16040                    Some(cx.background_spawn(computation))
16041                }
16042                HoverLink::Url(url) => {
16043                    first_url_or_file = Some(Either::Left(url));
16044                    None
16045                }
16046                HoverLink::File(path) => {
16047                    first_url_or_file = Some(Either::Right(path));
16048                    None
16049                }
16050            })
16051            .collect();
16052
16053        let workspace = self.workspace();
16054
16055        cx.spawn_in(window, async move |editor, acx| {
16056            let mut locations: Vec<Location> = future::join_all(definitions)
16057                .await
16058                .into_iter()
16059                .filter_map(|location| location.transpose())
16060                .collect::<Result<_>>()
16061                .context("location tasks")?;
16062
16063            if locations.len() > 1 {
16064                let Some(workspace) = workspace else {
16065                    return Ok(Navigated::No);
16066                };
16067
16068                let tab_kind = match kind {
16069                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16070                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16071                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16072                    Some(GotoDefinitionKind::Type) => "Types",
16073                };
16074                let title = editor
16075                    .update_in(acx, |_, _, cx| {
16076                        let target = locations
16077                            .iter()
16078                            .map(|location| {
16079                                location
16080                                    .buffer
16081                                    .read(cx)
16082                                    .text_for_range(location.range.clone())
16083                                    .collect::<String>()
16084                            })
16085                            .filter(|text| !text.contains('\n'))
16086                            .unique()
16087                            .take(3)
16088                            .join(", ");
16089                        if target.is_empty() {
16090                            tab_kind.to_owned()
16091                        } else {
16092                            format!("{tab_kind} for {target}")
16093                        }
16094                    })
16095                    .context("buffer title")?;
16096
16097                let opened = workspace
16098                    .update_in(acx, |workspace, window, cx| {
16099                        Self::open_locations_in_multibuffer(
16100                            workspace,
16101                            locations,
16102                            title,
16103                            split,
16104                            MultibufferSelectionMode::First,
16105                            window,
16106                            cx,
16107                        )
16108                    })
16109                    .is_ok();
16110
16111                anyhow::Ok(Navigated::from_bool(opened))
16112            } else if locations.is_empty() {
16113                // If there is one definition, just open it directly
16114                match first_url_or_file {
16115                    Some(Either::Left(url)) => {
16116                        acx.update(|_, cx| cx.open_url(&url))?;
16117                        Ok(Navigated::Yes)
16118                    }
16119                    Some(Either::Right(path)) => {
16120                        let Some(workspace) = workspace else {
16121                            return Ok(Navigated::No);
16122                        };
16123
16124                        workspace
16125                            .update_in(acx, |workspace, window, cx| {
16126                                workspace.open_resolved_path(path, window, cx)
16127                            })?
16128                            .await?;
16129                        Ok(Navigated::Yes)
16130                    }
16131                    None => Ok(Navigated::No),
16132                }
16133            } else {
16134                let Some(workspace) = workspace else {
16135                    return Ok(Navigated::No);
16136                };
16137
16138                let target = locations.pop().unwrap();
16139                editor.update_in(acx, |editor, window, cx| {
16140                    let pane = workspace.read(cx).active_pane().clone();
16141
16142                    let range = target.range.to_point(target.buffer.read(cx));
16143                    let range = editor.range_for_match(&range);
16144                    let range = collapse_multiline_range(range);
16145
16146                    if !split
16147                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16148                    {
16149                        editor.go_to_singleton_buffer_range(range, window, cx);
16150                    } else {
16151                        window.defer(cx, move |window, cx| {
16152                            let target_editor: Entity<Self> =
16153                                workspace.update(cx, |workspace, cx| {
16154                                    let pane = if split {
16155                                        workspace.adjacent_pane(window, cx)
16156                                    } else {
16157                                        workspace.active_pane().clone()
16158                                    };
16159
16160                                    workspace.open_project_item(
16161                                        pane,
16162                                        target.buffer.clone(),
16163                                        true,
16164                                        true,
16165                                        window,
16166                                        cx,
16167                                    )
16168                                });
16169                            target_editor.update(cx, |target_editor, cx| {
16170                                // When selecting a definition in a different buffer, disable the nav history
16171                                // to avoid creating a history entry at the previous cursor location.
16172                                pane.update(cx, |pane, _| pane.disable_history());
16173                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16174                                pane.update(cx, |pane, _| pane.enable_history());
16175                            });
16176                        });
16177                    }
16178                    Navigated::Yes
16179                })
16180            }
16181        })
16182    }
16183
16184    fn compute_target_location(
16185        &self,
16186        lsp_location: lsp::Location,
16187        server_id: LanguageServerId,
16188        window: &mut Window,
16189        cx: &mut Context<Self>,
16190    ) -> Task<anyhow::Result<Option<Location>>> {
16191        let Some(project) = self.project.clone() else {
16192            return Task::ready(Ok(None));
16193        };
16194
16195        cx.spawn_in(window, async move |editor, cx| {
16196            let location_task = editor.update(cx, |_, cx| {
16197                project.update(cx, |project, cx| {
16198                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16199                })
16200            })?;
16201            let location = Some({
16202                let target_buffer_handle = location_task.await.context("open local buffer")?;
16203                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16204                    let target_start = target_buffer
16205                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16206                    let target_end = target_buffer
16207                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16208                    target_buffer.anchor_after(target_start)
16209                        ..target_buffer.anchor_before(target_end)
16210                })?;
16211                Location {
16212                    buffer: target_buffer_handle,
16213                    range,
16214                }
16215            });
16216            Ok(location)
16217        })
16218    }
16219
16220    pub fn find_all_references(
16221        &mut self,
16222        _: &FindAllReferences,
16223        window: &mut Window,
16224        cx: &mut Context<Self>,
16225    ) -> Option<Task<Result<Navigated>>> {
16226        let selection = self.selections.newest::<usize>(cx);
16227        let multi_buffer = self.buffer.read(cx);
16228        let head = selection.head();
16229
16230        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16231        let head_anchor = multi_buffer_snapshot.anchor_at(
16232            head,
16233            if head < selection.tail() {
16234                Bias::Right
16235            } else {
16236                Bias::Left
16237            },
16238        );
16239
16240        match self
16241            .find_all_references_task_sources
16242            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16243        {
16244            Ok(_) => {
16245                log::info!(
16246                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16247                );
16248                return None;
16249            }
16250            Err(i) => {
16251                self.find_all_references_task_sources.insert(i, head_anchor);
16252            }
16253        }
16254
16255        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16256        let workspace = self.workspace()?;
16257        let project = workspace.read(cx).project().clone();
16258        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16259        Some(cx.spawn_in(window, async move |editor, cx| {
16260            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16261                if let Ok(i) = editor
16262                    .find_all_references_task_sources
16263                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16264                {
16265                    editor.find_all_references_task_sources.remove(i);
16266                }
16267            });
16268
16269            let Some(locations) = references.await? else {
16270                return anyhow::Ok(Navigated::No);
16271            };
16272            if locations.is_empty() {
16273                return anyhow::Ok(Navigated::No);
16274            }
16275
16276            workspace.update_in(cx, |workspace, window, cx| {
16277                let target = locations
16278                    .iter()
16279                    .map(|location| {
16280                        location
16281                            .buffer
16282                            .read(cx)
16283                            .text_for_range(location.range.clone())
16284                            .collect::<String>()
16285                    })
16286                    .filter(|text| !text.contains('\n'))
16287                    .unique()
16288                    .take(3)
16289                    .join(", ");
16290                let title = if target.is_empty() {
16291                    "References".to_owned()
16292                } else {
16293                    format!("References to {target}")
16294                };
16295                Self::open_locations_in_multibuffer(
16296                    workspace,
16297                    locations,
16298                    title,
16299                    false,
16300                    MultibufferSelectionMode::First,
16301                    window,
16302                    cx,
16303                );
16304                Navigated::Yes
16305            })
16306        }))
16307    }
16308
16309    /// Opens a multibuffer with the given project locations in it
16310    pub fn open_locations_in_multibuffer(
16311        workspace: &mut Workspace,
16312        mut locations: Vec<Location>,
16313        title: String,
16314        split: bool,
16315        multibuffer_selection_mode: MultibufferSelectionMode,
16316        window: &mut Window,
16317        cx: &mut Context<Workspace>,
16318    ) {
16319        if locations.is_empty() {
16320            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16321            return;
16322        }
16323
16324        // If there are multiple definitions, open them in a multibuffer
16325        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16326        let mut locations = locations.into_iter().peekable();
16327        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16328        let capability = workspace.project().read(cx).capability();
16329
16330        let excerpt_buffer = cx.new(|cx| {
16331            let mut multibuffer = MultiBuffer::new(capability);
16332            while let Some(location) = locations.next() {
16333                let buffer = location.buffer.read(cx);
16334                let mut ranges_for_buffer = Vec::new();
16335                let range = location.range.to_point(buffer);
16336                ranges_for_buffer.push(range.clone());
16337
16338                while let Some(next_location) = locations.peek() {
16339                    if next_location.buffer == location.buffer {
16340                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16341                        locations.next();
16342                    } else {
16343                        break;
16344                    }
16345                }
16346
16347                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16348                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16349                    PathKey::for_buffer(&location.buffer, cx),
16350                    location.buffer.clone(),
16351                    ranges_for_buffer,
16352                    multibuffer_context_lines(cx),
16353                    cx,
16354                );
16355                ranges.extend(new_ranges)
16356            }
16357
16358            multibuffer.with_title(title)
16359        });
16360
16361        let editor = cx.new(|cx| {
16362            Editor::for_multibuffer(
16363                excerpt_buffer,
16364                Some(workspace.project().clone()),
16365                window,
16366                cx,
16367            )
16368        });
16369        editor.update(cx, |editor, cx| {
16370            match multibuffer_selection_mode {
16371                MultibufferSelectionMode::First => {
16372                    if let Some(first_range) = ranges.first() {
16373                        editor.change_selections(
16374                            SelectionEffects::no_scroll(),
16375                            window,
16376                            cx,
16377                            |selections| {
16378                                selections.clear_disjoint();
16379                                selections
16380                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16381                            },
16382                        );
16383                    }
16384                    editor.highlight_background::<Self>(
16385                        &ranges,
16386                        |theme| theme.colors().editor_highlighted_line_background,
16387                        cx,
16388                    );
16389                }
16390                MultibufferSelectionMode::All => {
16391                    editor.change_selections(
16392                        SelectionEffects::no_scroll(),
16393                        window,
16394                        cx,
16395                        |selections| {
16396                            selections.clear_disjoint();
16397                            selections.select_anchor_ranges(ranges);
16398                        },
16399                    );
16400                }
16401            }
16402            editor.register_buffers_with_language_servers(cx);
16403        });
16404
16405        let item = Box::new(editor);
16406        let item_id = item.item_id();
16407
16408        if split {
16409            workspace.split_item(SplitDirection::Right, item, window, cx);
16410        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16411            let (preview_item_id, preview_item_idx) =
16412                workspace.active_pane().read_with(cx, |pane, _| {
16413                    (pane.preview_item_id(), pane.preview_item_idx())
16414                });
16415
16416            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16417
16418            if let Some(preview_item_id) = preview_item_id {
16419                workspace.active_pane().update(cx, |pane, cx| {
16420                    pane.remove_item(preview_item_id, false, false, window, cx);
16421                });
16422            }
16423        } else {
16424            workspace.add_item_to_active_pane(item, None, true, window, cx);
16425        }
16426        workspace.active_pane().update(cx, |pane, cx| {
16427            pane.set_preview_item_id(Some(item_id), cx);
16428        });
16429    }
16430
16431    pub fn rename(
16432        &mut self,
16433        _: &Rename,
16434        window: &mut Window,
16435        cx: &mut Context<Self>,
16436    ) -> Option<Task<Result<()>>> {
16437        use language::ToOffset as _;
16438
16439        let provider = self.semantics_provider.clone()?;
16440        let selection = self.selections.newest_anchor().clone();
16441        let (cursor_buffer, cursor_buffer_position) = self
16442            .buffer
16443            .read(cx)
16444            .text_anchor_for_position(selection.head(), cx)?;
16445        let (tail_buffer, cursor_buffer_position_end) = self
16446            .buffer
16447            .read(cx)
16448            .text_anchor_for_position(selection.tail(), cx)?;
16449        if tail_buffer != cursor_buffer {
16450            return None;
16451        }
16452
16453        let snapshot = cursor_buffer.read(cx).snapshot();
16454        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16455        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16456        let prepare_rename = provider
16457            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16458            .unwrap_or_else(|| Task::ready(Ok(None)));
16459        drop(snapshot);
16460
16461        Some(cx.spawn_in(window, async move |this, cx| {
16462            let rename_range = if let Some(range) = prepare_rename.await? {
16463                Some(range)
16464            } else {
16465                this.update(cx, |this, cx| {
16466                    let buffer = this.buffer.read(cx).snapshot(cx);
16467                    let mut buffer_highlights = this
16468                        .document_highlights_for_position(selection.head(), &buffer)
16469                        .filter(|highlight| {
16470                            highlight.start.excerpt_id == selection.head().excerpt_id
16471                                && highlight.end.excerpt_id == selection.head().excerpt_id
16472                        });
16473                    buffer_highlights
16474                        .next()
16475                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16476                })?
16477            };
16478            if let Some(rename_range) = rename_range {
16479                this.update_in(cx, |this, window, cx| {
16480                    let snapshot = cursor_buffer.read(cx).snapshot();
16481                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16482                    let cursor_offset_in_rename_range =
16483                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16484                    let cursor_offset_in_rename_range_end =
16485                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16486
16487                    this.take_rename(false, window, cx);
16488                    let buffer = this.buffer.read(cx).read(cx);
16489                    let cursor_offset = selection.head().to_offset(&buffer);
16490                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16491                    let rename_end = rename_start + rename_buffer_range.len();
16492                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16493                    let mut old_highlight_id = None;
16494                    let old_name: Arc<str> = buffer
16495                        .chunks(rename_start..rename_end, true)
16496                        .map(|chunk| {
16497                            if old_highlight_id.is_none() {
16498                                old_highlight_id = chunk.syntax_highlight_id;
16499                            }
16500                            chunk.text
16501                        })
16502                        .collect::<String>()
16503                        .into();
16504
16505                    drop(buffer);
16506
16507                    // Position the selection in the rename editor so that it matches the current selection.
16508                    this.show_local_selections = false;
16509                    let rename_editor = cx.new(|cx| {
16510                        let mut editor = Editor::single_line(window, cx);
16511                        editor.buffer.update(cx, |buffer, cx| {
16512                            buffer.edit([(0..0, old_name.clone())], None, cx)
16513                        });
16514                        let rename_selection_range = match cursor_offset_in_rename_range
16515                            .cmp(&cursor_offset_in_rename_range_end)
16516                        {
16517                            Ordering::Equal => {
16518                                editor.select_all(&SelectAll, window, cx);
16519                                return editor;
16520                            }
16521                            Ordering::Less => {
16522                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16523                            }
16524                            Ordering::Greater => {
16525                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16526                            }
16527                        };
16528                        if rename_selection_range.end > old_name.len() {
16529                            editor.select_all(&SelectAll, window, cx);
16530                        } else {
16531                            editor.change_selections(Default::default(), window, cx, |s| {
16532                                s.select_ranges([rename_selection_range]);
16533                            });
16534                        }
16535                        editor
16536                    });
16537                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16538                        if e == &EditorEvent::Focused {
16539                            cx.emit(EditorEvent::FocusedIn)
16540                        }
16541                    })
16542                    .detach();
16543
16544                    let write_highlights =
16545                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16546                    let read_highlights =
16547                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16548                    let ranges = write_highlights
16549                        .iter()
16550                        .flat_map(|(_, ranges)| ranges.iter())
16551                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16552                        .cloned()
16553                        .collect();
16554
16555                    this.highlight_text::<Rename>(
16556                        ranges,
16557                        HighlightStyle {
16558                            fade_out: Some(0.6),
16559                            ..Default::default()
16560                        },
16561                        cx,
16562                    );
16563                    let rename_focus_handle = rename_editor.focus_handle(cx);
16564                    window.focus(&rename_focus_handle);
16565                    let block_id = this.insert_blocks(
16566                        [BlockProperties {
16567                            style: BlockStyle::Flex,
16568                            placement: BlockPlacement::Below(range.start),
16569                            height: Some(1),
16570                            render: Arc::new({
16571                                let rename_editor = rename_editor.clone();
16572                                move |cx: &mut BlockContext| {
16573                                    let mut text_style = cx.editor_style.text.clone();
16574                                    if let Some(highlight_style) = old_highlight_id
16575                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16576                                    {
16577                                        text_style = text_style.highlight(highlight_style);
16578                                    }
16579                                    div()
16580                                        .block_mouse_except_scroll()
16581                                        .pl(cx.anchor_x)
16582                                        .child(EditorElement::new(
16583                                            &rename_editor,
16584                                            EditorStyle {
16585                                                background: cx.theme().system().transparent,
16586                                                local_player: cx.editor_style.local_player,
16587                                                text: text_style,
16588                                                scrollbar_width: cx.editor_style.scrollbar_width,
16589                                                syntax: cx.editor_style.syntax.clone(),
16590                                                status: cx.editor_style.status.clone(),
16591                                                inlay_hints_style: HighlightStyle {
16592                                                    font_weight: Some(FontWeight::BOLD),
16593                                                    ..make_inlay_hints_style(cx.app)
16594                                                },
16595                                                edit_prediction_styles: make_suggestion_styles(
16596                                                    cx.app,
16597                                                ),
16598                                                ..EditorStyle::default()
16599                                            },
16600                                        ))
16601                                        .into_any_element()
16602                                }
16603                            }),
16604                            priority: 0,
16605                        }],
16606                        Some(Autoscroll::fit()),
16607                        cx,
16608                    )[0];
16609                    this.pending_rename = Some(RenameState {
16610                        range,
16611                        old_name,
16612                        editor: rename_editor,
16613                        block_id,
16614                    });
16615                })?;
16616            }
16617
16618            Ok(())
16619        }))
16620    }
16621
16622    pub fn confirm_rename(
16623        &mut self,
16624        _: &ConfirmRename,
16625        window: &mut Window,
16626        cx: &mut Context<Self>,
16627    ) -> Option<Task<Result<()>>> {
16628        let rename = self.take_rename(false, window, cx)?;
16629        let workspace = self.workspace()?.downgrade();
16630        let (buffer, start) = self
16631            .buffer
16632            .read(cx)
16633            .text_anchor_for_position(rename.range.start, cx)?;
16634        let (end_buffer, _) = self
16635            .buffer
16636            .read(cx)
16637            .text_anchor_for_position(rename.range.end, cx)?;
16638        if buffer != end_buffer {
16639            return None;
16640        }
16641
16642        let old_name = rename.old_name;
16643        let new_name = rename.editor.read(cx).text(cx);
16644
16645        let rename = self.semantics_provider.as_ref()?.perform_rename(
16646            &buffer,
16647            start,
16648            new_name.clone(),
16649            cx,
16650        )?;
16651
16652        Some(cx.spawn_in(window, async move |editor, cx| {
16653            let project_transaction = rename.await?;
16654            Self::open_project_transaction(
16655                &editor,
16656                workspace,
16657                project_transaction,
16658                format!("Rename: {}{}", old_name, new_name),
16659                cx,
16660            )
16661            .await?;
16662
16663            editor.update(cx, |editor, cx| {
16664                editor.refresh_document_highlights(cx);
16665            })?;
16666            Ok(())
16667        }))
16668    }
16669
16670    fn take_rename(
16671        &mut self,
16672        moving_cursor: bool,
16673        window: &mut Window,
16674        cx: &mut Context<Self>,
16675    ) -> Option<RenameState> {
16676        let rename = self.pending_rename.take()?;
16677        if rename.editor.focus_handle(cx).is_focused(window) {
16678            window.focus(&self.focus_handle);
16679        }
16680
16681        self.remove_blocks(
16682            [rename.block_id].into_iter().collect(),
16683            Some(Autoscroll::fit()),
16684            cx,
16685        );
16686        self.clear_highlights::<Rename>(cx);
16687        self.show_local_selections = true;
16688
16689        if moving_cursor {
16690            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16691                editor.selections.newest::<usize>(cx).head()
16692            });
16693
16694            // Update the selection to match the position of the selection inside
16695            // the rename editor.
16696            let snapshot = self.buffer.read(cx).read(cx);
16697            let rename_range = rename.range.to_offset(&snapshot);
16698            let cursor_in_editor = snapshot
16699                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16700                .min(rename_range.end);
16701            drop(snapshot);
16702
16703            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16704                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16705            });
16706        } else {
16707            self.refresh_document_highlights(cx);
16708        }
16709
16710        Some(rename)
16711    }
16712
16713    pub fn pending_rename(&self) -> Option<&RenameState> {
16714        self.pending_rename.as_ref()
16715    }
16716
16717    fn format(
16718        &mut self,
16719        _: &Format,
16720        window: &mut Window,
16721        cx: &mut Context<Self>,
16722    ) -> Option<Task<Result<()>>> {
16723        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16724
16725        let project = match &self.project {
16726            Some(project) => project.clone(),
16727            None => return None,
16728        };
16729
16730        Some(self.perform_format(
16731            project,
16732            FormatTrigger::Manual,
16733            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16734            window,
16735            cx,
16736        ))
16737    }
16738
16739    fn format_selections(
16740        &mut self,
16741        _: &FormatSelections,
16742        window: &mut Window,
16743        cx: &mut Context<Self>,
16744    ) -> Option<Task<Result<()>>> {
16745        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16746
16747        let project = match &self.project {
16748            Some(project) => project.clone(),
16749            None => return None,
16750        };
16751
16752        let ranges = self
16753            .selections
16754            .all_adjusted(cx)
16755            .into_iter()
16756            .map(|selection| selection.range())
16757            .collect_vec();
16758
16759        Some(self.perform_format(
16760            project,
16761            FormatTrigger::Manual,
16762            FormatTarget::Ranges(ranges),
16763            window,
16764            cx,
16765        ))
16766    }
16767
16768    fn perform_format(
16769        &mut self,
16770        project: Entity<Project>,
16771        trigger: FormatTrigger,
16772        target: FormatTarget,
16773        window: &mut Window,
16774        cx: &mut Context<Self>,
16775    ) -> Task<Result<()>> {
16776        let buffer = self.buffer.clone();
16777        let (buffers, target) = match target {
16778            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16779            FormatTarget::Ranges(selection_ranges) => {
16780                let multi_buffer = buffer.read(cx);
16781                let snapshot = multi_buffer.read(cx);
16782                let mut buffers = HashSet::default();
16783                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16784                    BTreeMap::new();
16785                for selection_range in selection_ranges {
16786                    for (buffer, buffer_range, _) in
16787                        snapshot.range_to_buffer_ranges(selection_range)
16788                    {
16789                        let buffer_id = buffer.remote_id();
16790                        let start = buffer.anchor_before(buffer_range.start);
16791                        let end = buffer.anchor_after(buffer_range.end);
16792                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16793                        buffer_id_to_ranges
16794                            .entry(buffer_id)
16795                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16796                            .or_insert_with(|| vec![start..end]);
16797                    }
16798                }
16799                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16800            }
16801        };
16802
16803        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16804        let selections_prev = transaction_id_prev
16805            .and_then(|transaction_id_prev| {
16806                // default to selections as they were after the last edit, if we have them,
16807                // instead of how they are now.
16808                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16809                // will take you back to where you made the last edit, instead of staying where you scrolled
16810                self.selection_history
16811                    .transaction(transaction_id_prev)
16812                    .map(|t| t.0.clone())
16813            })
16814            .unwrap_or_else(|| self.selections.disjoint_anchors());
16815
16816        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16817        let format = project.update(cx, |project, cx| {
16818            project.format(buffers, target, true, trigger, cx)
16819        });
16820
16821        cx.spawn_in(window, async move |editor, cx| {
16822            let transaction = futures::select_biased! {
16823                transaction = format.log_err().fuse() => transaction,
16824                () = timeout => {
16825                    log::warn!("timed out waiting for formatting");
16826                    None
16827                }
16828            };
16829
16830            buffer
16831                .update(cx, |buffer, cx| {
16832                    if let Some(transaction) = transaction
16833                        && !buffer.is_singleton()
16834                    {
16835                        buffer.push_transaction(&transaction.0, cx);
16836                    }
16837                    cx.notify();
16838                })
16839                .ok();
16840
16841            if let Some(transaction_id_now) =
16842                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16843            {
16844                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16845                if has_new_transaction {
16846                    _ = editor.update(cx, |editor, _| {
16847                        editor
16848                            .selection_history
16849                            .insert_transaction(transaction_id_now, selections_prev);
16850                    });
16851                }
16852            }
16853
16854            Ok(())
16855        })
16856    }
16857
16858    fn organize_imports(
16859        &mut self,
16860        _: &OrganizeImports,
16861        window: &mut Window,
16862        cx: &mut Context<Self>,
16863    ) -> Option<Task<Result<()>>> {
16864        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16865        let project = match &self.project {
16866            Some(project) => project.clone(),
16867            None => return None,
16868        };
16869        Some(self.perform_code_action_kind(
16870            project,
16871            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16872            window,
16873            cx,
16874        ))
16875    }
16876
16877    fn perform_code_action_kind(
16878        &mut self,
16879        project: Entity<Project>,
16880        kind: CodeActionKind,
16881        window: &mut Window,
16882        cx: &mut Context<Self>,
16883    ) -> Task<Result<()>> {
16884        let buffer = self.buffer.clone();
16885        let buffers = buffer.read(cx).all_buffers();
16886        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16887        let apply_action = project.update(cx, |project, cx| {
16888            project.apply_code_action_kind(buffers, kind, true, cx)
16889        });
16890        cx.spawn_in(window, async move |_, cx| {
16891            let transaction = futures::select_biased! {
16892                () = timeout => {
16893                    log::warn!("timed out waiting for executing code action");
16894                    None
16895                }
16896                transaction = apply_action.log_err().fuse() => transaction,
16897            };
16898            buffer
16899                .update(cx, |buffer, cx| {
16900                    // check if we need this
16901                    if let Some(transaction) = transaction
16902                        && !buffer.is_singleton()
16903                    {
16904                        buffer.push_transaction(&transaction.0, cx);
16905                    }
16906                    cx.notify();
16907                })
16908                .ok();
16909            Ok(())
16910        })
16911    }
16912
16913    pub fn restart_language_server(
16914        &mut self,
16915        _: &RestartLanguageServer,
16916        _: &mut Window,
16917        cx: &mut Context<Self>,
16918    ) {
16919        if let Some(project) = self.project.clone() {
16920            self.buffer.update(cx, |multi_buffer, cx| {
16921                project.update(cx, |project, cx| {
16922                    project.restart_language_servers_for_buffers(
16923                        multi_buffer.all_buffers().into_iter().collect(),
16924                        HashSet::default(),
16925                        cx,
16926                    );
16927                });
16928            })
16929        }
16930    }
16931
16932    pub fn stop_language_server(
16933        &mut self,
16934        _: &StopLanguageServer,
16935        _: &mut Window,
16936        cx: &mut Context<Self>,
16937    ) {
16938        if let Some(project) = self.project.clone() {
16939            self.buffer.update(cx, |multi_buffer, cx| {
16940                project.update(cx, |project, cx| {
16941                    project.stop_language_servers_for_buffers(
16942                        multi_buffer.all_buffers().into_iter().collect(),
16943                        HashSet::default(),
16944                        cx,
16945                    );
16946                    cx.emit(project::Event::RefreshInlayHints);
16947                });
16948            });
16949        }
16950    }
16951
16952    fn cancel_language_server_work(
16953        workspace: &mut Workspace,
16954        _: &actions::CancelLanguageServerWork,
16955        _: &mut Window,
16956        cx: &mut Context<Workspace>,
16957    ) {
16958        let project = workspace.project();
16959        let buffers = workspace
16960            .active_item(cx)
16961            .and_then(|item| item.act_as::<Editor>(cx))
16962            .map_or(HashSet::default(), |editor| {
16963                editor.read(cx).buffer.read(cx).all_buffers()
16964            });
16965        project.update(cx, |project, cx| {
16966            project.cancel_language_server_work_for_buffers(buffers, cx);
16967        });
16968    }
16969
16970    fn show_character_palette(
16971        &mut self,
16972        _: &ShowCharacterPalette,
16973        window: &mut Window,
16974        _: &mut Context<Self>,
16975    ) {
16976        window.show_character_palette();
16977    }
16978
16979    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16980        if !self.diagnostics_enabled() {
16981            return;
16982        }
16983
16984        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16985            let buffer = self.buffer.read(cx).snapshot(cx);
16986            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16987            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16988            let is_valid = buffer
16989                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16990                .any(|entry| {
16991                    entry.diagnostic.is_primary
16992                        && !entry.range.is_empty()
16993                        && entry.range.start == primary_range_start
16994                        && entry.diagnostic.message == active_diagnostics.active_message
16995                });
16996
16997            if !is_valid {
16998                self.dismiss_diagnostics(cx);
16999            }
17000        }
17001    }
17002
17003    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17004        match &self.active_diagnostics {
17005            ActiveDiagnostic::Group(group) => Some(group),
17006            _ => None,
17007        }
17008    }
17009
17010    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17011        if !self.diagnostics_enabled() {
17012            return;
17013        }
17014        self.dismiss_diagnostics(cx);
17015        self.active_diagnostics = ActiveDiagnostic::All;
17016    }
17017
17018    fn activate_diagnostics(
17019        &mut self,
17020        buffer_id: BufferId,
17021        diagnostic: DiagnosticEntry<usize>,
17022        window: &mut Window,
17023        cx: &mut Context<Self>,
17024    ) {
17025        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17026            return;
17027        }
17028        self.dismiss_diagnostics(cx);
17029        let snapshot = self.snapshot(window, cx);
17030        let buffer = self.buffer.read(cx).snapshot(cx);
17031        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17032            return;
17033        };
17034
17035        let diagnostic_group = buffer
17036            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17037            .collect::<Vec<_>>();
17038
17039        let blocks =
17040            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17041
17042        let blocks = self.display_map.update(cx, |display_map, cx| {
17043            display_map.insert_blocks(blocks, cx).into_iter().collect()
17044        });
17045        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17046            active_range: buffer.anchor_before(diagnostic.range.start)
17047                ..buffer.anchor_after(diagnostic.range.end),
17048            active_message: diagnostic.diagnostic.message.clone(),
17049            group_id: diagnostic.diagnostic.group_id,
17050            blocks,
17051        });
17052        cx.notify();
17053    }
17054
17055    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17056        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17057            return;
17058        };
17059
17060        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17061        if let ActiveDiagnostic::Group(group) = prev {
17062            self.display_map.update(cx, |display_map, cx| {
17063                display_map.remove_blocks(group.blocks, cx);
17064            });
17065            cx.notify();
17066        }
17067    }
17068
17069    /// Disable inline diagnostics rendering for this editor.
17070    pub fn disable_inline_diagnostics(&mut self) {
17071        self.inline_diagnostics_enabled = false;
17072        self.inline_diagnostics_update = Task::ready(());
17073        self.inline_diagnostics.clear();
17074    }
17075
17076    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17077        self.diagnostics_enabled = false;
17078        self.dismiss_diagnostics(cx);
17079        self.inline_diagnostics_update = Task::ready(());
17080        self.inline_diagnostics.clear();
17081    }
17082
17083    pub fn diagnostics_enabled(&self) -> bool {
17084        self.diagnostics_enabled && self.mode.is_full()
17085    }
17086
17087    pub fn inline_diagnostics_enabled(&self) -> bool {
17088        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17089    }
17090
17091    pub fn show_inline_diagnostics(&self) -> bool {
17092        self.show_inline_diagnostics
17093    }
17094
17095    pub fn toggle_inline_diagnostics(
17096        &mut self,
17097        _: &ToggleInlineDiagnostics,
17098        window: &mut Window,
17099        cx: &mut Context<Editor>,
17100    ) {
17101        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17102        self.refresh_inline_diagnostics(false, window, cx);
17103    }
17104
17105    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17106        self.diagnostics_max_severity = severity;
17107        self.display_map.update(cx, |display_map, _| {
17108            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17109        });
17110    }
17111
17112    pub fn toggle_diagnostics(
17113        &mut self,
17114        _: &ToggleDiagnostics,
17115        window: &mut Window,
17116        cx: &mut Context<Editor>,
17117    ) {
17118        if !self.diagnostics_enabled() {
17119            return;
17120        }
17121
17122        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17123            EditorSettings::get_global(cx)
17124                .diagnostics_max_severity
17125                .filter(|severity| severity != &DiagnosticSeverity::Off)
17126                .unwrap_or(DiagnosticSeverity::Hint)
17127        } else {
17128            DiagnosticSeverity::Off
17129        };
17130        self.set_max_diagnostics_severity(new_severity, cx);
17131        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17132            self.active_diagnostics = ActiveDiagnostic::None;
17133            self.inline_diagnostics_update = Task::ready(());
17134            self.inline_diagnostics.clear();
17135        } else {
17136            self.refresh_inline_diagnostics(false, window, cx);
17137        }
17138
17139        cx.notify();
17140    }
17141
17142    pub fn toggle_minimap(
17143        &mut self,
17144        _: &ToggleMinimap,
17145        window: &mut Window,
17146        cx: &mut Context<Editor>,
17147    ) {
17148        if self.supports_minimap(cx) {
17149            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17150        }
17151    }
17152
17153    fn refresh_inline_diagnostics(
17154        &mut self,
17155        debounce: bool,
17156        window: &mut Window,
17157        cx: &mut Context<Self>,
17158    ) {
17159        let max_severity = ProjectSettings::get_global(cx)
17160            .diagnostics
17161            .inline
17162            .max_severity
17163            .unwrap_or(self.diagnostics_max_severity);
17164
17165        if !self.inline_diagnostics_enabled()
17166            || !self.show_inline_diagnostics
17167            || max_severity == DiagnosticSeverity::Off
17168        {
17169            self.inline_diagnostics_update = Task::ready(());
17170            self.inline_diagnostics.clear();
17171            return;
17172        }
17173
17174        let debounce_ms = ProjectSettings::get_global(cx)
17175            .diagnostics
17176            .inline
17177            .update_debounce_ms;
17178        let debounce = if debounce && debounce_ms > 0 {
17179            Some(Duration::from_millis(debounce_ms))
17180        } else {
17181            None
17182        };
17183        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17184            if let Some(debounce) = debounce {
17185                cx.background_executor().timer(debounce).await;
17186            }
17187            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17188                editor
17189                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17190                    .ok()
17191            }) else {
17192                return;
17193            };
17194
17195            let new_inline_diagnostics = cx
17196                .background_spawn(async move {
17197                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17198                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17199                        let message = diagnostic_entry
17200                            .diagnostic
17201                            .message
17202                            .split_once('\n')
17203                            .map(|(line, _)| line)
17204                            .map(SharedString::new)
17205                            .unwrap_or_else(|| {
17206                                SharedString::from(diagnostic_entry.diagnostic.message)
17207                            });
17208                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17209                        let (Ok(i) | Err(i)) = inline_diagnostics
17210                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17211                        inline_diagnostics.insert(
17212                            i,
17213                            (
17214                                start_anchor,
17215                                InlineDiagnostic {
17216                                    message,
17217                                    group_id: diagnostic_entry.diagnostic.group_id,
17218                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17219                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17220                                    severity: diagnostic_entry.diagnostic.severity,
17221                                },
17222                            ),
17223                        );
17224                    }
17225                    inline_diagnostics
17226                })
17227                .await;
17228
17229            editor
17230                .update(cx, |editor, cx| {
17231                    editor.inline_diagnostics = new_inline_diagnostics;
17232                    cx.notify();
17233                })
17234                .ok();
17235        });
17236    }
17237
17238    fn pull_diagnostics(
17239        &mut self,
17240        buffer_id: Option<BufferId>,
17241        window: &Window,
17242        cx: &mut Context<Self>,
17243    ) -> Option<()> {
17244        if !self.mode().is_full() {
17245            return None;
17246        }
17247        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17248            .diagnostics
17249            .lsp_pull_diagnostics;
17250        if !pull_diagnostics_settings.enabled {
17251            return None;
17252        }
17253        let project = self.project()?.downgrade();
17254        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17255        let mut buffers = self.buffer.read(cx).all_buffers();
17256        if let Some(buffer_id) = buffer_id {
17257            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17258        }
17259
17260        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17261            cx.background_executor().timer(debounce).await;
17262
17263            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17264                buffers
17265                    .into_iter()
17266                    .filter_map(|buffer| {
17267                        project
17268                            .update(cx, |project, cx| {
17269                                project.lsp_store().update(cx, |lsp_store, cx| {
17270                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17271                                })
17272                            })
17273                            .ok()
17274                    })
17275                    .collect::<FuturesUnordered<_>>()
17276            }) else {
17277                return;
17278            };
17279
17280            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17281                match pull_task {
17282                    Ok(()) => {
17283                        if editor
17284                            .update_in(cx, |editor, window, cx| {
17285                                editor.update_diagnostics_state(window, cx);
17286                            })
17287                            .is_err()
17288                        {
17289                            return;
17290                        }
17291                    }
17292                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17293                }
17294            }
17295        });
17296
17297        Some(())
17298    }
17299
17300    pub fn set_selections_from_remote(
17301        &mut self,
17302        selections: Vec<Selection<Anchor>>,
17303        pending_selection: Option<Selection<Anchor>>,
17304        window: &mut Window,
17305        cx: &mut Context<Self>,
17306    ) {
17307        let old_cursor_position = self.selections.newest_anchor().head();
17308        self.selections.change_with(cx, |s| {
17309            s.select_anchors(selections);
17310            if let Some(pending_selection) = pending_selection {
17311                s.set_pending(pending_selection, SelectMode::Character);
17312            } else {
17313                s.clear_pending();
17314            }
17315        });
17316        self.selections_did_change(
17317            false,
17318            &old_cursor_position,
17319            SelectionEffects::default(),
17320            window,
17321            cx,
17322        );
17323    }
17324
17325    pub fn transact(
17326        &mut self,
17327        window: &mut Window,
17328        cx: &mut Context<Self>,
17329        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17330    ) -> Option<TransactionId> {
17331        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17332            this.start_transaction_at(Instant::now(), window, cx);
17333            update(this, window, cx);
17334            this.end_transaction_at(Instant::now(), cx)
17335        })
17336    }
17337
17338    pub fn start_transaction_at(
17339        &mut self,
17340        now: Instant,
17341        window: &mut Window,
17342        cx: &mut Context<Self>,
17343    ) -> Option<TransactionId> {
17344        self.end_selection(window, cx);
17345        if let Some(tx_id) = self
17346            .buffer
17347            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17348        {
17349            self.selection_history
17350                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17351            cx.emit(EditorEvent::TransactionBegun {
17352                transaction_id: tx_id,
17353            });
17354            Some(tx_id)
17355        } else {
17356            None
17357        }
17358    }
17359
17360    pub fn end_transaction_at(
17361        &mut self,
17362        now: Instant,
17363        cx: &mut Context<Self>,
17364    ) -> Option<TransactionId> {
17365        if let Some(transaction_id) = self
17366            .buffer
17367            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17368        {
17369            if let Some((_, end_selections)) =
17370                self.selection_history.transaction_mut(transaction_id)
17371            {
17372                *end_selections = Some(self.selections.disjoint_anchors());
17373            } else {
17374                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17375            }
17376
17377            cx.emit(EditorEvent::Edited { transaction_id });
17378            Some(transaction_id)
17379        } else {
17380            None
17381        }
17382    }
17383
17384    pub fn modify_transaction_selection_history(
17385        &mut self,
17386        transaction_id: TransactionId,
17387        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17388    ) -> bool {
17389        self.selection_history
17390            .transaction_mut(transaction_id)
17391            .map(modify)
17392            .is_some()
17393    }
17394
17395    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17396        if self.selection_mark_mode {
17397            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17398                s.move_with(|_, sel| {
17399                    sel.collapse_to(sel.head(), SelectionGoal::None);
17400                });
17401            })
17402        }
17403        self.selection_mark_mode = true;
17404        cx.notify();
17405    }
17406
17407    pub fn swap_selection_ends(
17408        &mut self,
17409        _: &actions::SwapSelectionEnds,
17410        window: &mut Window,
17411        cx: &mut Context<Self>,
17412    ) {
17413        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17414            s.move_with(|_, sel| {
17415                if sel.start != sel.end {
17416                    sel.reversed = !sel.reversed
17417                }
17418            });
17419        });
17420        self.request_autoscroll(Autoscroll::newest(), cx);
17421        cx.notify();
17422    }
17423
17424    pub fn toggle_focus(
17425        workspace: &mut Workspace,
17426        _: &actions::ToggleFocus,
17427        window: &mut Window,
17428        cx: &mut Context<Workspace>,
17429    ) {
17430        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17431            return;
17432        };
17433        workspace.activate_item(&item, true, true, window, cx);
17434    }
17435
17436    pub fn toggle_fold(
17437        &mut self,
17438        _: &actions::ToggleFold,
17439        window: &mut Window,
17440        cx: &mut Context<Self>,
17441    ) {
17442        if self.is_singleton(cx) {
17443            let selection = self.selections.newest::<Point>(cx);
17444
17445            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17446            let range = if selection.is_empty() {
17447                let point = selection.head().to_display_point(&display_map);
17448                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17449                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17450                    .to_point(&display_map);
17451                start..end
17452            } else {
17453                selection.range()
17454            };
17455            if display_map.folds_in_range(range).next().is_some() {
17456                self.unfold_lines(&Default::default(), window, cx)
17457            } else {
17458                self.fold(&Default::default(), window, cx)
17459            }
17460        } else {
17461            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17462            let buffer_ids: HashSet<_> = self
17463                .selections
17464                .disjoint_anchor_ranges()
17465                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17466                .collect();
17467
17468            let should_unfold = buffer_ids
17469                .iter()
17470                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17471
17472            for buffer_id in buffer_ids {
17473                if should_unfold {
17474                    self.unfold_buffer(buffer_id, cx);
17475                } else {
17476                    self.fold_buffer(buffer_id, cx);
17477                }
17478            }
17479        }
17480    }
17481
17482    pub fn toggle_fold_recursive(
17483        &mut self,
17484        _: &actions::ToggleFoldRecursive,
17485        window: &mut Window,
17486        cx: &mut Context<Self>,
17487    ) {
17488        let selection = self.selections.newest::<Point>(cx);
17489
17490        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17491        let range = if selection.is_empty() {
17492            let point = selection.head().to_display_point(&display_map);
17493            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17494            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17495                .to_point(&display_map);
17496            start..end
17497        } else {
17498            selection.range()
17499        };
17500        if display_map.folds_in_range(range).next().is_some() {
17501            self.unfold_recursive(&Default::default(), window, cx)
17502        } else {
17503            self.fold_recursive(&Default::default(), window, cx)
17504        }
17505    }
17506
17507    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17508        if self.is_singleton(cx) {
17509            let mut to_fold = Vec::new();
17510            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17511            let selections = self.selections.all_adjusted(cx);
17512
17513            for selection in selections {
17514                let range = selection.range().sorted();
17515                let buffer_start_row = range.start.row;
17516
17517                if range.start.row != range.end.row {
17518                    let mut found = false;
17519                    let mut row = range.start.row;
17520                    while row <= range.end.row {
17521                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17522                        {
17523                            found = true;
17524                            row = crease.range().end.row + 1;
17525                            to_fold.push(crease);
17526                        } else {
17527                            row += 1
17528                        }
17529                    }
17530                    if found {
17531                        continue;
17532                    }
17533                }
17534
17535                for row in (0..=range.start.row).rev() {
17536                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17537                        && crease.range().end.row >= buffer_start_row
17538                    {
17539                        to_fold.push(crease);
17540                        if row <= range.start.row {
17541                            break;
17542                        }
17543                    }
17544                }
17545            }
17546
17547            self.fold_creases(to_fold, true, window, cx);
17548        } else {
17549            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17550            let buffer_ids = self
17551                .selections
17552                .disjoint_anchor_ranges()
17553                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17554                .collect::<HashSet<_>>();
17555            for buffer_id in buffer_ids {
17556                self.fold_buffer(buffer_id, cx);
17557            }
17558        }
17559    }
17560
17561    pub fn toggle_fold_all(
17562        &mut self,
17563        _: &actions::ToggleFoldAll,
17564        window: &mut Window,
17565        cx: &mut Context<Self>,
17566    ) {
17567        if self.buffer.read(cx).is_singleton() {
17568            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17569            let has_folds = display_map
17570                .folds_in_range(0..display_map.buffer_snapshot.len())
17571                .next()
17572                .is_some();
17573
17574            if has_folds {
17575                self.unfold_all(&actions::UnfoldAll, window, cx);
17576            } else {
17577                self.fold_all(&actions::FoldAll, window, cx);
17578            }
17579        } else {
17580            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17581            let should_unfold = buffer_ids
17582                .iter()
17583                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17584
17585            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17586                editor
17587                    .update_in(cx, |editor, _, cx| {
17588                        for buffer_id in buffer_ids {
17589                            if should_unfold {
17590                                editor.unfold_buffer(buffer_id, cx);
17591                            } else {
17592                                editor.fold_buffer(buffer_id, cx);
17593                            }
17594                        }
17595                    })
17596                    .ok();
17597            });
17598        }
17599    }
17600
17601    fn fold_at_level(
17602        &mut self,
17603        fold_at: &FoldAtLevel,
17604        window: &mut Window,
17605        cx: &mut Context<Self>,
17606    ) {
17607        if !self.buffer.read(cx).is_singleton() {
17608            return;
17609        }
17610
17611        let fold_at_level = fold_at.0;
17612        let snapshot = self.buffer.read(cx).snapshot(cx);
17613        let mut to_fold = Vec::new();
17614        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17615
17616        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17617            while start_row < end_row {
17618                match self
17619                    .snapshot(window, cx)
17620                    .crease_for_buffer_row(MultiBufferRow(start_row))
17621                {
17622                    Some(crease) => {
17623                        let nested_start_row = crease.range().start.row + 1;
17624                        let nested_end_row = crease.range().end.row;
17625
17626                        if current_level < fold_at_level {
17627                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17628                        } else if current_level == fold_at_level {
17629                            to_fold.push(crease);
17630                        }
17631
17632                        start_row = nested_end_row + 1;
17633                    }
17634                    None => start_row += 1,
17635                }
17636            }
17637        }
17638
17639        self.fold_creases(to_fold, true, window, cx);
17640    }
17641
17642    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17643        if self.buffer.read(cx).is_singleton() {
17644            let mut fold_ranges = Vec::new();
17645            let snapshot = self.buffer.read(cx).snapshot(cx);
17646
17647            for row in 0..snapshot.max_row().0 {
17648                if let Some(foldable_range) = self
17649                    .snapshot(window, cx)
17650                    .crease_for_buffer_row(MultiBufferRow(row))
17651                {
17652                    fold_ranges.push(foldable_range);
17653                }
17654            }
17655
17656            self.fold_creases(fold_ranges, true, window, cx);
17657        } else {
17658            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17659                editor
17660                    .update_in(cx, |editor, _, cx| {
17661                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17662                            editor.fold_buffer(buffer_id, cx);
17663                        }
17664                    })
17665                    .ok();
17666            });
17667        }
17668    }
17669
17670    pub fn fold_function_bodies(
17671        &mut self,
17672        _: &actions::FoldFunctionBodies,
17673        window: &mut Window,
17674        cx: &mut Context<Self>,
17675    ) {
17676        let snapshot = self.buffer.read(cx).snapshot(cx);
17677
17678        let ranges = snapshot
17679            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17680            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17681            .collect::<Vec<_>>();
17682
17683        let creases = ranges
17684            .into_iter()
17685            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17686            .collect();
17687
17688        self.fold_creases(creases, true, window, cx);
17689    }
17690
17691    pub fn fold_recursive(
17692        &mut self,
17693        _: &actions::FoldRecursive,
17694        window: &mut Window,
17695        cx: &mut Context<Self>,
17696    ) {
17697        let mut to_fold = Vec::new();
17698        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17699        let selections = self.selections.all_adjusted(cx);
17700
17701        for selection in selections {
17702            let range = selection.range().sorted();
17703            let buffer_start_row = range.start.row;
17704
17705            if range.start.row != range.end.row {
17706                let mut found = false;
17707                for row in range.start.row..=range.end.row {
17708                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17709                        found = true;
17710                        to_fold.push(crease);
17711                    }
17712                }
17713                if found {
17714                    continue;
17715                }
17716            }
17717
17718            for row in (0..=range.start.row).rev() {
17719                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17720                    if crease.range().end.row >= buffer_start_row {
17721                        to_fold.push(crease);
17722                    } else {
17723                        break;
17724                    }
17725                }
17726            }
17727        }
17728
17729        self.fold_creases(to_fold, true, window, cx);
17730    }
17731
17732    pub fn fold_at(
17733        &mut self,
17734        buffer_row: MultiBufferRow,
17735        window: &mut Window,
17736        cx: &mut Context<Self>,
17737    ) {
17738        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17739
17740        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17741            let autoscroll = self
17742                .selections
17743                .all::<Point>(cx)
17744                .iter()
17745                .any(|selection| crease.range().overlaps(&selection.range()));
17746
17747            self.fold_creases(vec![crease], autoscroll, window, cx);
17748        }
17749    }
17750
17751    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17752        if self.is_singleton(cx) {
17753            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17754            let buffer = &display_map.buffer_snapshot;
17755            let selections = self.selections.all::<Point>(cx);
17756            let ranges = selections
17757                .iter()
17758                .map(|s| {
17759                    let range = s.display_range(&display_map).sorted();
17760                    let mut start = range.start.to_point(&display_map);
17761                    let mut end = range.end.to_point(&display_map);
17762                    start.column = 0;
17763                    end.column = buffer.line_len(MultiBufferRow(end.row));
17764                    start..end
17765                })
17766                .collect::<Vec<_>>();
17767
17768            self.unfold_ranges(&ranges, true, true, cx);
17769        } else {
17770            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17771            let buffer_ids = self
17772                .selections
17773                .disjoint_anchor_ranges()
17774                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17775                .collect::<HashSet<_>>();
17776            for buffer_id in buffer_ids {
17777                self.unfold_buffer(buffer_id, cx);
17778            }
17779        }
17780    }
17781
17782    pub fn unfold_recursive(
17783        &mut self,
17784        _: &UnfoldRecursive,
17785        _window: &mut Window,
17786        cx: &mut Context<Self>,
17787    ) {
17788        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17789        let selections = self.selections.all::<Point>(cx);
17790        let ranges = selections
17791            .iter()
17792            .map(|s| {
17793                let mut range = s.display_range(&display_map).sorted();
17794                *range.start.column_mut() = 0;
17795                *range.end.column_mut() = display_map.line_len(range.end.row());
17796                let start = range.start.to_point(&display_map);
17797                let end = range.end.to_point(&display_map);
17798                start..end
17799            })
17800            .collect::<Vec<_>>();
17801
17802        self.unfold_ranges(&ranges, true, true, cx);
17803    }
17804
17805    pub fn unfold_at(
17806        &mut self,
17807        buffer_row: MultiBufferRow,
17808        _window: &mut Window,
17809        cx: &mut Context<Self>,
17810    ) {
17811        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17812
17813        let intersection_range = Point::new(buffer_row.0, 0)
17814            ..Point::new(
17815                buffer_row.0,
17816                display_map.buffer_snapshot.line_len(buffer_row),
17817            );
17818
17819        let autoscroll = self
17820            .selections
17821            .all::<Point>(cx)
17822            .iter()
17823            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17824
17825        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17826    }
17827
17828    pub fn unfold_all(
17829        &mut self,
17830        _: &actions::UnfoldAll,
17831        _window: &mut Window,
17832        cx: &mut Context<Self>,
17833    ) {
17834        if self.buffer.read(cx).is_singleton() {
17835            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17836            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17837        } else {
17838            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17839                editor
17840                    .update(cx, |editor, cx| {
17841                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17842                            editor.unfold_buffer(buffer_id, cx);
17843                        }
17844                    })
17845                    .ok();
17846            });
17847        }
17848    }
17849
17850    pub fn fold_selected_ranges(
17851        &mut self,
17852        _: &FoldSelectedRanges,
17853        window: &mut Window,
17854        cx: &mut Context<Self>,
17855    ) {
17856        let selections = self.selections.all_adjusted(cx);
17857        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17858        let ranges = selections
17859            .into_iter()
17860            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17861            .collect::<Vec<_>>();
17862        self.fold_creases(ranges, true, window, cx);
17863    }
17864
17865    pub fn fold_ranges<T: ToOffset + Clone>(
17866        &mut self,
17867        ranges: Vec<Range<T>>,
17868        auto_scroll: bool,
17869        window: &mut Window,
17870        cx: &mut Context<Self>,
17871    ) {
17872        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17873        let ranges = ranges
17874            .into_iter()
17875            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17876            .collect::<Vec<_>>();
17877        self.fold_creases(ranges, auto_scroll, window, cx);
17878    }
17879
17880    pub fn fold_creases<T: ToOffset + Clone>(
17881        &mut self,
17882        creases: Vec<Crease<T>>,
17883        auto_scroll: bool,
17884        _window: &mut Window,
17885        cx: &mut Context<Self>,
17886    ) {
17887        if creases.is_empty() {
17888            return;
17889        }
17890
17891        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17892
17893        if auto_scroll {
17894            self.request_autoscroll(Autoscroll::fit(), cx);
17895        }
17896
17897        cx.notify();
17898
17899        self.scrollbar_marker_state.dirty = true;
17900        self.folds_did_change(cx);
17901    }
17902
17903    /// Removes any folds whose ranges intersect any of the given ranges.
17904    pub fn unfold_ranges<T: ToOffset + Clone>(
17905        &mut self,
17906        ranges: &[Range<T>],
17907        inclusive: bool,
17908        auto_scroll: bool,
17909        cx: &mut Context<Self>,
17910    ) {
17911        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17912            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17913        });
17914        self.folds_did_change(cx);
17915    }
17916
17917    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17918        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17919            return;
17920        }
17921        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17922        self.display_map.update(cx, |display_map, cx| {
17923            display_map.fold_buffers([buffer_id], cx)
17924        });
17925        cx.emit(EditorEvent::BufferFoldToggled {
17926            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17927            folded: true,
17928        });
17929        cx.notify();
17930    }
17931
17932    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17933        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17934            return;
17935        }
17936        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17937        self.display_map.update(cx, |display_map, cx| {
17938            display_map.unfold_buffers([buffer_id], cx);
17939        });
17940        cx.emit(EditorEvent::BufferFoldToggled {
17941            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17942            folded: false,
17943        });
17944        cx.notify();
17945    }
17946
17947    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17948        self.display_map.read(cx).is_buffer_folded(buffer)
17949    }
17950
17951    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17952        self.display_map.read(cx).folded_buffers()
17953    }
17954
17955    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17956        self.display_map.update(cx, |display_map, cx| {
17957            display_map.disable_header_for_buffer(buffer_id, cx);
17958        });
17959        cx.notify();
17960    }
17961
17962    /// Removes any folds with the given ranges.
17963    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17964        &mut self,
17965        ranges: &[Range<T>],
17966        type_id: TypeId,
17967        auto_scroll: bool,
17968        cx: &mut Context<Self>,
17969    ) {
17970        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17971            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17972        });
17973        self.folds_did_change(cx);
17974    }
17975
17976    fn remove_folds_with<T: ToOffset + Clone>(
17977        &mut self,
17978        ranges: &[Range<T>],
17979        auto_scroll: bool,
17980        cx: &mut Context<Self>,
17981        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17982    ) {
17983        if ranges.is_empty() {
17984            return;
17985        }
17986
17987        let mut buffers_affected = HashSet::default();
17988        let multi_buffer = self.buffer().read(cx);
17989        for range in ranges {
17990            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17991                buffers_affected.insert(buffer.read(cx).remote_id());
17992            };
17993        }
17994
17995        self.display_map.update(cx, update);
17996
17997        if auto_scroll {
17998            self.request_autoscroll(Autoscroll::fit(), cx);
17999        }
18000
18001        cx.notify();
18002        self.scrollbar_marker_state.dirty = true;
18003        self.active_indent_guides_state.dirty = true;
18004    }
18005
18006    pub fn update_renderer_widths(
18007        &mut self,
18008        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18009        cx: &mut Context<Self>,
18010    ) -> bool {
18011        self.display_map
18012            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18013    }
18014
18015    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18016        self.display_map.read(cx).fold_placeholder.clone()
18017    }
18018
18019    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18020        self.buffer.update(cx, |buffer, cx| {
18021            buffer.set_all_diff_hunks_expanded(cx);
18022        });
18023    }
18024
18025    pub fn expand_all_diff_hunks(
18026        &mut self,
18027        _: &ExpandAllDiffHunks,
18028        _window: &mut Window,
18029        cx: &mut Context<Self>,
18030    ) {
18031        self.buffer.update(cx, |buffer, cx| {
18032            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18033        });
18034    }
18035
18036    pub fn toggle_selected_diff_hunks(
18037        &mut self,
18038        _: &ToggleSelectedDiffHunks,
18039        _window: &mut Window,
18040        cx: &mut Context<Self>,
18041    ) {
18042        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18043        self.toggle_diff_hunks_in_ranges(ranges, cx);
18044    }
18045
18046    pub fn diff_hunks_in_ranges<'a>(
18047        &'a self,
18048        ranges: &'a [Range<Anchor>],
18049        buffer: &'a MultiBufferSnapshot,
18050    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18051        ranges.iter().flat_map(move |range| {
18052            let end_excerpt_id = range.end.excerpt_id;
18053            let range = range.to_point(buffer);
18054            let mut peek_end = range.end;
18055            if range.end.row < buffer.max_row().0 {
18056                peek_end = Point::new(range.end.row + 1, 0);
18057            }
18058            buffer
18059                .diff_hunks_in_range(range.start..peek_end)
18060                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18061        })
18062    }
18063
18064    pub fn has_stageable_diff_hunks_in_ranges(
18065        &self,
18066        ranges: &[Range<Anchor>],
18067        snapshot: &MultiBufferSnapshot,
18068    ) -> bool {
18069        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18070        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18071    }
18072
18073    pub fn toggle_staged_selected_diff_hunks(
18074        &mut self,
18075        _: &::git::ToggleStaged,
18076        _: &mut Window,
18077        cx: &mut Context<Self>,
18078    ) {
18079        let snapshot = self.buffer.read(cx).snapshot(cx);
18080        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18081        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18082        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18083    }
18084
18085    pub fn set_render_diff_hunk_controls(
18086        &mut self,
18087        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18088        cx: &mut Context<Self>,
18089    ) {
18090        self.render_diff_hunk_controls = render_diff_hunk_controls;
18091        cx.notify();
18092    }
18093
18094    pub fn stage_and_next(
18095        &mut self,
18096        _: &::git::StageAndNext,
18097        window: &mut Window,
18098        cx: &mut Context<Self>,
18099    ) {
18100        self.do_stage_or_unstage_and_next(true, window, cx);
18101    }
18102
18103    pub fn unstage_and_next(
18104        &mut self,
18105        _: &::git::UnstageAndNext,
18106        window: &mut Window,
18107        cx: &mut Context<Self>,
18108    ) {
18109        self.do_stage_or_unstage_and_next(false, window, cx);
18110    }
18111
18112    pub fn stage_or_unstage_diff_hunks(
18113        &mut self,
18114        stage: bool,
18115        ranges: Vec<Range<Anchor>>,
18116        cx: &mut Context<Self>,
18117    ) {
18118        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18119        cx.spawn(async move |this, cx| {
18120            task.await?;
18121            this.update(cx, |this, cx| {
18122                let snapshot = this.buffer.read(cx).snapshot(cx);
18123                let chunk_by = this
18124                    .diff_hunks_in_ranges(&ranges, &snapshot)
18125                    .chunk_by(|hunk| hunk.buffer_id);
18126                for (buffer_id, hunks) in &chunk_by {
18127                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18128                }
18129            })
18130        })
18131        .detach_and_log_err(cx);
18132    }
18133
18134    fn save_buffers_for_ranges_if_needed(
18135        &mut self,
18136        ranges: &[Range<Anchor>],
18137        cx: &mut Context<Editor>,
18138    ) -> Task<Result<()>> {
18139        let multibuffer = self.buffer.read(cx);
18140        let snapshot = multibuffer.read(cx);
18141        let buffer_ids: HashSet<_> = ranges
18142            .iter()
18143            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18144            .collect();
18145        drop(snapshot);
18146
18147        let mut buffers = HashSet::default();
18148        for buffer_id in buffer_ids {
18149            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18150                let buffer = buffer_entity.read(cx);
18151                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18152                {
18153                    buffers.insert(buffer_entity);
18154                }
18155            }
18156        }
18157
18158        if let Some(project) = &self.project {
18159            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18160        } else {
18161            Task::ready(Ok(()))
18162        }
18163    }
18164
18165    fn do_stage_or_unstage_and_next(
18166        &mut self,
18167        stage: bool,
18168        window: &mut Window,
18169        cx: &mut Context<Self>,
18170    ) {
18171        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18172
18173        if ranges.iter().any(|range| range.start != range.end) {
18174            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18175            return;
18176        }
18177
18178        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18179        let snapshot = self.snapshot(window, cx);
18180        let position = self.selections.newest::<Point>(cx).head();
18181        let mut row = snapshot
18182            .buffer_snapshot
18183            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18184            .find(|hunk| hunk.row_range.start.0 > position.row)
18185            .map(|hunk| hunk.row_range.start);
18186
18187        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18188        // Outside of the project diff editor, wrap around to the beginning.
18189        if !all_diff_hunks_expanded {
18190            row = row.or_else(|| {
18191                snapshot
18192                    .buffer_snapshot
18193                    .diff_hunks_in_range(Point::zero()..position)
18194                    .find(|hunk| hunk.row_range.end.0 < position.row)
18195                    .map(|hunk| hunk.row_range.start)
18196            });
18197        }
18198
18199        if let Some(row) = row {
18200            let destination = Point::new(row.0, 0);
18201            let autoscroll = Autoscroll::center();
18202
18203            self.unfold_ranges(&[destination..destination], false, false, cx);
18204            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18205                s.select_ranges([destination..destination]);
18206            });
18207        }
18208    }
18209
18210    fn do_stage_or_unstage(
18211        &self,
18212        stage: bool,
18213        buffer_id: BufferId,
18214        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18215        cx: &mut App,
18216    ) -> Option<()> {
18217        let project = self.project()?;
18218        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18219        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18220        let buffer_snapshot = buffer.read(cx).snapshot();
18221        let file_exists = buffer_snapshot
18222            .file()
18223            .is_some_and(|file| file.disk_state().exists());
18224        diff.update(cx, |diff, cx| {
18225            diff.stage_or_unstage_hunks(
18226                stage,
18227                &hunks
18228                    .map(|hunk| buffer_diff::DiffHunk {
18229                        buffer_range: hunk.buffer_range,
18230                        diff_base_byte_range: hunk.diff_base_byte_range,
18231                        secondary_status: hunk.secondary_status,
18232                        range: Point::zero()..Point::zero(), // unused
18233                    })
18234                    .collect::<Vec<_>>(),
18235                &buffer_snapshot,
18236                file_exists,
18237                cx,
18238            )
18239        });
18240        None
18241    }
18242
18243    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18244        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18245        self.buffer
18246            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18247    }
18248
18249    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18250        self.buffer.update(cx, |buffer, cx| {
18251            let ranges = vec![Anchor::min()..Anchor::max()];
18252            if !buffer.all_diff_hunks_expanded()
18253                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18254            {
18255                buffer.collapse_diff_hunks(ranges, cx);
18256                true
18257            } else {
18258                false
18259            }
18260        })
18261    }
18262
18263    fn toggle_diff_hunks_in_ranges(
18264        &mut self,
18265        ranges: Vec<Range<Anchor>>,
18266        cx: &mut Context<Editor>,
18267    ) {
18268        self.buffer.update(cx, |buffer, cx| {
18269            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18270            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18271        })
18272    }
18273
18274    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18275        self.buffer.update(cx, |buffer, cx| {
18276            let snapshot = buffer.snapshot(cx);
18277            let excerpt_id = range.end.excerpt_id;
18278            let point_range = range.to_point(&snapshot);
18279            let expand = !buffer.single_hunk_is_expanded(range, cx);
18280            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18281        })
18282    }
18283
18284    pub(crate) fn apply_all_diff_hunks(
18285        &mut self,
18286        _: &ApplyAllDiffHunks,
18287        window: &mut Window,
18288        cx: &mut Context<Self>,
18289    ) {
18290        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18291
18292        let buffers = self.buffer.read(cx).all_buffers();
18293        for branch_buffer in buffers {
18294            branch_buffer.update(cx, |branch_buffer, cx| {
18295                branch_buffer.merge_into_base(Vec::new(), cx);
18296            });
18297        }
18298
18299        if let Some(project) = self.project.clone() {
18300            self.save(
18301                SaveOptions {
18302                    format: true,
18303                    autosave: false,
18304                },
18305                project,
18306                window,
18307                cx,
18308            )
18309            .detach_and_log_err(cx);
18310        }
18311    }
18312
18313    pub(crate) fn apply_selected_diff_hunks(
18314        &mut self,
18315        _: &ApplyDiffHunk,
18316        window: &mut Window,
18317        cx: &mut Context<Self>,
18318    ) {
18319        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18320        let snapshot = self.snapshot(window, cx);
18321        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18322        let mut ranges_by_buffer = HashMap::default();
18323        self.transact(window, cx, |editor, _window, cx| {
18324            for hunk in hunks {
18325                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18326                    ranges_by_buffer
18327                        .entry(buffer.clone())
18328                        .or_insert_with(Vec::new)
18329                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18330                }
18331            }
18332
18333            for (buffer, ranges) in ranges_by_buffer {
18334                buffer.update(cx, |buffer, cx| {
18335                    buffer.merge_into_base(ranges, cx);
18336                });
18337            }
18338        });
18339
18340        if let Some(project) = self.project.clone() {
18341            self.save(
18342                SaveOptions {
18343                    format: true,
18344                    autosave: false,
18345                },
18346                project,
18347                window,
18348                cx,
18349            )
18350            .detach_and_log_err(cx);
18351        }
18352    }
18353
18354    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18355        if hovered != self.gutter_hovered {
18356            self.gutter_hovered = hovered;
18357            cx.notify();
18358        }
18359    }
18360
18361    pub fn insert_blocks(
18362        &mut self,
18363        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18364        autoscroll: Option<Autoscroll>,
18365        cx: &mut Context<Self>,
18366    ) -> Vec<CustomBlockId> {
18367        let blocks = self
18368            .display_map
18369            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18370        if let Some(autoscroll) = autoscroll {
18371            self.request_autoscroll(autoscroll, cx);
18372        }
18373        cx.notify();
18374        blocks
18375    }
18376
18377    pub fn resize_blocks(
18378        &mut self,
18379        heights: HashMap<CustomBlockId, u32>,
18380        autoscroll: Option<Autoscroll>,
18381        cx: &mut Context<Self>,
18382    ) {
18383        self.display_map
18384            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18385        if let Some(autoscroll) = autoscroll {
18386            self.request_autoscroll(autoscroll, cx);
18387        }
18388        cx.notify();
18389    }
18390
18391    pub fn replace_blocks(
18392        &mut self,
18393        renderers: HashMap<CustomBlockId, RenderBlock>,
18394        autoscroll: Option<Autoscroll>,
18395        cx: &mut Context<Self>,
18396    ) {
18397        self.display_map
18398            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18399        if let Some(autoscroll) = autoscroll {
18400            self.request_autoscroll(autoscroll, cx);
18401        }
18402        cx.notify();
18403    }
18404
18405    pub fn remove_blocks(
18406        &mut self,
18407        block_ids: HashSet<CustomBlockId>,
18408        autoscroll: Option<Autoscroll>,
18409        cx: &mut Context<Self>,
18410    ) {
18411        self.display_map.update(cx, |display_map, cx| {
18412            display_map.remove_blocks(block_ids, cx)
18413        });
18414        if let Some(autoscroll) = autoscroll {
18415            self.request_autoscroll(autoscroll, cx);
18416        }
18417        cx.notify();
18418    }
18419
18420    pub fn row_for_block(
18421        &self,
18422        block_id: CustomBlockId,
18423        cx: &mut Context<Self>,
18424    ) -> Option<DisplayRow> {
18425        self.display_map
18426            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18427    }
18428
18429    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18430        self.focused_block = Some(focused_block);
18431    }
18432
18433    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18434        self.focused_block.take()
18435    }
18436
18437    pub fn insert_creases(
18438        &mut self,
18439        creases: impl IntoIterator<Item = Crease<Anchor>>,
18440        cx: &mut Context<Self>,
18441    ) -> Vec<CreaseId> {
18442        self.display_map
18443            .update(cx, |map, cx| map.insert_creases(creases, cx))
18444    }
18445
18446    pub fn remove_creases(
18447        &mut self,
18448        ids: impl IntoIterator<Item = CreaseId>,
18449        cx: &mut Context<Self>,
18450    ) -> Vec<(CreaseId, Range<Anchor>)> {
18451        self.display_map
18452            .update(cx, |map, cx| map.remove_creases(ids, cx))
18453    }
18454
18455    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18456        self.display_map
18457            .update(cx, |map, cx| map.snapshot(cx))
18458            .longest_row()
18459    }
18460
18461    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18462        self.display_map
18463            .update(cx, |map, cx| map.snapshot(cx))
18464            .max_point()
18465    }
18466
18467    pub fn text(&self, cx: &App) -> String {
18468        self.buffer.read(cx).read(cx).text()
18469    }
18470
18471    pub fn is_empty(&self, cx: &App) -> bool {
18472        self.buffer.read(cx).read(cx).is_empty()
18473    }
18474
18475    pub fn text_option(&self, cx: &App) -> Option<String> {
18476        let text = self.text(cx);
18477        let text = text.trim();
18478
18479        if text.is_empty() {
18480            return None;
18481        }
18482
18483        Some(text.to_string())
18484    }
18485
18486    pub fn set_text(
18487        &mut self,
18488        text: impl Into<Arc<str>>,
18489        window: &mut Window,
18490        cx: &mut Context<Self>,
18491    ) {
18492        self.transact(window, cx, |this, _, cx| {
18493            this.buffer
18494                .read(cx)
18495                .as_singleton()
18496                .expect("you can only call set_text on editors for singleton buffers")
18497                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18498        });
18499    }
18500
18501    pub fn display_text(&self, cx: &mut App) -> String {
18502        self.display_map
18503            .update(cx, |map, cx| map.snapshot(cx))
18504            .text()
18505    }
18506
18507    fn create_minimap(
18508        &self,
18509        minimap_settings: MinimapSettings,
18510        window: &mut Window,
18511        cx: &mut Context<Self>,
18512    ) -> Option<Entity<Self>> {
18513        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18514            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18515    }
18516
18517    fn initialize_new_minimap(
18518        &self,
18519        minimap_settings: MinimapSettings,
18520        window: &mut Window,
18521        cx: &mut Context<Self>,
18522    ) -> Entity<Self> {
18523        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18524
18525        let mut minimap = Editor::new_internal(
18526            EditorMode::Minimap {
18527                parent: cx.weak_entity(),
18528            },
18529            self.buffer.clone(),
18530            None,
18531            Some(self.display_map.clone()),
18532            window,
18533            cx,
18534        );
18535        minimap.scroll_manager.clone_state(&self.scroll_manager);
18536        minimap.set_text_style_refinement(TextStyleRefinement {
18537            font_size: Some(MINIMAP_FONT_SIZE),
18538            font_weight: Some(MINIMAP_FONT_WEIGHT),
18539            ..Default::default()
18540        });
18541        minimap.update_minimap_configuration(minimap_settings, cx);
18542        cx.new(|_| minimap)
18543    }
18544
18545    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18546        let current_line_highlight = minimap_settings
18547            .current_line_highlight
18548            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18549        self.set_current_line_highlight(Some(current_line_highlight));
18550    }
18551
18552    pub fn minimap(&self) -> Option<&Entity<Self>> {
18553        self.minimap
18554            .as_ref()
18555            .filter(|_| self.minimap_visibility.visible())
18556    }
18557
18558    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18559        let mut wrap_guides = smallvec![];
18560
18561        if self.show_wrap_guides == Some(false) {
18562            return wrap_guides;
18563        }
18564
18565        let settings = self.buffer.read(cx).language_settings(cx);
18566        if settings.show_wrap_guides {
18567            match self.soft_wrap_mode(cx) {
18568                SoftWrap::Column(soft_wrap) => {
18569                    wrap_guides.push((soft_wrap as usize, true));
18570                }
18571                SoftWrap::Bounded(soft_wrap) => {
18572                    wrap_guides.push((soft_wrap as usize, true));
18573                }
18574                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18575            }
18576            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18577        }
18578
18579        wrap_guides
18580    }
18581
18582    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18583        let settings = self.buffer.read(cx).language_settings(cx);
18584        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18585        match mode {
18586            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18587                SoftWrap::None
18588            }
18589            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18590            language_settings::SoftWrap::PreferredLineLength => {
18591                SoftWrap::Column(settings.preferred_line_length)
18592            }
18593            language_settings::SoftWrap::Bounded => {
18594                SoftWrap::Bounded(settings.preferred_line_length)
18595            }
18596        }
18597    }
18598
18599    pub fn set_soft_wrap_mode(
18600        &mut self,
18601        mode: language_settings::SoftWrap,
18602
18603        cx: &mut Context<Self>,
18604    ) {
18605        self.soft_wrap_mode_override = Some(mode);
18606        cx.notify();
18607    }
18608
18609    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18610        self.hard_wrap = hard_wrap;
18611        cx.notify();
18612    }
18613
18614    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18615        self.text_style_refinement = Some(style);
18616    }
18617
18618    /// called by the Element so we know what style we were most recently rendered with.
18619    pub(crate) fn set_style(
18620        &mut self,
18621        style: EditorStyle,
18622        window: &mut Window,
18623        cx: &mut Context<Self>,
18624    ) {
18625        // We intentionally do not inform the display map about the minimap style
18626        // so that wrapping is not recalculated and stays consistent for the editor
18627        // and its linked minimap.
18628        if !self.mode.is_minimap() {
18629            let rem_size = window.rem_size();
18630            self.display_map.update(cx, |map, cx| {
18631                map.set_font(
18632                    style.text.font(),
18633                    style.text.font_size.to_pixels(rem_size),
18634                    cx,
18635                )
18636            });
18637        }
18638        self.style = Some(style);
18639    }
18640
18641    pub fn style(&self) -> Option<&EditorStyle> {
18642        self.style.as_ref()
18643    }
18644
18645    // Called by the element. This method is not designed to be called outside of the editor
18646    // element's layout code because it does not notify when rewrapping is computed synchronously.
18647    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18648        self.display_map
18649            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18650    }
18651
18652    pub fn set_soft_wrap(&mut self) {
18653        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18654    }
18655
18656    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18657        if self.soft_wrap_mode_override.is_some() {
18658            self.soft_wrap_mode_override.take();
18659        } else {
18660            let soft_wrap = match self.soft_wrap_mode(cx) {
18661                SoftWrap::GitDiff => return,
18662                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18663                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18664                    language_settings::SoftWrap::None
18665                }
18666            };
18667            self.soft_wrap_mode_override = Some(soft_wrap);
18668        }
18669        cx.notify();
18670    }
18671
18672    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18673        let Some(workspace) = self.workspace() else {
18674            return;
18675        };
18676        let fs = workspace.read(cx).app_state().fs.clone();
18677        let current_show = TabBarSettings::get_global(cx).show;
18678        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18679            setting.show = Some(!current_show);
18680        });
18681    }
18682
18683    pub fn toggle_indent_guides(
18684        &mut self,
18685        _: &ToggleIndentGuides,
18686        _: &mut Window,
18687        cx: &mut Context<Self>,
18688    ) {
18689        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18690            self.buffer
18691                .read(cx)
18692                .language_settings(cx)
18693                .indent_guides
18694                .enabled
18695        });
18696        self.show_indent_guides = Some(!currently_enabled);
18697        cx.notify();
18698    }
18699
18700    fn should_show_indent_guides(&self) -> Option<bool> {
18701        self.show_indent_guides
18702    }
18703
18704    pub fn toggle_line_numbers(
18705        &mut self,
18706        _: &ToggleLineNumbers,
18707        _: &mut Window,
18708        cx: &mut Context<Self>,
18709    ) {
18710        let mut editor_settings = EditorSettings::get_global(cx).clone();
18711        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18712        EditorSettings::override_global(editor_settings, cx);
18713    }
18714
18715    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18716        if let Some(show_line_numbers) = self.show_line_numbers {
18717            return show_line_numbers;
18718        }
18719        EditorSettings::get_global(cx).gutter.line_numbers
18720    }
18721
18722    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18723        self.use_relative_line_numbers
18724            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18725    }
18726
18727    pub fn toggle_relative_line_numbers(
18728        &mut self,
18729        _: &ToggleRelativeLineNumbers,
18730        _: &mut Window,
18731        cx: &mut Context<Self>,
18732    ) {
18733        let is_relative = self.should_use_relative_line_numbers(cx);
18734        self.set_relative_line_number(Some(!is_relative), cx)
18735    }
18736
18737    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18738        self.use_relative_line_numbers = is_relative;
18739        cx.notify();
18740    }
18741
18742    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18743        self.show_gutter = show_gutter;
18744        cx.notify();
18745    }
18746
18747    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18748        self.show_scrollbars = ScrollbarAxes {
18749            horizontal: show,
18750            vertical: show,
18751        };
18752        cx.notify();
18753    }
18754
18755    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18756        self.show_scrollbars.vertical = show;
18757        cx.notify();
18758    }
18759
18760    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18761        self.show_scrollbars.horizontal = show;
18762        cx.notify();
18763    }
18764
18765    pub fn set_minimap_visibility(
18766        &mut self,
18767        minimap_visibility: MinimapVisibility,
18768        window: &mut Window,
18769        cx: &mut Context<Self>,
18770    ) {
18771        if self.minimap_visibility != minimap_visibility {
18772            if minimap_visibility.visible() && self.minimap.is_none() {
18773                let minimap_settings = EditorSettings::get_global(cx).minimap;
18774                self.minimap =
18775                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18776            }
18777            self.minimap_visibility = minimap_visibility;
18778            cx.notify();
18779        }
18780    }
18781
18782    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18783        self.set_show_scrollbars(false, cx);
18784        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18785    }
18786
18787    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18788        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18789    }
18790
18791    /// Normally the text in full mode and auto height editors is padded on the
18792    /// left side by roughly half a character width for improved hit testing.
18793    ///
18794    /// Use this method to disable this for cases where this is not wanted (e.g.
18795    /// if you want to align the editor text with some other text above or below)
18796    /// or if you want to add this padding to single-line editors.
18797    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18798        self.offset_content = offset_content;
18799        cx.notify();
18800    }
18801
18802    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18803        self.show_line_numbers = Some(show_line_numbers);
18804        cx.notify();
18805    }
18806
18807    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18808        self.disable_expand_excerpt_buttons = true;
18809        cx.notify();
18810    }
18811
18812    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18813        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18814        cx.notify();
18815    }
18816
18817    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18818        self.show_code_actions = Some(show_code_actions);
18819        cx.notify();
18820    }
18821
18822    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18823        self.show_runnables = Some(show_runnables);
18824        cx.notify();
18825    }
18826
18827    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18828        self.show_breakpoints = Some(show_breakpoints);
18829        cx.notify();
18830    }
18831
18832    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18833        if self.display_map.read(cx).masked != masked {
18834            self.display_map.update(cx, |map, _| map.masked = masked);
18835        }
18836        cx.notify()
18837    }
18838
18839    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18840        self.show_wrap_guides = Some(show_wrap_guides);
18841        cx.notify();
18842    }
18843
18844    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18845        self.show_indent_guides = Some(show_indent_guides);
18846        cx.notify();
18847    }
18848
18849    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18850        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18851            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18852                && let Some(dir) = file.abs_path(cx).parent()
18853            {
18854                return Some(dir.to_owned());
18855            }
18856
18857            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18858                return Some(project_path.path.to_path_buf());
18859            }
18860        }
18861
18862        None
18863    }
18864
18865    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18866        self.active_excerpt(cx)?
18867            .1
18868            .read(cx)
18869            .file()
18870            .and_then(|f| f.as_local())
18871    }
18872
18873    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18874        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18875            let buffer = buffer.read(cx);
18876            if let Some(project_path) = buffer.project_path(cx) {
18877                let project = self.project()?.read(cx);
18878                project.absolute_path(&project_path, cx)
18879            } else {
18880                buffer
18881                    .file()
18882                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18883            }
18884        })
18885    }
18886
18887    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18888        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18889            let project_path = buffer.read(cx).project_path(cx)?;
18890            let project = self.project()?.read(cx);
18891            let entry = project.entry_for_path(&project_path, cx)?;
18892            let path = entry.path.to_path_buf();
18893            Some(path)
18894        })
18895    }
18896
18897    pub fn reveal_in_finder(
18898        &mut self,
18899        _: &RevealInFileManager,
18900        _window: &mut Window,
18901        cx: &mut Context<Self>,
18902    ) {
18903        if let Some(target) = self.target_file(cx) {
18904            cx.reveal_path(&target.abs_path(cx));
18905        }
18906    }
18907
18908    pub fn copy_path(
18909        &mut self,
18910        _: &zed_actions::workspace::CopyPath,
18911        _window: &mut Window,
18912        cx: &mut Context<Self>,
18913    ) {
18914        if let Some(path) = self.target_file_abs_path(cx)
18915            && let Some(path) = path.to_str()
18916        {
18917            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18918        }
18919    }
18920
18921    pub fn copy_relative_path(
18922        &mut self,
18923        _: &zed_actions::workspace::CopyRelativePath,
18924        _window: &mut Window,
18925        cx: &mut Context<Self>,
18926    ) {
18927        if let Some(path) = self.target_file_path(cx)
18928            && let Some(path) = path.to_str()
18929        {
18930            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18931        }
18932    }
18933
18934    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18935        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18936            buffer.read(cx).project_path(cx)
18937        } else {
18938            None
18939        }
18940    }
18941
18942    // Returns true if the editor handled a go-to-line request
18943    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18944        maybe!({
18945            let breakpoint_store = self.breakpoint_store.as_ref()?;
18946
18947            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18948            else {
18949                self.clear_row_highlights::<ActiveDebugLine>();
18950                return None;
18951            };
18952
18953            let position = active_stack_frame.position;
18954            let buffer_id = position.buffer_id?;
18955            let snapshot = self
18956                .project
18957                .as_ref()?
18958                .read(cx)
18959                .buffer_for_id(buffer_id, cx)?
18960                .read(cx)
18961                .snapshot();
18962
18963            let mut handled = false;
18964            for (id, ExcerptRange { context, .. }) in
18965                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18966            {
18967                if context.start.cmp(&position, &snapshot).is_ge()
18968                    || context.end.cmp(&position, &snapshot).is_lt()
18969                {
18970                    continue;
18971                }
18972                let snapshot = self.buffer.read(cx).snapshot(cx);
18973                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18974
18975                handled = true;
18976                self.clear_row_highlights::<ActiveDebugLine>();
18977
18978                self.go_to_line::<ActiveDebugLine>(
18979                    multibuffer_anchor,
18980                    Some(cx.theme().colors().editor_debugger_active_line_background),
18981                    window,
18982                    cx,
18983                );
18984
18985                cx.notify();
18986            }
18987
18988            handled.then_some(())
18989        })
18990        .is_some()
18991    }
18992
18993    pub fn copy_file_name_without_extension(
18994        &mut self,
18995        _: &CopyFileNameWithoutExtension,
18996        _: &mut Window,
18997        cx: &mut Context<Self>,
18998    ) {
18999        if let Some(file) = self.target_file(cx)
19000            && let Some(file_stem) = file.path().file_stem()
19001            && let Some(name) = file_stem.to_str()
19002        {
19003            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19004        }
19005    }
19006
19007    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19008        if let Some(file) = self.target_file(cx)
19009            && let Some(file_name) = file.path().file_name()
19010            && let Some(name) = file_name.to_str()
19011        {
19012            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19013        }
19014    }
19015
19016    pub fn toggle_git_blame(
19017        &mut self,
19018        _: &::git::Blame,
19019        window: &mut Window,
19020        cx: &mut Context<Self>,
19021    ) {
19022        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19023
19024        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19025            self.start_git_blame(true, window, cx);
19026        }
19027
19028        cx.notify();
19029    }
19030
19031    pub fn toggle_git_blame_inline(
19032        &mut self,
19033        _: &ToggleGitBlameInline,
19034        window: &mut Window,
19035        cx: &mut Context<Self>,
19036    ) {
19037        self.toggle_git_blame_inline_internal(true, window, cx);
19038        cx.notify();
19039    }
19040
19041    pub fn open_git_blame_commit(
19042        &mut self,
19043        _: &OpenGitBlameCommit,
19044        window: &mut Window,
19045        cx: &mut Context<Self>,
19046    ) {
19047        self.open_git_blame_commit_internal(window, cx);
19048    }
19049
19050    fn open_git_blame_commit_internal(
19051        &mut self,
19052        window: &mut Window,
19053        cx: &mut Context<Self>,
19054    ) -> Option<()> {
19055        let blame = self.blame.as_ref()?;
19056        let snapshot = self.snapshot(window, cx);
19057        let cursor = self.selections.newest::<Point>(cx).head();
19058        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19059        let blame_entry = blame
19060            .update(cx, |blame, cx| {
19061                blame
19062                    .blame_for_rows(
19063                        &[RowInfo {
19064                            buffer_id: Some(buffer.remote_id()),
19065                            buffer_row: Some(point.row),
19066                            ..Default::default()
19067                        }],
19068                        cx,
19069                    )
19070                    .next()
19071            })
19072            .flatten()?;
19073        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19074        let repo = blame.read(cx).repository(cx)?;
19075        let workspace = self.workspace()?.downgrade();
19076        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19077        None
19078    }
19079
19080    pub fn git_blame_inline_enabled(&self) -> bool {
19081        self.git_blame_inline_enabled
19082    }
19083
19084    pub fn toggle_selection_menu(
19085        &mut self,
19086        _: &ToggleSelectionMenu,
19087        _: &mut Window,
19088        cx: &mut Context<Self>,
19089    ) {
19090        self.show_selection_menu = self
19091            .show_selection_menu
19092            .map(|show_selections_menu| !show_selections_menu)
19093            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19094
19095        cx.notify();
19096    }
19097
19098    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19099        self.show_selection_menu
19100            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19101    }
19102
19103    fn start_git_blame(
19104        &mut self,
19105        user_triggered: bool,
19106        window: &mut Window,
19107        cx: &mut Context<Self>,
19108    ) {
19109        if let Some(project) = self.project() {
19110            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
19111                return;
19112            };
19113
19114            if buffer.read(cx).file().is_none() {
19115                return;
19116            }
19117
19118            let focused = self.focus_handle(cx).contains_focused(window, cx);
19119
19120            let project = project.clone();
19121            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
19122            self.blame_subscription =
19123                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19124            self.blame = Some(blame);
19125        }
19126    }
19127
19128    fn toggle_git_blame_inline_internal(
19129        &mut self,
19130        user_triggered: bool,
19131        window: &mut Window,
19132        cx: &mut Context<Self>,
19133    ) {
19134        if self.git_blame_inline_enabled {
19135            self.git_blame_inline_enabled = false;
19136            self.show_git_blame_inline = false;
19137            self.show_git_blame_inline_delay_task.take();
19138        } else {
19139            self.git_blame_inline_enabled = true;
19140            self.start_git_blame_inline(user_triggered, window, cx);
19141        }
19142
19143        cx.notify();
19144    }
19145
19146    fn start_git_blame_inline(
19147        &mut self,
19148        user_triggered: bool,
19149        window: &mut Window,
19150        cx: &mut Context<Self>,
19151    ) {
19152        self.start_git_blame(user_triggered, window, cx);
19153
19154        if ProjectSettings::get_global(cx)
19155            .git
19156            .inline_blame_delay()
19157            .is_some()
19158        {
19159            self.start_inline_blame_timer(window, cx);
19160        } else {
19161            self.show_git_blame_inline = true
19162        }
19163    }
19164
19165    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19166        self.blame.as_ref()
19167    }
19168
19169    pub fn show_git_blame_gutter(&self) -> bool {
19170        self.show_git_blame_gutter
19171    }
19172
19173    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19174        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19175    }
19176
19177    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19178        self.show_git_blame_inline
19179            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19180            && !self.newest_selection_head_on_empty_line(cx)
19181            && self.has_blame_entries(cx)
19182    }
19183
19184    fn has_blame_entries(&self, cx: &App) -> bool {
19185        self.blame()
19186            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19187    }
19188
19189    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19190        let cursor_anchor = self.selections.newest_anchor().head();
19191
19192        let snapshot = self.buffer.read(cx).snapshot(cx);
19193        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19194
19195        snapshot.line_len(buffer_row) == 0
19196    }
19197
19198    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19199        let buffer_and_selection = maybe!({
19200            let selection = self.selections.newest::<Point>(cx);
19201            let selection_range = selection.range();
19202
19203            let multi_buffer = self.buffer().read(cx);
19204            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19205            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19206
19207            let (buffer, range, _) = if selection.reversed {
19208                buffer_ranges.first()
19209            } else {
19210                buffer_ranges.last()
19211            }?;
19212
19213            let selection = text::ToPoint::to_point(&range.start, buffer).row
19214                ..text::ToPoint::to_point(&range.end, buffer).row;
19215            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19216        });
19217
19218        let Some((buffer, selection)) = buffer_and_selection else {
19219            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19220        };
19221
19222        let Some(project) = self.project() else {
19223            return Task::ready(Err(anyhow!("editor does not have project")));
19224        };
19225
19226        project.update(cx, |project, cx| {
19227            project.get_permalink_to_line(&buffer, selection, cx)
19228        })
19229    }
19230
19231    pub fn copy_permalink_to_line(
19232        &mut self,
19233        _: &CopyPermalinkToLine,
19234        window: &mut Window,
19235        cx: &mut Context<Self>,
19236    ) {
19237        let permalink_task = self.get_permalink_to_line(cx);
19238        let workspace = self.workspace();
19239
19240        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19241            Ok(permalink) => {
19242                cx.update(|_, cx| {
19243                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19244                })
19245                .ok();
19246            }
19247            Err(err) => {
19248                let message = format!("Failed to copy permalink: {err}");
19249
19250                anyhow::Result::<()>::Err(err).log_err();
19251
19252                if let Some(workspace) = workspace {
19253                    workspace
19254                        .update_in(cx, |workspace, _, cx| {
19255                            struct CopyPermalinkToLine;
19256
19257                            workspace.show_toast(
19258                                Toast::new(
19259                                    NotificationId::unique::<CopyPermalinkToLine>(),
19260                                    message,
19261                                ),
19262                                cx,
19263                            )
19264                        })
19265                        .ok();
19266                }
19267            }
19268        })
19269        .detach();
19270    }
19271
19272    pub fn copy_file_location(
19273        &mut self,
19274        _: &CopyFileLocation,
19275        _: &mut Window,
19276        cx: &mut Context<Self>,
19277    ) {
19278        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19279        if let Some(file) = self.target_file(cx)
19280            && let Some(path) = file.path().to_str()
19281        {
19282            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19283        }
19284    }
19285
19286    pub fn open_permalink_to_line(
19287        &mut self,
19288        _: &OpenPermalinkToLine,
19289        window: &mut Window,
19290        cx: &mut Context<Self>,
19291    ) {
19292        let permalink_task = self.get_permalink_to_line(cx);
19293        let workspace = self.workspace();
19294
19295        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19296            Ok(permalink) => {
19297                cx.update(|_, cx| {
19298                    cx.open_url(permalink.as_ref());
19299                })
19300                .ok();
19301            }
19302            Err(err) => {
19303                let message = format!("Failed to open permalink: {err}");
19304
19305                anyhow::Result::<()>::Err(err).log_err();
19306
19307                if let Some(workspace) = workspace {
19308                    workspace
19309                        .update(cx, |workspace, cx| {
19310                            struct OpenPermalinkToLine;
19311
19312                            workspace.show_toast(
19313                                Toast::new(
19314                                    NotificationId::unique::<OpenPermalinkToLine>(),
19315                                    message,
19316                                ),
19317                                cx,
19318                            )
19319                        })
19320                        .ok();
19321                }
19322            }
19323        })
19324        .detach();
19325    }
19326
19327    pub fn insert_uuid_v4(
19328        &mut self,
19329        _: &InsertUuidV4,
19330        window: &mut Window,
19331        cx: &mut Context<Self>,
19332    ) {
19333        self.insert_uuid(UuidVersion::V4, window, cx);
19334    }
19335
19336    pub fn insert_uuid_v7(
19337        &mut self,
19338        _: &InsertUuidV7,
19339        window: &mut Window,
19340        cx: &mut Context<Self>,
19341    ) {
19342        self.insert_uuid(UuidVersion::V7, window, cx);
19343    }
19344
19345    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19346        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19347        self.transact(window, cx, |this, window, cx| {
19348            let edits = this
19349                .selections
19350                .all::<Point>(cx)
19351                .into_iter()
19352                .map(|selection| {
19353                    let uuid = match version {
19354                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19355                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19356                    };
19357
19358                    (selection.range(), uuid.to_string())
19359                });
19360            this.edit(edits, cx);
19361            this.refresh_edit_prediction(true, false, window, cx);
19362        });
19363    }
19364
19365    pub fn open_selections_in_multibuffer(
19366        &mut self,
19367        _: &OpenSelectionsInMultibuffer,
19368        window: &mut Window,
19369        cx: &mut Context<Self>,
19370    ) {
19371        let multibuffer = self.buffer.read(cx);
19372
19373        let Some(buffer) = multibuffer.as_singleton() else {
19374            return;
19375        };
19376
19377        let Some(workspace) = self.workspace() else {
19378            return;
19379        };
19380
19381        let title = multibuffer.title(cx).to_string();
19382
19383        let locations = self
19384            .selections
19385            .all_anchors(cx)
19386            .iter()
19387            .map(|selection| Location {
19388                buffer: buffer.clone(),
19389                range: selection.start.text_anchor..selection.end.text_anchor,
19390            })
19391            .collect::<Vec<_>>();
19392
19393        cx.spawn_in(window, async move |_, cx| {
19394            workspace.update_in(cx, |workspace, window, cx| {
19395                Self::open_locations_in_multibuffer(
19396                    workspace,
19397                    locations,
19398                    format!("Selections for '{title}'"),
19399                    false,
19400                    MultibufferSelectionMode::All,
19401                    window,
19402                    cx,
19403                );
19404            })
19405        })
19406        .detach();
19407    }
19408
19409    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19410    /// last highlight added will be used.
19411    ///
19412    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19413    pub fn highlight_rows<T: 'static>(
19414        &mut self,
19415        range: Range<Anchor>,
19416        color: Hsla,
19417        options: RowHighlightOptions,
19418        cx: &mut Context<Self>,
19419    ) {
19420        let snapshot = self.buffer().read(cx).snapshot(cx);
19421        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19422        let ix = row_highlights.binary_search_by(|highlight| {
19423            Ordering::Equal
19424                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19425                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19426        });
19427
19428        if let Err(mut ix) = ix {
19429            let index = post_inc(&mut self.highlight_order);
19430
19431            // If this range intersects with the preceding highlight, then merge it with
19432            // the preceding highlight. Otherwise insert a new highlight.
19433            let mut merged = false;
19434            if ix > 0 {
19435                let prev_highlight = &mut row_highlights[ix - 1];
19436                if prev_highlight
19437                    .range
19438                    .end
19439                    .cmp(&range.start, &snapshot)
19440                    .is_ge()
19441                {
19442                    ix -= 1;
19443                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19444                        prev_highlight.range.end = range.end;
19445                    }
19446                    merged = true;
19447                    prev_highlight.index = index;
19448                    prev_highlight.color = color;
19449                    prev_highlight.options = options;
19450                }
19451            }
19452
19453            if !merged {
19454                row_highlights.insert(
19455                    ix,
19456                    RowHighlight {
19457                        range,
19458                        index,
19459                        color,
19460                        options,
19461                        type_id: TypeId::of::<T>(),
19462                    },
19463                );
19464            }
19465
19466            // If any of the following highlights intersect with this one, merge them.
19467            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19468                let highlight = &row_highlights[ix];
19469                if next_highlight
19470                    .range
19471                    .start
19472                    .cmp(&highlight.range.end, &snapshot)
19473                    .is_le()
19474                {
19475                    if next_highlight
19476                        .range
19477                        .end
19478                        .cmp(&highlight.range.end, &snapshot)
19479                        .is_gt()
19480                    {
19481                        row_highlights[ix].range.end = next_highlight.range.end;
19482                    }
19483                    row_highlights.remove(ix + 1);
19484                } else {
19485                    break;
19486                }
19487            }
19488        }
19489    }
19490
19491    /// Remove any highlighted row ranges of the given type that intersect the
19492    /// given ranges.
19493    pub fn remove_highlighted_rows<T: 'static>(
19494        &mut self,
19495        ranges_to_remove: Vec<Range<Anchor>>,
19496        cx: &mut Context<Self>,
19497    ) {
19498        let snapshot = self.buffer().read(cx).snapshot(cx);
19499        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19500        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19501        row_highlights.retain(|highlight| {
19502            while let Some(range_to_remove) = ranges_to_remove.peek() {
19503                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19504                    Ordering::Less | Ordering::Equal => {
19505                        ranges_to_remove.next();
19506                    }
19507                    Ordering::Greater => {
19508                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19509                            Ordering::Less | Ordering::Equal => {
19510                                return false;
19511                            }
19512                            Ordering::Greater => break,
19513                        }
19514                    }
19515                }
19516            }
19517
19518            true
19519        })
19520    }
19521
19522    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19523    pub fn clear_row_highlights<T: 'static>(&mut self) {
19524        self.highlighted_rows.remove(&TypeId::of::<T>());
19525    }
19526
19527    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19528    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19529        self.highlighted_rows
19530            .get(&TypeId::of::<T>())
19531            .map_or(&[] as &[_], |vec| vec.as_slice())
19532            .iter()
19533            .map(|highlight| (highlight.range.clone(), highlight.color))
19534    }
19535
19536    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19537    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19538    /// Allows to ignore certain kinds of highlights.
19539    pub fn highlighted_display_rows(
19540        &self,
19541        window: &mut Window,
19542        cx: &mut App,
19543    ) -> BTreeMap<DisplayRow, LineHighlight> {
19544        let snapshot = self.snapshot(window, cx);
19545        let mut used_highlight_orders = HashMap::default();
19546        self.highlighted_rows
19547            .iter()
19548            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19549            .fold(
19550                BTreeMap::<DisplayRow, LineHighlight>::new(),
19551                |mut unique_rows, highlight| {
19552                    let start = highlight.range.start.to_display_point(&snapshot);
19553                    let end = highlight.range.end.to_display_point(&snapshot);
19554                    let start_row = start.row().0;
19555                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19556                        && end.column() == 0
19557                    {
19558                        end.row().0.saturating_sub(1)
19559                    } else {
19560                        end.row().0
19561                    };
19562                    for row in start_row..=end_row {
19563                        let used_index =
19564                            used_highlight_orders.entry(row).or_insert(highlight.index);
19565                        if highlight.index >= *used_index {
19566                            *used_index = highlight.index;
19567                            unique_rows.insert(
19568                                DisplayRow(row),
19569                                LineHighlight {
19570                                    include_gutter: highlight.options.include_gutter,
19571                                    border: None,
19572                                    background: highlight.color.into(),
19573                                    type_id: Some(highlight.type_id),
19574                                },
19575                            );
19576                        }
19577                    }
19578                    unique_rows
19579                },
19580            )
19581    }
19582
19583    pub fn highlighted_display_row_for_autoscroll(
19584        &self,
19585        snapshot: &DisplaySnapshot,
19586    ) -> Option<DisplayRow> {
19587        self.highlighted_rows
19588            .values()
19589            .flat_map(|highlighted_rows| highlighted_rows.iter())
19590            .filter_map(|highlight| {
19591                if highlight.options.autoscroll {
19592                    Some(highlight.range.start.to_display_point(snapshot).row())
19593                } else {
19594                    None
19595                }
19596            })
19597            .min()
19598    }
19599
19600    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19601        self.highlight_background::<SearchWithinRange>(
19602            ranges,
19603            |colors| colors.colors().editor_document_highlight_read_background,
19604            cx,
19605        )
19606    }
19607
19608    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19609        self.breadcrumb_header = Some(new_header);
19610    }
19611
19612    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19613        self.clear_background_highlights::<SearchWithinRange>(cx);
19614    }
19615
19616    pub fn highlight_background<T: 'static>(
19617        &mut self,
19618        ranges: &[Range<Anchor>],
19619        color_fetcher: fn(&Theme) -> Hsla,
19620        cx: &mut Context<Self>,
19621    ) {
19622        self.background_highlights.insert(
19623            HighlightKey::Type(TypeId::of::<T>()),
19624            (color_fetcher, Arc::from(ranges)),
19625        );
19626        self.scrollbar_marker_state.dirty = true;
19627        cx.notify();
19628    }
19629
19630    pub fn highlight_background_key<T: 'static>(
19631        &mut self,
19632        key: usize,
19633        ranges: &[Range<Anchor>],
19634        color_fetcher: fn(&Theme) -> Hsla,
19635        cx: &mut Context<Self>,
19636    ) {
19637        self.background_highlights.insert(
19638            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19639            (color_fetcher, Arc::from(ranges)),
19640        );
19641        self.scrollbar_marker_state.dirty = true;
19642        cx.notify();
19643    }
19644
19645    pub fn clear_background_highlights<T: 'static>(
19646        &mut self,
19647        cx: &mut Context<Self>,
19648    ) -> Option<BackgroundHighlight> {
19649        let text_highlights = self
19650            .background_highlights
19651            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19652        if !text_highlights.1.is_empty() {
19653            self.scrollbar_marker_state.dirty = true;
19654            cx.notify();
19655        }
19656        Some(text_highlights)
19657    }
19658
19659    pub fn highlight_gutter<T: 'static>(
19660        &mut self,
19661        ranges: impl Into<Vec<Range<Anchor>>>,
19662        color_fetcher: fn(&App) -> Hsla,
19663        cx: &mut Context<Self>,
19664    ) {
19665        self.gutter_highlights
19666            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19667        cx.notify();
19668    }
19669
19670    pub fn clear_gutter_highlights<T: 'static>(
19671        &mut self,
19672        cx: &mut Context<Self>,
19673    ) -> Option<GutterHighlight> {
19674        cx.notify();
19675        self.gutter_highlights.remove(&TypeId::of::<T>())
19676    }
19677
19678    pub fn insert_gutter_highlight<T: 'static>(
19679        &mut self,
19680        range: Range<Anchor>,
19681        color_fetcher: fn(&App) -> Hsla,
19682        cx: &mut Context<Self>,
19683    ) {
19684        let snapshot = self.buffer().read(cx).snapshot(cx);
19685        let mut highlights = self
19686            .gutter_highlights
19687            .remove(&TypeId::of::<T>())
19688            .map(|(_, highlights)| highlights)
19689            .unwrap_or_default();
19690        let ix = highlights.binary_search_by(|highlight| {
19691            Ordering::Equal
19692                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19693                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19694        });
19695        if let Err(ix) = ix {
19696            highlights.insert(ix, range);
19697        }
19698        self.gutter_highlights
19699            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19700    }
19701
19702    pub fn remove_gutter_highlights<T: 'static>(
19703        &mut self,
19704        ranges_to_remove: Vec<Range<Anchor>>,
19705        cx: &mut Context<Self>,
19706    ) {
19707        let snapshot = self.buffer().read(cx).snapshot(cx);
19708        let Some((color_fetcher, mut gutter_highlights)) =
19709            self.gutter_highlights.remove(&TypeId::of::<T>())
19710        else {
19711            return;
19712        };
19713        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19714        gutter_highlights.retain(|highlight| {
19715            while let Some(range_to_remove) = ranges_to_remove.peek() {
19716                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19717                    Ordering::Less | Ordering::Equal => {
19718                        ranges_to_remove.next();
19719                    }
19720                    Ordering::Greater => {
19721                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19722                            Ordering::Less | Ordering::Equal => {
19723                                return false;
19724                            }
19725                            Ordering::Greater => break,
19726                        }
19727                    }
19728                }
19729            }
19730
19731            true
19732        });
19733        self.gutter_highlights
19734            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19735    }
19736
19737    #[cfg(feature = "test-support")]
19738    pub fn all_text_highlights(
19739        &self,
19740        window: &mut Window,
19741        cx: &mut Context<Self>,
19742    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19743        let snapshot = self.snapshot(window, cx);
19744        self.display_map.update(cx, |display_map, _| {
19745            display_map
19746                .all_text_highlights()
19747                .map(|highlight| {
19748                    let (style, ranges) = highlight.as_ref();
19749                    (
19750                        *style,
19751                        ranges
19752                            .iter()
19753                            .map(|range| range.clone().to_display_points(&snapshot))
19754                            .collect(),
19755                    )
19756                })
19757                .collect()
19758        })
19759    }
19760
19761    #[cfg(feature = "test-support")]
19762    pub fn all_text_background_highlights(
19763        &self,
19764        window: &mut Window,
19765        cx: &mut Context<Self>,
19766    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19767        let snapshot = self.snapshot(window, cx);
19768        let buffer = &snapshot.buffer_snapshot;
19769        let start = buffer.anchor_before(0);
19770        let end = buffer.anchor_after(buffer.len());
19771        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19772    }
19773
19774    #[cfg(feature = "test-support")]
19775    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19776        let snapshot = self.buffer().read(cx).snapshot(cx);
19777
19778        let highlights = self
19779            .background_highlights
19780            .get(&HighlightKey::Type(TypeId::of::<
19781                items::BufferSearchHighlights,
19782            >()));
19783
19784        if let Some((_color, ranges)) = highlights {
19785            ranges
19786                .iter()
19787                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19788                .collect_vec()
19789        } else {
19790            vec![]
19791        }
19792    }
19793
19794    fn document_highlights_for_position<'a>(
19795        &'a self,
19796        position: Anchor,
19797        buffer: &'a MultiBufferSnapshot,
19798    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19799        let read_highlights = self
19800            .background_highlights
19801            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19802            .map(|h| &h.1);
19803        let write_highlights = self
19804            .background_highlights
19805            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19806            .map(|h| &h.1);
19807        let left_position = position.bias_left(buffer);
19808        let right_position = position.bias_right(buffer);
19809        read_highlights
19810            .into_iter()
19811            .chain(write_highlights)
19812            .flat_map(move |ranges| {
19813                let start_ix = match ranges.binary_search_by(|probe| {
19814                    let cmp = probe.end.cmp(&left_position, buffer);
19815                    if cmp.is_ge() {
19816                        Ordering::Greater
19817                    } else {
19818                        Ordering::Less
19819                    }
19820                }) {
19821                    Ok(i) | Err(i) => i,
19822                };
19823
19824                ranges[start_ix..]
19825                    .iter()
19826                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19827            })
19828    }
19829
19830    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19831        self.background_highlights
19832            .get(&HighlightKey::Type(TypeId::of::<T>()))
19833            .is_some_and(|(_, highlights)| !highlights.is_empty())
19834    }
19835
19836    pub fn background_highlights_in_range(
19837        &self,
19838        search_range: Range<Anchor>,
19839        display_snapshot: &DisplaySnapshot,
19840        theme: &Theme,
19841    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19842        let mut results = Vec::new();
19843        for (color_fetcher, ranges) in self.background_highlights.values() {
19844            let color = color_fetcher(theme);
19845            let start_ix = match ranges.binary_search_by(|probe| {
19846                let cmp = probe
19847                    .end
19848                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19849                if cmp.is_gt() {
19850                    Ordering::Greater
19851                } else {
19852                    Ordering::Less
19853                }
19854            }) {
19855                Ok(i) | Err(i) => i,
19856            };
19857            for range in &ranges[start_ix..] {
19858                if range
19859                    .start
19860                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19861                    .is_ge()
19862                {
19863                    break;
19864                }
19865
19866                let start = range.start.to_display_point(display_snapshot);
19867                let end = range.end.to_display_point(display_snapshot);
19868                results.push((start..end, color))
19869            }
19870        }
19871        results
19872    }
19873
19874    pub fn background_highlight_row_ranges<T: 'static>(
19875        &self,
19876        search_range: Range<Anchor>,
19877        display_snapshot: &DisplaySnapshot,
19878        count: usize,
19879    ) -> Vec<RangeInclusive<DisplayPoint>> {
19880        let mut results = Vec::new();
19881        let Some((_, ranges)) = self
19882            .background_highlights
19883            .get(&HighlightKey::Type(TypeId::of::<T>()))
19884        else {
19885            return vec![];
19886        };
19887
19888        let start_ix = match ranges.binary_search_by(|probe| {
19889            let cmp = probe
19890                .end
19891                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19892            if cmp.is_gt() {
19893                Ordering::Greater
19894            } else {
19895                Ordering::Less
19896            }
19897        }) {
19898            Ok(i) | Err(i) => i,
19899        };
19900        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19901            if let (Some(start_display), Some(end_display)) = (start, end) {
19902                results.push(
19903                    start_display.to_display_point(display_snapshot)
19904                        ..=end_display.to_display_point(display_snapshot),
19905                );
19906            }
19907        };
19908        let mut start_row: Option<Point> = None;
19909        let mut end_row: Option<Point> = None;
19910        if ranges.len() > count {
19911            return Vec::new();
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            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19922            if let Some(current_row) = &end_row
19923                && end.row == current_row.row
19924            {
19925                continue;
19926            }
19927            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19928            if start_row.is_none() {
19929                assert_eq!(end_row, None);
19930                start_row = Some(start);
19931                end_row = Some(end);
19932                continue;
19933            }
19934            if let Some(current_end) = end_row.as_mut() {
19935                if start.row > current_end.row + 1 {
19936                    push_region(start_row, end_row);
19937                    start_row = Some(start);
19938                    end_row = Some(end);
19939                } else {
19940                    // Merge two hunks.
19941                    *current_end = end;
19942                }
19943            } else {
19944                unreachable!();
19945            }
19946        }
19947        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19948        push_region(start_row, end_row);
19949        results
19950    }
19951
19952    pub fn gutter_highlights_in_range(
19953        &self,
19954        search_range: Range<Anchor>,
19955        display_snapshot: &DisplaySnapshot,
19956        cx: &App,
19957    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19958        let mut results = Vec::new();
19959        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19960            let color = color_fetcher(cx);
19961            let start_ix = match ranges.binary_search_by(|probe| {
19962                let cmp = probe
19963                    .end
19964                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19965                if cmp.is_gt() {
19966                    Ordering::Greater
19967                } else {
19968                    Ordering::Less
19969                }
19970            }) {
19971                Ok(i) | Err(i) => i,
19972            };
19973            for range in &ranges[start_ix..] {
19974                if range
19975                    .start
19976                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19977                    .is_ge()
19978                {
19979                    break;
19980                }
19981
19982                let start = range.start.to_display_point(display_snapshot);
19983                let end = range.end.to_display_point(display_snapshot);
19984                results.push((start..end, color))
19985            }
19986        }
19987        results
19988    }
19989
19990    /// Get the text ranges corresponding to the redaction query
19991    pub fn redacted_ranges(
19992        &self,
19993        search_range: Range<Anchor>,
19994        display_snapshot: &DisplaySnapshot,
19995        cx: &App,
19996    ) -> Vec<Range<DisplayPoint>> {
19997        display_snapshot
19998            .buffer_snapshot
19999            .redacted_ranges(search_range, |file| {
20000                if let Some(file) = file {
20001                    file.is_private()
20002                        && EditorSettings::get(
20003                            Some(SettingsLocation {
20004                                worktree_id: file.worktree_id(cx),
20005                                path: file.path().as_ref(),
20006                            }),
20007                            cx,
20008                        )
20009                        .redact_private_values
20010                } else {
20011                    false
20012                }
20013            })
20014            .map(|range| {
20015                range.start.to_display_point(display_snapshot)
20016                    ..range.end.to_display_point(display_snapshot)
20017            })
20018            .collect()
20019    }
20020
20021    pub fn highlight_text_key<T: 'static>(
20022        &mut self,
20023        key: usize,
20024        ranges: Vec<Range<Anchor>>,
20025        style: HighlightStyle,
20026        cx: &mut Context<Self>,
20027    ) {
20028        self.display_map.update(cx, |map, _| {
20029            map.highlight_text(
20030                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20031                ranges,
20032                style,
20033            );
20034        });
20035        cx.notify();
20036    }
20037
20038    pub fn highlight_text<T: 'static>(
20039        &mut self,
20040        ranges: Vec<Range<Anchor>>,
20041        style: HighlightStyle,
20042        cx: &mut Context<Self>,
20043    ) {
20044        self.display_map.update(cx, |map, _| {
20045            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20046        });
20047        cx.notify();
20048    }
20049
20050    pub(crate) fn highlight_inlays<T: 'static>(
20051        &mut self,
20052        highlights: Vec<InlayHighlight>,
20053        style: HighlightStyle,
20054        cx: &mut Context<Self>,
20055    ) {
20056        self.display_map.update(cx, |map, _| {
20057            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20058        });
20059        cx.notify();
20060    }
20061
20062    pub fn text_highlights<'a, T: 'static>(
20063        &'a self,
20064        cx: &'a App,
20065    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20066        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20067    }
20068
20069    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20070        let cleared = self
20071            .display_map
20072            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20073        if cleared {
20074            cx.notify();
20075        }
20076    }
20077
20078    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20079        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20080            && self.focus_handle.is_focused(window)
20081    }
20082
20083    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20084        self.show_cursor_when_unfocused = is_enabled;
20085        cx.notify();
20086    }
20087
20088    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20089        cx.notify();
20090    }
20091
20092    fn on_debug_session_event(
20093        &mut self,
20094        _session: Entity<Session>,
20095        event: &SessionEvent,
20096        cx: &mut Context<Self>,
20097    ) {
20098        if let SessionEvent::InvalidateInlineValue = event {
20099            self.refresh_inline_values(cx);
20100        }
20101    }
20102
20103    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20104        let Some(project) = self.project.clone() else {
20105            return;
20106        };
20107
20108        if !self.inline_value_cache.enabled {
20109            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20110            self.splice_inlays(&inlays, Vec::new(), cx);
20111            return;
20112        }
20113
20114        let current_execution_position = self
20115            .highlighted_rows
20116            .get(&TypeId::of::<ActiveDebugLine>())
20117            .and_then(|lines| lines.last().map(|line| line.range.end));
20118
20119        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20120            let inline_values = editor
20121                .update(cx, |editor, cx| {
20122                    let Some(current_execution_position) = current_execution_position else {
20123                        return Some(Task::ready(Ok(Vec::new())));
20124                    };
20125
20126                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20127                        let snapshot = buffer.snapshot(cx);
20128
20129                        let excerpt = snapshot.excerpt_containing(
20130                            current_execution_position..current_execution_position,
20131                        )?;
20132
20133                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20134                    })?;
20135
20136                    let range =
20137                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20138
20139                    project.inline_values(buffer, range, cx)
20140                })
20141                .ok()
20142                .flatten()?
20143                .await
20144                .context("refreshing debugger inlays")
20145                .log_err()?;
20146
20147            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20148
20149            for (buffer_id, inline_value) in inline_values
20150                .into_iter()
20151                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20152            {
20153                buffer_inline_values
20154                    .entry(buffer_id)
20155                    .or_default()
20156                    .push(inline_value);
20157            }
20158
20159            editor
20160                .update(cx, |editor, cx| {
20161                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20162                    let mut new_inlays = Vec::default();
20163
20164                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20165                        let buffer_id = buffer_snapshot.remote_id();
20166                        buffer_inline_values
20167                            .get(&buffer_id)
20168                            .into_iter()
20169                            .flatten()
20170                            .for_each(|hint| {
20171                                let inlay = Inlay::debugger(
20172                                    post_inc(&mut editor.next_inlay_id),
20173                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20174                                    hint.text(),
20175                                );
20176                                if !inlay.text.chars().contains(&'\n') {
20177                                    new_inlays.push(inlay);
20178                                }
20179                            });
20180                    }
20181
20182                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20183                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20184
20185                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20186                })
20187                .ok()?;
20188            Some(())
20189        });
20190    }
20191
20192    fn on_buffer_event(
20193        &mut self,
20194        multibuffer: &Entity<MultiBuffer>,
20195        event: &multi_buffer::Event,
20196        window: &mut Window,
20197        cx: &mut Context<Self>,
20198    ) {
20199        match event {
20200            multi_buffer::Event::Edited {
20201                singleton_buffer_edited,
20202                edited_buffer,
20203            } => {
20204                self.scrollbar_marker_state.dirty = true;
20205                self.active_indent_guides_state.dirty = true;
20206                self.refresh_active_diagnostics(cx);
20207                self.refresh_code_actions(window, cx);
20208                self.refresh_selected_text_highlights(true, window, cx);
20209                self.refresh_single_line_folds(window, cx);
20210                refresh_matching_bracket_highlights(self, window, cx);
20211                if self.has_active_edit_prediction() {
20212                    self.update_visible_edit_prediction(window, cx);
20213                }
20214                if let Some(project) = self.project.as_ref()
20215                    && let Some(edited_buffer) = edited_buffer
20216                {
20217                    project.update(cx, |project, cx| {
20218                        self.registered_buffers
20219                            .entry(edited_buffer.read(cx).remote_id())
20220                            .or_insert_with(|| {
20221                                project.register_buffer_with_language_servers(edited_buffer, cx)
20222                            });
20223                    });
20224                }
20225                cx.emit(EditorEvent::BufferEdited);
20226                cx.emit(SearchEvent::MatchesInvalidated);
20227
20228                if let Some(buffer) = edited_buffer {
20229                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20230                }
20231
20232                if *singleton_buffer_edited {
20233                    if let Some(buffer) = edited_buffer
20234                        && buffer.read(cx).file().is_none()
20235                    {
20236                        cx.emit(EditorEvent::TitleChanged);
20237                    }
20238                    if let Some(project) = &self.project {
20239                        #[allow(clippy::mutable_key_type)]
20240                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20241                            multibuffer
20242                                .all_buffers()
20243                                .into_iter()
20244                                .filter_map(|buffer| {
20245                                    buffer.update(cx, |buffer, cx| {
20246                                        let language = buffer.language()?;
20247                                        let should_discard = project.update(cx, |project, cx| {
20248                                            project.is_local()
20249                                                && !project.has_language_servers_for(buffer, cx)
20250                                        });
20251                                        should_discard.not().then_some(language.clone())
20252                                    })
20253                                })
20254                                .collect::<HashSet<_>>()
20255                        });
20256                        if !languages_affected.is_empty() {
20257                            self.refresh_inlay_hints(
20258                                InlayHintRefreshReason::BufferEdited(languages_affected),
20259                                cx,
20260                            );
20261                        }
20262                    }
20263                }
20264
20265                let Some(project) = &self.project else { return };
20266                let (telemetry, is_via_ssh) = {
20267                    let project = project.read(cx);
20268                    let telemetry = project.client().telemetry().clone();
20269                    let is_via_ssh = project.is_via_remote_server();
20270                    (telemetry, is_via_ssh)
20271                };
20272                refresh_linked_ranges(self, window, cx);
20273                telemetry.log_edit_event("editor", is_via_ssh);
20274            }
20275            multi_buffer::Event::ExcerptsAdded {
20276                buffer,
20277                predecessor,
20278                excerpts,
20279            } => {
20280                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20281                let buffer_id = buffer.read(cx).remote_id();
20282                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20283                    && let Some(project) = &self.project
20284                {
20285                    update_uncommitted_diff_for_buffer(
20286                        cx.entity(),
20287                        project,
20288                        [buffer.clone()],
20289                        self.buffer.clone(),
20290                        cx,
20291                    )
20292                    .detach();
20293                }
20294                self.update_lsp_data(false, Some(buffer_id), window, cx);
20295                cx.emit(EditorEvent::ExcerptsAdded {
20296                    buffer: buffer.clone(),
20297                    predecessor: *predecessor,
20298                    excerpts: excerpts.clone(),
20299                });
20300                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20301            }
20302            multi_buffer::Event::ExcerptsRemoved {
20303                ids,
20304                removed_buffer_ids,
20305            } => {
20306                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20307                let buffer = self.buffer.read(cx);
20308                self.registered_buffers
20309                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20310                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20311                cx.emit(EditorEvent::ExcerptsRemoved {
20312                    ids: ids.clone(),
20313                    removed_buffer_ids: removed_buffer_ids.clone(),
20314                });
20315            }
20316            multi_buffer::Event::ExcerptsEdited {
20317                excerpt_ids,
20318                buffer_ids,
20319            } => {
20320                self.display_map.update(cx, |map, cx| {
20321                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20322                });
20323                cx.emit(EditorEvent::ExcerptsEdited {
20324                    ids: excerpt_ids.clone(),
20325                });
20326            }
20327            multi_buffer::Event::ExcerptsExpanded { ids } => {
20328                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20329                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20330            }
20331            multi_buffer::Event::Reparsed(buffer_id) => {
20332                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20333                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20334
20335                cx.emit(EditorEvent::Reparsed(*buffer_id));
20336            }
20337            multi_buffer::Event::DiffHunksToggled => {
20338                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20339            }
20340            multi_buffer::Event::LanguageChanged(buffer_id) => {
20341                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20342                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20343                cx.emit(EditorEvent::Reparsed(*buffer_id));
20344                cx.notify();
20345            }
20346            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20347            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20348            multi_buffer::Event::FileHandleChanged
20349            | multi_buffer::Event::Reloaded
20350            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20351            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20352            multi_buffer::Event::DiagnosticsUpdated => {
20353                self.update_diagnostics_state(window, cx);
20354            }
20355            _ => {}
20356        };
20357    }
20358
20359    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20360        if !self.diagnostics_enabled() {
20361            return;
20362        }
20363        self.refresh_active_diagnostics(cx);
20364        self.refresh_inline_diagnostics(true, window, cx);
20365        self.scrollbar_marker_state.dirty = true;
20366        cx.notify();
20367    }
20368
20369    pub fn start_temporary_diff_override(&mut self) {
20370        self.load_diff_task.take();
20371        self.temporary_diff_override = true;
20372    }
20373
20374    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20375        self.temporary_diff_override = false;
20376        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20377        self.buffer.update(cx, |buffer, cx| {
20378            buffer.set_all_diff_hunks_collapsed(cx);
20379        });
20380
20381        if let Some(project) = self.project.clone() {
20382            self.load_diff_task = Some(
20383                update_uncommitted_diff_for_buffer(
20384                    cx.entity(),
20385                    &project,
20386                    self.buffer.read(cx).all_buffers(),
20387                    self.buffer.clone(),
20388                    cx,
20389                )
20390                .shared(),
20391            );
20392        }
20393    }
20394
20395    fn on_display_map_changed(
20396        &mut self,
20397        _: Entity<DisplayMap>,
20398        _: &mut Window,
20399        cx: &mut Context<Self>,
20400    ) {
20401        cx.notify();
20402    }
20403
20404    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20405        if self.diagnostics_enabled() {
20406            let new_severity = EditorSettings::get_global(cx)
20407                .diagnostics_max_severity
20408                .unwrap_or(DiagnosticSeverity::Hint);
20409            self.set_max_diagnostics_severity(new_severity, cx);
20410        }
20411        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20412        self.update_edit_prediction_settings(cx);
20413        self.refresh_edit_prediction(true, false, window, cx);
20414        self.refresh_inline_values(cx);
20415        self.refresh_inlay_hints(
20416            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20417                self.selections.newest_anchor().head(),
20418                &self.buffer.read(cx).snapshot(cx),
20419                cx,
20420            )),
20421            cx,
20422        );
20423
20424        let old_cursor_shape = self.cursor_shape;
20425        let old_show_breadcrumbs = self.show_breadcrumbs;
20426
20427        {
20428            let editor_settings = EditorSettings::get_global(cx);
20429            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20430            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20431            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20432            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20433        }
20434
20435        if old_cursor_shape != self.cursor_shape {
20436            cx.emit(EditorEvent::CursorShapeChanged);
20437        }
20438
20439        if old_show_breadcrumbs != self.show_breadcrumbs {
20440            cx.emit(EditorEvent::BreadcrumbsChanged);
20441        }
20442
20443        let project_settings = ProjectSettings::get_global(cx);
20444        self.serialize_dirty_buffers =
20445            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20446
20447        if self.mode.is_full() {
20448            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20449            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20450            if self.show_inline_diagnostics != show_inline_diagnostics {
20451                self.show_inline_diagnostics = show_inline_diagnostics;
20452                self.refresh_inline_diagnostics(false, window, cx);
20453            }
20454
20455            if self.git_blame_inline_enabled != inline_blame_enabled {
20456                self.toggle_git_blame_inline_internal(false, window, cx);
20457            }
20458
20459            let minimap_settings = EditorSettings::get_global(cx).minimap;
20460            if self.minimap_visibility != MinimapVisibility::Disabled {
20461                if self.minimap_visibility.settings_visibility()
20462                    != minimap_settings.minimap_enabled()
20463                {
20464                    self.set_minimap_visibility(
20465                        MinimapVisibility::for_mode(self.mode(), cx),
20466                        window,
20467                        cx,
20468                    );
20469                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20470                    minimap_entity.update(cx, |minimap_editor, cx| {
20471                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20472                    })
20473                }
20474            }
20475        }
20476
20477        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20478            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20479        }) {
20480            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20481                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20482            }
20483            self.refresh_colors(false, None, window, cx);
20484        }
20485
20486        cx.notify();
20487    }
20488
20489    pub fn set_searchable(&mut self, searchable: bool) {
20490        self.searchable = searchable;
20491    }
20492
20493    pub fn searchable(&self) -> bool {
20494        self.searchable
20495    }
20496
20497    fn open_proposed_changes_editor(
20498        &mut self,
20499        _: &OpenProposedChangesEditor,
20500        window: &mut Window,
20501        cx: &mut Context<Self>,
20502    ) {
20503        let Some(workspace) = self.workspace() else {
20504            cx.propagate();
20505            return;
20506        };
20507
20508        let selections = self.selections.all::<usize>(cx);
20509        let multi_buffer = self.buffer.read(cx);
20510        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20511        let mut new_selections_by_buffer = HashMap::default();
20512        for selection in selections {
20513            for (buffer, range, _) in
20514                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20515            {
20516                let mut range = range.to_point(buffer);
20517                range.start.column = 0;
20518                range.end.column = buffer.line_len(range.end.row);
20519                new_selections_by_buffer
20520                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20521                    .or_insert(Vec::new())
20522                    .push(range)
20523            }
20524        }
20525
20526        let proposed_changes_buffers = new_selections_by_buffer
20527            .into_iter()
20528            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20529            .collect::<Vec<_>>();
20530        let proposed_changes_editor = cx.new(|cx| {
20531            ProposedChangesEditor::new(
20532                "Proposed changes",
20533                proposed_changes_buffers,
20534                self.project.clone(),
20535                window,
20536                cx,
20537            )
20538        });
20539
20540        window.defer(cx, move |window, cx| {
20541            workspace.update(cx, |workspace, cx| {
20542                workspace.active_pane().update(cx, |pane, cx| {
20543                    pane.add_item(
20544                        Box::new(proposed_changes_editor),
20545                        true,
20546                        true,
20547                        None,
20548                        window,
20549                        cx,
20550                    );
20551                });
20552            });
20553        });
20554    }
20555
20556    pub fn open_excerpts_in_split(
20557        &mut self,
20558        _: &OpenExcerptsSplit,
20559        window: &mut Window,
20560        cx: &mut Context<Self>,
20561    ) {
20562        self.open_excerpts_common(None, true, window, cx)
20563    }
20564
20565    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20566        self.open_excerpts_common(None, false, window, cx)
20567    }
20568
20569    fn open_excerpts_common(
20570        &mut self,
20571        jump_data: Option<JumpData>,
20572        split: bool,
20573        window: &mut Window,
20574        cx: &mut Context<Self>,
20575    ) {
20576        let Some(workspace) = self.workspace() else {
20577            cx.propagate();
20578            return;
20579        };
20580
20581        if self.buffer.read(cx).is_singleton() {
20582            cx.propagate();
20583            return;
20584        }
20585
20586        let mut new_selections_by_buffer = HashMap::default();
20587        match &jump_data {
20588            Some(JumpData::MultiBufferPoint {
20589                excerpt_id,
20590                position,
20591                anchor,
20592                line_offset_from_top,
20593            }) => {
20594                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20595                if let Some(buffer) = multi_buffer_snapshot
20596                    .buffer_id_for_excerpt(*excerpt_id)
20597                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20598                {
20599                    let buffer_snapshot = buffer.read(cx).snapshot();
20600                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20601                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20602                    } else {
20603                        buffer_snapshot.clip_point(*position, Bias::Left)
20604                    };
20605                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20606                    new_selections_by_buffer.insert(
20607                        buffer,
20608                        (
20609                            vec![jump_to_offset..jump_to_offset],
20610                            Some(*line_offset_from_top),
20611                        ),
20612                    );
20613                }
20614            }
20615            Some(JumpData::MultiBufferRow {
20616                row,
20617                line_offset_from_top,
20618            }) => {
20619                let point = MultiBufferPoint::new(row.0, 0);
20620                if let Some((buffer, buffer_point, _)) =
20621                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20622                {
20623                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20624                    new_selections_by_buffer
20625                        .entry(buffer)
20626                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20627                        .0
20628                        .push(buffer_offset..buffer_offset)
20629                }
20630            }
20631            None => {
20632                let selections = self.selections.all::<usize>(cx);
20633                let multi_buffer = self.buffer.read(cx);
20634                for selection in selections {
20635                    for (snapshot, range, _, anchor) in multi_buffer
20636                        .snapshot(cx)
20637                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20638                    {
20639                        if let Some(anchor) = anchor {
20640                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20641                            else {
20642                                continue;
20643                            };
20644                            let offset = text::ToOffset::to_offset(
20645                                &anchor.text_anchor,
20646                                &buffer_handle.read(cx).snapshot(),
20647                            );
20648                            let range = offset..offset;
20649                            new_selections_by_buffer
20650                                .entry(buffer_handle)
20651                                .or_insert((Vec::new(), None))
20652                                .0
20653                                .push(range)
20654                        } else {
20655                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20656                            else {
20657                                continue;
20658                            };
20659                            new_selections_by_buffer
20660                                .entry(buffer_handle)
20661                                .or_insert((Vec::new(), None))
20662                                .0
20663                                .push(range)
20664                        }
20665                    }
20666                }
20667            }
20668        }
20669
20670        new_selections_by_buffer
20671            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20672
20673        if new_selections_by_buffer.is_empty() {
20674            return;
20675        }
20676
20677        // We defer the pane interaction because we ourselves are a workspace item
20678        // and activating a new item causes the pane to call a method on us reentrantly,
20679        // which panics if we're on the stack.
20680        window.defer(cx, move |window, cx| {
20681            workspace.update(cx, |workspace, cx| {
20682                let pane = if split {
20683                    workspace.adjacent_pane(window, cx)
20684                } else {
20685                    workspace.active_pane().clone()
20686                };
20687
20688                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20689                    let editor = buffer
20690                        .read(cx)
20691                        .file()
20692                        .is_none()
20693                        .then(|| {
20694                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20695                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20696                            // Instead, we try to activate the existing editor in the pane first.
20697                            let (editor, pane_item_index) =
20698                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20699                                    let editor = item.downcast::<Editor>()?;
20700                                    let singleton_buffer =
20701                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20702                                    if singleton_buffer == buffer {
20703                                        Some((editor, i))
20704                                    } else {
20705                                        None
20706                                    }
20707                                })?;
20708                            pane.update(cx, |pane, cx| {
20709                                pane.activate_item(pane_item_index, true, true, window, cx)
20710                            });
20711                            Some(editor)
20712                        })
20713                        .flatten()
20714                        .unwrap_or_else(|| {
20715                            workspace.open_project_item::<Self>(
20716                                pane.clone(),
20717                                buffer,
20718                                true,
20719                                true,
20720                                window,
20721                                cx,
20722                            )
20723                        });
20724
20725                    editor.update(cx, |editor, cx| {
20726                        let autoscroll = match scroll_offset {
20727                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20728                            None => Autoscroll::newest(),
20729                        };
20730                        let nav_history = editor.nav_history.take();
20731                        editor.change_selections(
20732                            SelectionEffects::scroll(autoscroll),
20733                            window,
20734                            cx,
20735                            |s| {
20736                                s.select_ranges(ranges);
20737                            },
20738                        );
20739                        editor.nav_history = nav_history;
20740                    });
20741                }
20742            })
20743        });
20744    }
20745
20746    // For now, don't allow opening excerpts in buffers that aren't backed by
20747    // regular project files.
20748    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20749        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20750    }
20751
20752    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20753        let snapshot = self.buffer.read(cx).read(cx);
20754        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20755        Some(
20756            ranges
20757                .iter()
20758                .map(move |range| {
20759                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20760                })
20761                .collect(),
20762        )
20763    }
20764
20765    fn selection_replacement_ranges(
20766        &self,
20767        range: Range<OffsetUtf16>,
20768        cx: &mut App,
20769    ) -> Vec<Range<OffsetUtf16>> {
20770        let selections = self.selections.all::<OffsetUtf16>(cx);
20771        let newest_selection = selections
20772            .iter()
20773            .max_by_key(|selection| selection.id)
20774            .unwrap();
20775        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20776        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20777        let snapshot = self.buffer.read(cx).read(cx);
20778        selections
20779            .into_iter()
20780            .map(|mut selection| {
20781                selection.start.0 =
20782                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20783                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20784                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20785                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20786            })
20787            .collect()
20788    }
20789
20790    fn report_editor_event(
20791        &self,
20792        reported_event: ReportEditorEvent,
20793        file_extension: Option<String>,
20794        cx: &App,
20795    ) {
20796        if cfg!(any(test, feature = "test-support")) {
20797            return;
20798        }
20799
20800        let Some(project) = &self.project else { return };
20801
20802        // If None, we are in a file without an extension
20803        let file = self
20804            .buffer
20805            .read(cx)
20806            .as_singleton()
20807            .and_then(|b| b.read(cx).file());
20808        let file_extension = file_extension.or(file
20809            .as_ref()
20810            .and_then(|file| Path::new(file.file_name(cx)).extension())
20811            .and_then(|e| e.to_str())
20812            .map(|a| a.to_string()));
20813
20814        let vim_mode = vim_enabled(cx);
20815
20816        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20817        let copilot_enabled = edit_predictions_provider
20818            == language::language_settings::EditPredictionProvider::Copilot;
20819        let copilot_enabled_for_language = self
20820            .buffer
20821            .read(cx)
20822            .language_settings(cx)
20823            .show_edit_predictions;
20824
20825        let project = project.read(cx);
20826        let event_type = reported_event.event_type();
20827
20828        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20829            telemetry::event!(
20830                event_type,
20831                type = if auto_saved {"autosave"} else {"manual"},
20832                file_extension,
20833                vim_mode,
20834                copilot_enabled,
20835                copilot_enabled_for_language,
20836                edit_predictions_provider,
20837                is_via_ssh = project.is_via_remote_server(),
20838            );
20839        } else {
20840            telemetry::event!(
20841                event_type,
20842                file_extension,
20843                vim_mode,
20844                copilot_enabled,
20845                copilot_enabled_for_language,
20846                edit_predictions_provider,
20847                is_via_ssh = project.is_via_remote_server(),
20848            );
20849        };
20850    }
20851
20852    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20853    /// with each line being an array of {text, highlight} objects.
20854    fn copy_highlight_json(
20855        &mut self,
20856        _: &CopyHighlightJson,
20857        window: &mut Window,
20858        cx: &mut Context<Self>,
20859    ) {
20860        #[derive(Serialize)]
20861        struct Chunk<'a> {
20862            text: String,
20863            highlight: Option<&'a str>,
20864        }
20865
20866        let snapshot = self.buffer.read(cx).snapshot(cx);
20867        let range = self
20868            .selected_text_range(false, window, cx)
20869            .and_then(|selection| {
20870                if selection.range.is_empty() {
20871                    None
20872                } else {
20873                    Some(selection.range)
20874                }
20875            })
20876            .unwrap_or_else(|| 0..snapshot.len());
20877
20878        let chunks = snapshot.chunks(range, true);
20879        let mut lines = Vec::new();
20880        let mut line: VecDeque<Chunk> = VecDeque::new();
20881
20882        let Some(style) = self.style.as_ref() else {
20883            return;
20884        };
20885
20886        for chunk in chunks {
20887            let highlight = chunk
20888                .syntax_highlight_id
20889                .and_then(|id| id.name(&style.syntax));
20890            let mut chunk_lines = chunk.text.split('\n').peekable();
20891            while let Some(text) = chunk_lines.next() {
20892                let mut merged_with_last_token = false;
20893                if let Some(last_token) = line.back_mut()
20894                    && last_token.highlight == highlight
20895                {
20896                    last_token.text.push_str(text);
20897                    merged_with_last_token = true;
20898                }
20899
20900                if !merged_with_last_token {
20901                    line.push_back(Chunk {
20902                        text: text.into(),
20903                        highlight,
20904                    });
20905                }
20906
20907                if chunk_lines.peek().is_some() {
20908                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20909                        line.pop_front();
20910                    }
20911                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20912                        line.pop_back();
20913                    }
20914
20915                    lines.push(mem::take(&mut line));
20916                }
20917            }
20918        }
20919
20920        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20921            return;
20922        };
20923        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20924    }
20925
20926    pub fn open_context_menu(
20927        &mut self,
20928        _: &OpenContextMenu,
20929        window: &mut Window,
20930        cx: &mut Context<Self>,
20931    ) {
20932        self.request_autoscroll(Autoscroll::newest(), cx);
20933        let position = self.selections.newest_display(cx).start;
20934        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20935    }
20936
20937    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20938        &self.inlay_hint_cache
20939    }
20940
20941    pub fn replay_insert_event(
20942        &mut self,
20943        text: &str,
20944        relative_utf16_range: Option<Range<isize>>,
20945        window: &mut Window,
20946        cx: &mut Context<Self>,
20947    ) {
20948        if !self.input_enabled {
20949            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20950            return;
20951        }
20952        if let Some(relative_utf16_range) = relative_utf16_range {
20953            let selections = self.selections.all::<OffsetUtf16>(cx);
20954            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20955                let new_ranges = selections.into_iter().map(|range| {
20956                    let start = OffsetUtf16(
20957                        range
20958                            .head()
20959                            .0
20960                            .saturating_add_signed(relative_utf16_range.start),
20961                    );
20962                    let end = OffsetUtf16(
20963                        range
20964                            .head()
20965                            .0
20966                            .saturating_add_signed(relative_utf16_range.end),
20967                    );
20968                    start..end
20969                });
20970                s.select_ranges(new_ranges);
20971            });
20972        }
20973
20974        self.handle_input(text, window, cx);
20975    }
20976
20977    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20978        let Some(provider) = self.semantics_provider.as_ref() else {
20979            return false;
20980        };
20981
20982        let mut supports = false;
20983        self.buffer().update(cx, |this, cx| {
20984            this.for_each_buffer(|buffer| {
20985                supports |= provider.supports_inlay_hints(buffer, cx);
20986            });
20987        });
20988
20989        supports
20990    }
20991
20992    pub fn is_focused(&self, window: &Window) -> bool {
20993        self.focus_handle.is_focused(window)
20994    }
20995
20996    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20997        cx.emit(EditorEvent::Focused);
20998
20999        if let Some(descendant) = self
21000            .last_focused_descendant
21001            .take()
21002            .and_then(|descendant| descendant.upgrade())
21003        {
21004            window.focus(&descendant);
21005        } else {
21006            if let Some(blame) = self.blame.as_ref() {
21007                blame.update(cx, GitBlame::focus)
21008            }
21009
21010            self.blink_manager.update(cx, BlinkManager::enable);
21011            self.show_cursor_names(window, cx);
21012            self.buffer.update(cx, |buffer, cx| {
21013                buffer.finalize_last_transaction(cx);
21014                if self.leader_id.is_none() {
21015                    buffer.set_active_selections(
21016                        &self.selections.disjoint_anchors(),
21017                        self.selections.line_mode,
21018                        self.cursor_shape,
21019                        cx,
21020                    );
21021                }
21022            });
21023        }
21024    }
21025
21026    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21027        cx.emit(EditorEvent::FocusedIn)
21028    }
21029
21030    fn handle_focus_out(
21031        &mut self,
21032        event: FocusOutEvent,
21033        _window: &mut Window,
21034        cx: &mut Context<Self>,
21035    ) {
21036        if event.blurred != self.focus_handle {
21037            self.last_focused_descendant = Some(event.blurred);
21038        }
21039        self.selection_drag_state = SelectionDragState::None;
21040        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21041    }
21042
21043    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21044        self.blink_manager.update(cx, BlinkManager::disable);
21045        self.buffer
21046            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21047
21048        if let Some(blame) = self.blame.as_ref() {
21049            blame.update(cx, GitBlame::blur)
21050        }
21051        if !self.hover_state.focused(window, cx) {
21052            hide_hover(self, cx);
21053        }
21054        if !self
21055            .context_menu
21056            .borrow()
21057            .as_ref()
21058            .is_some_and(|context_menu| context_menu.focused(window, cx))
21059        {
21060            self.hide_context_menu(window, cx);
21061        }
21062        self.discard_edit_prediction(false, cx);
21063        cx.emit(EditorEvent::Blurred);
21064        cx.notify();
21065    }
21066
21067    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21068        let mut pending: String = window
21069            .pending_input_keystrokes()
21070            .into_iter()
21071            .flatten()
21072            .filter_map(|keystroke| {
21073                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21074                    keystroke.key_char.clone()
21075                } else {
21076                    None
21077                }
21078            })
21079            .collect();
21080
21081        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21082            pending = "".to_string();
21083        }
21084
21085        let existing_pending = self
21086            .text_highlights::<PendingInput>(cx)
21087            .map(|(_, ranges)| ranges.to_vec());
21088        if existing_pending.is_none() && pending.is_empty() {
21089            return;
21090        }
21091        let transaction =
21092            self.transact(window, cx, |this, window, cx| {
21093                let selections = this.selections.all::<usize>(cx);
21094                let edits = selections
21095                    .iter()
21096                    .map(|selection| (selection.end..selection.end, pending.clone()));
21097                this.edit(edits, cx);
21098                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21099                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21100                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21101                    }));
21102                });
21103                if let Some(existing_ranges) = existing_pending {
21104                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21105                    this.edit(edits, cx);
21106                }
21107            });
21108
21109        let snapshot = self.snapshot(window, cx);
21110        let ranges = self
21111            .selections
21112            .all::<usize>(cx)
21113            .into_iter()
21114            .map(|selection| {
21115                snapshot.buffer_snapshot.anchor_after(selection.end)
21116                    ..snapshot
21117                        .buffer_snapshot
21118                        .anchor_before(selection.end + pending.len())
21119            })
21120            .collect();
21121
21122        if pending.is_empty() {
21123            self.clear_highlights::<PendingInput>(cx);
21124        } else {
21125            self.highlight_text::<PendingInput>(
21126                ranges,
21127                HighlightStyle {
21128                    underline: Some(UnderlineStyle {
21129                        thickness: px(1.),
21130                        color: None,
21131                        wavy: false,
21132                    }),
21133                    ..Default::default()
21134                },
21135                cx,
21136            );
21137        }
21138
21139        self.ime_transaction = self.ime_transaction.or(transaction);
21140        if let Some(transaction) = self.ime_transaction {
21141            self.buffer.update(cx, |buffer, cx| {
21142                buffer.group_until_transaction(transaction, cx);
21143            });
21144        }
21145
21146        if self.text_highlights::<PendingInput>(cx).is_none() {
21147            self.ime_transaction.take();
21148        }
21149    }
21150
21151    pub fn register_action_renderer(
21152        &mut self,
21153        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21154    ) -> Subscription {
21155        let id = self.next_editor_action_id.post_inc();
21156        self.editor_actions
21157            .borrow_mut()
21158            .insert(id, Box::new(listener));
21159
21160        let editor_actions = self.editor_actions.clone();
21161        Subscription::new(move || {
21162            editor_actions.borrow_mut().remove(&id);
21163        })
21164    }
21165
21166    pub fn register_action<A: Action>(
21167        &mut self,
21168        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21169    ) -> Subscription {
21170        let id = self.next_editor_action_id.post_inc();
21171        let listener = Arc::new(listener);
21172        self.editor_actions.borrow_mut().insert(
21173            id,
21174            Box::new(move |_, window, _| {
21175                let listener = listener.clone();
21176                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21177                    let action = action.downcast_ref().unwrap();
21178                    if phase == DispatchPhase::Bubble {
21179                        listener(action, window, cx)
21180                    }
21181                })
21182            }),
21183        );
21184
21185        let editor_actions = self.editor_actions.clone();
21186        Subscription::new(move || {
21187            editor_actions.borrow_mut().remove(&id);
21188        })
21189    }
21190
21191    pub fn file_header_size(&self) -> u32 {
21192        FILE_HEADER_HEIGHT
21193    }
21194
21195    pub fn restore(
21196        &mut self,
21197        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21198        window: &mut Window,
21199        cx: &mut Context<Self>,
21200    ) {
21201        let workspace = self.workspace();
21202        let project = self.project();
21203        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21204            let mut tasks = Vec::new();
21205            for (buffer_id, changes) in revert_changes {
21206                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21207                    buffer.update(cx, |buffer, cx| {
21208                        buffer.edit(
21209                            changes
21210                                .into_iter()
21211                                .map(|(range, text)| (range, text.to_string())),
21212                            None,
21213                            cx,
21214                        );
21215                    });
21216
21217                    if let Some(project) =
21218                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21219                    {
21220                        project.update(cx, |project, cx| {
21221                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21222                        })
21223                    }
21224                }
21225            }
21226            tasks
21227        });
21228        cx.spawn_in(window, async move |_, cx| {
21229            for (buffer, task) in save_tasks {
21230                let result = task.await;
21231                if result.is_err() {
21232                    let Some(path) = buffer
21233                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21234                        .ok()
21235                    else {
21236                        continue;
21237                    };
21238                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21239                        let Some(task) = cx
21240                            .update_window_entity(workspace, |workspace, window, cx| {
21241                                workspace
21242                                    .open_path_preview(path, None, false, false, false, window, cx)
21243                            })
21244                            .ok()
21245                        else {
21246                            continue;
21247                        };
21248                        task.await.log_err();
21249                    }
21250                }
21251            }
21252        })
21253        .detach();
21254        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21255            selections.refresh()
21256        });
21257    }
21258
21259    pub fn to_pixel_point(
21260        &self,
21261        source: multi_buffer::Anchor,
21262        editor_snapshot: &EditorSnapshot,
21263        window: &mut Window,
21264    ) -> Option<gpui::Point<Pixels>> {
21265        let source_point = source.to_display_point(editor_snapshot);
21266        self.display_to_pixel_point(source_point, editor_snapshot, window)
21267    }
21268
21269    pub fn display_to_pixel_point(
21270        &self,
21271        source: DisplayPoint,
21272        editor_snapshot: &EditorSnapshot,
21273        window: &mut Window,
21274    ) -> Option<gpui::Point<Pixels>> {
21275        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21276        let text_layout_details = self.text_layout_details(window);
21277        let scroll_top = text_layout_details
21278            .scroll_anchor
21279            .scroll_position(editor_snapshot)
21280            .y;
21281
21282        if source.row().as_f32() < scroll_top.floor() {
21283            return None;
21284        }
21285        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21286        let source_y = line_height * (source.row().as_f32() - scroll_top);
21287        Some(gpui::Point::new(source_x, source_y))
21288    }
21289
21290    pub fn has_visible_completions_menu(&self) -> bool {
21291        !self.edit_prediction_preview_is_active()
21292            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21293                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21294            })
21295    }
21296
21297    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21298        if self.mode.is_minimap() {
21299            return;
21300        }
21301        self.addons
21302            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21303    }
21304
21305    pub fn unregister_addon<T: Addon>(&mut self) {
21306        self.addons.remove(&std::any::TypeId::of::<T>());
21307    }
21308
21309    pub fn addon<T: Addon>(&self) -> Option<&T> {
21310        let type_id = std::any::TypeId::of::<T>();
21311        self.addons
21312            .get(&type_id)
21313            .and_then(|item| item.to_any().downcast_ref::<T>())
21314    }
21315
21316    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21317        let type_id = std::any::TypeId::of::<T>();
21318        self.addons
21319            .get_mut(&type_id)
21320            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21321    }
21322
21323    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21324        let text_layout_details = self.text_layout_details(window);
21325        let style = &text_layout_details.editor_style;
21326        let font_id = window.text_system().resolve_font(&style.text.font());
21327        let font_size = style.text.font_size.to_pixels(window.rem_size());
21328        let line_height = style.text.line_height_in_pixels(window.rem_size());
21329        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21330        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21331
21332        CharacterDimensions {
21333            em_width,
21334            em_advance,
21335            line_height,
21336        }
21337    }
21338
21339    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21340        self.load_diff_task.clone()
21341    }
21342
21343    fn read_metadata_from_db(
21344        &mut self,
21345        item_id: u64,
21346        workspace_id: WorkspaceId,
21347        window: &mut Window,
21348        cx: &mut Context<Editor>,
21349    ) {
21350        if self.is_singleton(cx)
21351            && !self.mode.is_minimap()
21352            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21353        {
21354            let buffer_snapshot = OnceCell::new();
21355
21356            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21357                && !folds.is_empty()
21358            {
21359                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21360                self.fold_ranges(
21361                    folds
21362                        .into_iter()
21363                        .map(|(start, end)| {
21364                            snapshot.clip_offset(start, Bias::Left)
21365                                ..snapshot.clip_offset(end, Bias::Right)
21366                        })
21367                        .collect(),
21368                    false,
21369                    window,
21370                    cx,
21371                );
21372            }
21373
21374            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21375                && !selections.is_empty()
21376            {
21377                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21378                // skip adding the initial selection to selection history
21379                self.selection_history.mode = SelectionHistoryMode::Skipping;
21380                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21381                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21382                        snapshot.clip_offset(start, Bias::Left)
21383                            ..snapshot.clip_offset(end, Bias::Right)
21384                    }));
21385                });
21386                self.selection_history.mode = SelectionHistoryMode::Normal;
21387            };
21388        }
21389
21390        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21391    }
21392
21393    fn update_lsp_data(
21394        &mut self,
21395        ignore_cache: bool,
21396        for_buffer: Option<BufferId>,
21397        window: &mut Window,
21398        cx: &mut Context<'_, Self>,
21399    ) {
21400        self.pull_diagnostics(for_buffer, window, cx);
21401        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21402    }
21403}
21404
21405fn vim_enabled(cx: &App) -> bool {
21406    cx.global::<SettingsStore>()
21407        .raw_user_settings()
21408        .get("vim_mode")
21409        == Some(&serde_json::Value::Bool(true))
21410}
21411
21412fn process_completion_for_edit(
21413    completion: &Completion,
21414    intent: CompletionIntent,
21415    buffer: &Entity<Buffer>,
21416    cursor_position: &text::Anchor,
21417    cx: &mut Context<Editor>,
21418) -> CompletionEdit {
21419    let buffer = buffer.read(cx);
21420    let buffer_snapshot = buffer.snapshot();
21421    let (snippet, new_text) = if completion.is_snippet() {
21422        // Workaround for typescript language server issues so that methods don't expand within
21423        // strings and functions with type expressions. The previous point is used because the query
21424        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21425        let mut snippet_source = completion.new_text.clone();
21426        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21427        previous_point.column = previous_point.column.saturating_sub(1);
21428        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21429            && scope.prefers_label_for_snippet_in_completion()
21430            && let Some(label) = completion.label()
21431            && matches!(
21432                completion.kind(),
21433                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21434            )
21435        {
21436            snippet_source = label;
21437        }
21438        match Snippet::parse(&snippet_source).log_err() {
21439            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21440            None => (None, completion.new_text.clone()),
21441        }
21442    } else {
21443        (None, completion.new_text.clone())
21444    };
21445
21446    let mut range_to_replace = {
21447        let replace_range = &completion.replace_range;
21448        if let CompletionSource::Lsp {
21449            insert_range: Some(insert_range),
21450            ..
21451        } = &completion.source
21452        {
21453            debug_assert_eq!(
21454                insert_range.start, replace_range.start,
21455                "insert_range and replace_range should start at the same position"
21456            );
21457            debug_assert!(
21458                insert_range
21459                    .start
21460                    .cmp(cursor_position, &buffer_snapshot)
21461                    .is_le(),
21462                "insert_range should start before or at cursor position"
21463            );
21464            debug_assert!(
21465                replace_range
21466                    .start
21467                    .cmp(cursor_position, &buffer_snapshot)
21468                    .is_le(),
21469                "replace_range should start before or at cursor position"
21470            );
21471
21472            let should_replace = match intent {
21473                CompletionIntent::CompleteWithInsert => false,
21474                CompletionIntent::CompleteWithReplace => true,
21475                CompletionIntent::Complete | CompletionIntent::Compose => {
21476                    let insert_mode =
21477                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21478                            .completions
21479                            .lsp_insert_mode;
21480                    match insert_mode {
21481                        LspInsertMode::Insert => false,
21482                        LspInsertMode::Replace => true,
21483                        LspInsertMode::ReplaceSubsequence => {
21484                            let mut text_to_replace = buffer.chars_for_range(
21485                                buffer.anchor_before(replace_range.start)
21486                                    ..buffer.anchor_after(replace_range.end),
21487                            );
21488                            let mut current_needle = text_to_replace.next();
21489                            for haystack_ch in completion.label.text.chars() {
21490                                if let Some(needle_ch) = current_needle
21491                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21492                                {
21493                                    current_needle = text_to_replace.next();
21494                                }
21495                            }
21496                            current_needle.is_none()
21497                        }
21498                        LspInsertMode::ReplaceSuffix => {
21499                            if replace_range
21500                                .end
21501                                .cmp(cursor_position, &buffer_snapshot)
21502                                .is_gt()
21503                            {
21504                                let range_after_cursor = *cursor_position..replace_range.end;
21505                                let text_after_cursor = buffer
21506                                    .text_for_range(
21507                                        buffer.anchor_before(range_after_cursor.start)
21508                                            ..buffer.anchor_after(range_after_cursor.end),
21509                                    )
21510                                    .collect::<String>()
21511                                    .to_ascii_lowercase();
21512                                completion
21513                                    .label
21514                                    .text
21515                                    .to_ascii_lowercase()
21516                                    .ends_with(&text_after_cursor)
21517                            } else {
21518                                true
21519                            }
21520                        }
21521                    }
21522                }
21523            };
21524
21525            if should_replace {
21526                replace_range.clone()
21527            } else {
21528                insert_range.clone()
21529            }
21530        } else {
21531            replace_range.clone()
21532        }
21533    };
21534
21535    if range_to_replace
21536        .end
21537        .cmp(cursor_position, &buffer_snapshot)
21538        .is_lt()
21539    {
21540        range_to_replace.end = *cursor_position;
21541    }
21542
21543    CompletionEdit {
21544        new_text,
21545        replace_range: range_to_replace.to_offset(buffer),
21546        snippet,
21547    }
21548}
21549
21550struct CompletionEdit {
21551    new_text: String,
21552    replace_range: Range<usize>,
21553    snippet: Option<Snippet>,
21554}
21555
21556fn insert_extra_newline_brackets(
21557    buffer: &MultiBufferSnapshot,
21558    range: Range<usize>,
21559    language: &language::LanguageScope,
21560) -> bool {
21561    let leading_whitespace_len = buffer
21562        .reversed_chars_at(range.start)
21563        .take_while(|c| c.is_whitespace() && *c != '\n')
21564        .map(|c| c.len_utf8())
21565        .sum::<usize>();
21566    let trailing_whitespace_len = buffer
21567        .chars_at(range.end)
21568        .take_while(|c| c.is_whitespace() && *c != '\n')
21569        .map(|c| c.len_utf8())
21570        .sum::<usize>();
21571    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21572
21573    language.brackets().any(|(pair, enabled)| {
21574        let pair_start = pair.start.trim_end();
21575        let pair_end = pair.end.trim_start();
21576
21577        enabled
21578            && pair.newline
21579            && buffer.contains_str_at(range.end, pair_end)
21580            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21581    })
21582}
21583
21584fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21585    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21586        [(buffer, range, _)] => (*buffer, range.clone()),
21587        _ => return false,
21588    };
21589    let pair = {
21590        let mut result: Option<BracketMatch> = None;
21591
21592        for pair in buffer
21593            .all_bracket_ranges(range.clone())
21594            .filter(move |pair| {
21595                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21596            })
21597        {
21598            let len = pair.close_range.end - pair.open_range.start;
21599
21600            if let Some(existing) = &result {
21601                let existing_len = existing.close_range.end - existing.open_range.start;
21602                if len > existing_len {
21603                    continue;
21604                }
21605            }
21606
21607            result = Some(pair);
21608        }
21609
21610        result
21611    };
21612    let Some(pair) = pair else {
21613        return false;
21614    };
21615    pair.newline_only
21616        && buffer
21617            .chars_for_range(pair.open_range.end..range.start)
21618            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21619            .all(|c| c.is_whitespace() && c != '\n')
21620}
21621
21622fn update_uncommitted_diff_for_buffer(
21623    editor: Entity<Editor>,
21624    project: &Entity<Project>,
21625    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21626    buffer: Entity<MultiBuffer>,
21627    cx: &mut App,
21628) -> Task<()> {
21629    let mut tasks = Vec::new();
21630    project.update(cx, |project, cx| {
21631        for buffer in buffers {
21632            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21633                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21634            }
21635        }
21636    });
21637    cx.spawn(async move |cx| {
21638        let diffs = future::join_all(tasks).await;
21639        if editor
21640            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21641            .unwrap_or(false)
21642        {
21643            return;
21644        }
21645
21646        buffer
21647            .update(cx, |buffer, cx| {
21648                for diff in diffs.into_iter().flatten() {
21649                    buffer.add_diff(diff, cx);
21650                }
21651            })
21652            .ok();
21653    })
21654}
21655
21656fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21657    let tab_size = tab_size.get() as usize;
21658    let mut width = offset;
21659
21660    for ch in text.chars() {
21661        width += if ch == '\t' {
21662            tab_size - (width % tab_size)
21663        } else {
21664            1
21665        };
21666    }
21667
21668    width - offset
21669}
21670
21671#[cfg(test)]
21672mod tests {
21673    use super::*;
21674
21675    #[test]
21676    fn test_string_size_with_expanded_tabs() {
21677        let nz = |val| NonZeroU32::new(val).unwrap();
21678        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21679        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21680        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21681        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21682        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21683        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21684        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21685        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21686    }
21687}
21688
21689/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21690struct WordBreakingTokenizer<'a> {
21691    input: &'a str,
21692}
21693
21694impl<'a> WordBreakingTokenizer<'a> {
21695    fn new(input: &'a str) -> Self {
21696        Self { input }
21697    }
21698}
21699
21700fn is_char_ideographic(ch: char) -> bool {
21701    use unicode_script::Script::*;
21702    use unicode_script::UnicodeScript;
21703    matches!(ch.script(), Han | Tangut | Yi)
21704}
21705
21706fn is_grapheme_ideographic(text: &str) -> bool {
21707    text.chars().any(is_char_ideographic)
21708}
21709
21710fn is_grapheme_whitespace(text: &str) -> bool {
21711    text.chars().any(|x| x.is_whitespace())
21712}
21713
21714fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21715    text.chars()
21716        .next()
21717        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21718}
21719
21720#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21721enum WordBreakToken<'a> {
21722    Word { token: &'a str, grapheme_len: usize },
21723    InlineWhitespace { token: &'a str, grapheme_len: usize },
21724    Newline,
21725}
21726
21727impl<'a> Iterator for WordBreakingTokenizer<'a> {
21728    /// Yields a span, the count of graphemes in the token, and whether it was
21729    /// whitespace. Note that it also breaks at word boundaries.
21730    type Item = WordBreakToken<'a>;
21731
21732    fn next(&mut self) -> Option<Self::Item> {
21733        use unicode_segmentation::UnicodeSegmentation;
21734        if self.input.is_empty() {
21735            return None;
21736        }
21737
21738        let mut iter = self.input.graphemes(true).peekable();
21739        let mut offset = 0;
21740        let mut grapheme_len = 0;
21741        if let Some(first_grapheme) = iter.next() {
21742            let is_newline = first_grapheme == "\n";
21743            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21744            offset += first_grapheme.len();
21745            grapheme_len += 1;
21746            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21747                if let Some(grapheme) = iter.peek().copied()
21748                    && should_stay_with_preceding_ideograph(grapheme)
21749                {
21750                    offset += grapheme.len();
21751                    grapheme_len += 1;
21752                }
21753            } else {
21754                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21755                let mut next_word_bound = words.peek().copied();
21756                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21757                    next_word_bound = words.next();
21758                }
21759                while let Some(grapheme) = iter.peek().copied() {
21760                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21761                        break;
21762                    };
21763                    if is_grapheme_whitespace(grapheme) != is_whitespace
21764                        || (grapheme == "\n") != is_newline
21765                    {
21766                        break;
21767                    };
21768                    offset += grapheme.len();
21769                    grapheme_len += 1;
21770                    iter.next();
21771                }
21772            }
21773            let token = &self.input[..offset];
21774            self.input = &self.input[offset..];
21775            if token == "\n" {
21776                Some(WordBreakToken::Newline)
21777            } else if is_whitespace {
21778                Some(WordBreakToken::InlineWhitespace {
21779                    token,
21780                    grapheme_len,
21781                })
21782            } else {
21783                Some(WordBreakToken::Word {
21784                    token,
21785                    grapheme_len,
21786                })
21787            }
21788        } else {
21789            None
21790        }
21791    }
21792}
21793
21794#[test]
21795fn test_word_breaking_tokenizer() {
21796    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21797        ("", &[]),
21798        ("  ", &[whitespace("  ", 2)]),
21799        ("Ʒ", &[word("Ʒ", 1)]),
21800        ("Ǽ", &[word("Ǽ", 1)]),
21801        ("", &[word("", 1)]),
21802        ("⋑⋑", &[word("⋑⋑", 2)]),
21803        (
21804            "原理,进而",
21805            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21806        ),
21807        (
21808            "hello world",
21809            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21810        ),
21811        (
21812            "hello, world",
21813            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21814        ),
21815        (
21816            "  hello world",
21817            &[
21818                whitespace("  ", 2),
21819                word("hello", 5),
21820                whitespace(" ", 1),
21821                word("world", 5),
21822            ],
21823        ),
21824        (
21825            "这是什么 \n 钢笔",
21826            &[
21827                word("", 1),
21828                word("", 1),
21829                word("", 1),
21830                word("", 1),
21831                whitespace(" ", 1),
21832                newline(),
21833                whitespace(" ", 1),
21834                word("", 1),
21835                word("", 1),
21836            ],
21837        ),
21838        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21839    ];
21840
21841    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21842        WordBreakToken::Word {
21843            token,
21844            grapheme_len,
21845        }
21846    }
21847
21848    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21849        WordBreakToken::InlineWhitespace {
21850            token,
21851            grapheme_len,
21852        }
21853    }
21854
21855    fn newline() -> WordBreakToken<'static> {
21856        WordBreakToken::Newline
21857    }
21858
21859    for (input, result) in tests {
21860        assert_eq!(
21861            WordBreakingTokenizer::new(input)
21862                .collect::<Vec<_>>()
21863                .as_slice(),
21864            *result,
21865        );
21866    }
21867}
21868
21869fn wrap_with_prefix(
21870    first_line_prefix: String,
21871    subsequent_lines_prefix: String,
21872    unwrapped_text: String,
21873    wrap_column: usize,
21874    tab_size: NonZeroU32,
21875    preserve_existing_whitespace: bool,
21876) -> String {
21877    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21878    let subsequent_lines_prefix_len =
21879        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21880    let mut wrapped_text = String::new();
21881    let mut current_line = first_line_prefix;
21882    let mut is_first_line = true;
21883
21884    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21885    let mut current_line_len = first_line_prefix_len;
21886    let mut in_whitespace = false;
21887    for token in tokenizer {
21888        let have_preceding_whitespace = in_whitespace;
21889        match token {
21890            WordBreakToken::Word {
21891                token,
21892                grapheme_len,
21893            } => {
21894                in_whitespace = false;
21895                let current_prefix_len = if is_first_line {
21896                    first_line_prefix_len
21897                } else {
21898                    subsequent_lines_prefix_len
21899                };
21900                if current_line_len + grapheme_len > wrap_column
21901                    && current_line_len != current_prefix_len
21902                {
21903                    wrapped_text.push_str(current_line.trim_end());
21904                    wrapped_text.push('\n');
21905                    is_first_line = false;
21906                    current_line = subsequent_lines_prefix.clone();
21907                    current_line_len = subsequent_lines_prefix_len;
21908                }
21909                current_line.push_str(token);
21910                current_line_len += grapheme_len;
21911            }
21912            WordBreakToken::InlineWhitespace {
21913                mut token,
21914                mut grapheme_len,
21915            } => {
21916                in_whitespace = true;
21917                if have_preceding_whitespace && !preserve_existing_whitespace {
21918                    continue;
21919                }
21920                if !preserve_existing_whitespace {
21921                    token = " ";
21922                    grapheme_len = 1;
21923                }
21924                let current_prefix_len = if is_first_line {
21925                    first_line_prefix_len
21926                } else {
21927                    subsequent_lines_prefix_len
21928                };
21929                if current_line_len + grapheme_len > wrap_column {
21930                    wrapped_text.push_str(current_line.trim_end());
21931                    wrapped_text.push('\n');
21932                    is_first_line = false;
21933                    current_line = subsequent_lines_prefix.clone();
21934                    current_line_len = subsequent_lines_prefix_len;
21935                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21936                    current_line.push_str(token);
21937                    current_line_len += grapheme_len;
21938                }
21939            }
21940            WordBreakToken::Newline => {
21941                in_whitespace = true;
21942                let current_prefix_len = if is_first_line {
21943                    first_line_prefix_len
21944                } else {
21945                    subsequent_lines_prefix_len
21946                };
21947                if preserve_existing_whitespace {
21948                    wrapped_text.push_str(current_line.trim_end());
21949                    wrapped_text.push('\n');
21950                    is_first_line = false;
21951                    current_line = subsequent_lines_prefix.clone();
21952                    current_line_len = subsequent_lines_prefix_len;
21953                } else if have_preceding_whitespace {
21954                    continue;
21955                } else if current_line_len + 1 > wrap_column
21956                    && current_line_len != current_prefix_len
21957                {
21958                    wrapped_text.push_str(current_line.trim_end());
21959                    wrapped_text.push('\n');
21960                    is_first_line = false;
21961                    current_line = subsequent_lines_prefix.clone();
21962                    current_line_len = subsequent_lines_prefix_len;
21963                } else if current_line_len != current_prefix_len {
21964                    current_line.push(' ');
21965                    current_line_len += 1;
21966                }
21967            }
21968        }
21969    }
21970
21971    if !current_line.is_empty() {
21972        wrapped_text.push_str(&current_line);
21973    }
21974    wrapped_text
21975}
21976
21977#[test]
21978fn test_wrap_with_prefix() {
21979    assert_eq!(
21980        wrap_with_prefix(
21981            "# ".to_string(),
21982            "# ".to_string(),
21983            "abcdefg".to_string(),
21984            4,
21985            NonZeroU32::new(4).unwrap(),
21986            false,
21987        ),
21988        "# abcdefg"
21989    );
21990    assert_eq!(
21991        wrap_with_prefix(
21992            "".to_string(),
21993            "".to_string(),
21994            "\thello world".to_string(),
21995            8,
21996            NonZeroU32::new(4).unwrap(),
21997            false,
21998        ),
21999        "hello\nworld"
22000    );
22001    assert_eq!(
22002        wrap_with_prefix(
22003            "// ".to_string(),
22004            "// ".to_string(),
22005            "xx \nyy zz aa bb cc".to_string(),
22006            12,
22007            NonZeroU32::new(4).unwrap(),
22008            false,
22009        ),
22010        "// xx yy zz\n// aa bb cc"
22011    );
22012    assert_eq!(
22013        wrap_with_prefix(
22014            String::new(),
22015            String::new(),
22016            "这是什么 \n 钢笔".to_string(),
22017            3,
22018            NonZeroU32::new(4).unwrap(),
22019            false,
22020        ),
22021        "这是什\n么 钢\n"
22022    );
22023}
22024
22025pub trait CollaborationHub {
22026    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22027    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22028    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22029}
22030
22031impl CollaborationHub for Entity<Project> {
22032    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22033        self.read(cx).collaborators()
22034    }
22035
22036    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22037        self.read(cx).user_store().read(cx).participant_indices()
22038    }
22039
22040    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22041        let this = self.read(cx);
22042        let user_ids = this.collaborators().values().map(|c| c.user_id);
22043        this.user_store().read(cx).participant_names(user_ids, cx)
22044    }
22045}
22046
22047pub trait SemanticsProvider {
22048    fn hover(
22049        &self,
22050        buffer: &Entity<Buffer>,
22051        position: text::Anchor,
22052        cx: &mut App,
22053    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22054
22055    fn inline_values(
22056        &self,
22057        buffer_handle: Entity<Buffer>,
22058        range: Range<text::Anchor>,
22059        cx: &mut App,
22060    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22061
22062    fn inlay_hints(
22063        &self,
22064        buffer_handle: Entity<Buffer>,
22065        range: Range<text::Anchor>,
22066        cx: &mut App,
22067    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22068
22069    fn resolve_inlay_hint(
22070        &self,
22071        hint: InlayHint,
22072        buffer_handle: Entity<Buffer>,
22073        server_id: LanguageServerId,
22074        cx: &mut App,
22075    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22076
22077    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22078
22079    fn document_highlights(
22080        &self,
22081        buffer: &Entity<Buffer>,
22082        position: text::Anchor,
22083        cx: &mut App,
22084    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22085
22086    fn definitions(
22087        &self,
22088        buffer: &Entity<Buffer>,
22089        position: text::Anchor,
22090        kind: GotoDefinitionKind,
22091        cx: &mut App,
22092    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22093
22094    fn range_for_rename(
22095        &self,
22096        buffer: &Entity<Buffer>,
22097        position: text::Anchor,
22098        cx: &mut App,
22099    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22100
22101    fn perform_rename(
22102        &self,
22103        buffer: &Entity<Buffer>,
22104        position: text::Anchor,
22105        new_name: String,
22106        cx: &mut App,
22107    ) -> Option<Task<Result<ProjectTransaction>>>;
22108}
22109
22110pub trait CompletionProvider {
22111    fn completions(
22112        &self,
22113        excerpt_id: ExcerptId,
22114        buffer: &Entity<Buffer>,
22115        buffer_position: text::Anchor,
22116        trigger: CompletionContext,
22117        window: &mut Window,
22118        cx: &mut Context<Editor>,
22119    ) -> Task<Result<Vec<CompletionResponse>>>;
22120
22121    fn resolve_completions(
22122        &self,
22123        _buffer: Entity<Buffer>,
22124        _completion_indices: Vec<usize>,
22125        _completions: Rc<RefCell<Box<[Completion]>>>,
22126        _cx: &mut Context<Editor>,
22127    ) -> Task<Result<bool>> {
22128        Task::ready(Ok(false))
22129    }
22130
22131    fn apply_additional_edits_for_completion(
22132        &self,
22133        _buffer: Entity<Buffer>,
22134        _completions: Rc<RefCell<Box<[Completion]>>>,
22135        _completion_index: usize,
22136        _push_to_history: bool,
22137        _cx: &mut Context<Editor>,
22138    ) -> Task<Result<Option<language::Transaction>>> {
22139        Task::ready(Ok(None))
22140    }
22141
22142    fn is_completion_trigger(
22143        &self,
22144        buffer: &Entity<Buffer>,
22145        position: language::Anchor,
22146        text: &str,
22147        trigger_in_words: bool,
22148        menu_is_open: bool,
22149        cx: &mut Context<Editor>,
22150    ) -> bool;
22151
22152    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22153
22154    fn sort_completions(&self) -> bool {
22155        true
22156    }
22157
22158    fn filter_completions(&self) -> bool {
22159        true
22160    }
22161}
22162
22163pub trait CodeActionProvider {
22164    fn id(&self) -> Arc<str>;
22165
22166    fn code_actions(
22167        &self,
22168        buffer: &Entity<Buffer>,
22169        range: Range<text::Anchor>,
22170        window: &mut Window,
22171        cx: &mut App,
22172    ) -> Task<Result<Vec<CodeAction>>>;
22173
22174    fn apply_code_action(
22175        &self,
22176        buffer_handle: Entity<Buffer>,
22177        action: CodeAction,
22178        excerpt_id: ExcerptId,
22179        push_to_history: bool,
22180        window: &mut Window,
22181        cx: &mut App,
22182    ) -> Task<Result<ProjectTransaction>>;
22183}
22184
22185impl CodeActionProvider for Entity<Project> {
22186    fn id(&self) -> Arc<str> {
22187        "project".into()
22188    }
22189
22190    fn code_actions(
22191        &self,
22192        buffer: &Entity<Buffer>,
22193        range: Range<text::Anchor>,
22194        _window: &mut Window,
22195        cx: &mut App,
22196    ) -> Task<Result<Vec<CodeAction>>> {
22197        self.update(cx, |project, cx| {
22198            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22199            let code_actions = project.code_actions(buffer, range, None, cx);
22200            cx.background_spawn(async move {
22201                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22202                Ok(code_lens_actions
22203                    .context("code lens fetch")?
22204                    .into_iter()
22205                    .flatten()
22206                    .chain(
22207                        code_actions
22208                            .context("code action fetch")?
22209                            .into_iter()
22210                            .flatten(),
22211                    )
22212                    .collect())
22213            })
22214        })
22215    }
22216
22217    fn apply_code_action(
22218        &self,
22219        buffer_handle: Entity<Buffer>,
22220        action: CodeAction,
22221        _excerpt_id: ExcerptId,
22222        push_to_history: bool,
22223        _window: &mut Window,
22224        cx: &mut App,
22225    ) -> Task<Result<ProjectTransaction>> {
22226        self.update(cx, |project, cx| {
22227            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22228        })
22229    }
22230}
22231
22232fn snippet_completions(
22233    project: &Project,
22234    buffer: &Entity<Buffer>,
22235    buffer_position: text::Anchor,
22236    cx: &mut App,
22237) -> Task<Result<CompletionResponse>> {
22238    let languages = buffer.read(cx).languages_at(buffer_position);
22239    let snippet_store = project.snippets().read(cx);
22240
22241    let scopes: Vec<_> = languages
22242        .iter()
22243        .filter_map(|language| {
22244            let language_name = language.lsp_id();
22245            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22246
22247            if snippets.is_empty() {
22248                None
22249            } else {
22250                Some((language.default_scope(), snippets))
22251            }
22252        })
22253        .collect();
22254
22255    if scopes.is_empty() {
22256        return Task::ready(Ok(CompletionResponse {
22257            completions: vec![],
22258            is_incomplete: false,
22259        }));
22260    }
22261
22262    let snapshot = buffer.read(cx).text_snapshot();
22263    let chars: String = snapshot
22264        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22265        .collect();
22266    let executor = cx.background_executor().clone();
22267
22268    cx.background_spawn(async move {
22269        let mut is_incomplete = false;
22270        let mut completions: Vec<Completion> = Vec::new();
22271        for (scope, snippets) in scopes.into_iter() {
22272            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22273            let mut last_word = chars
22274                .chars()
22275                .take_while(|c| classifier.is_word(*c))
22276                .collect::<String>();
22277            last_word = last_word.chars().rev().collect();
22278
22279            if last_word.is_empty() {
22280                return Ok(CompletionResponse {
22281                    completions: vec![],
22282                    is_incomplete: true,
22283                });
22284            }
22285
22286            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22287            let to_lsp = |point: &text::Anchor| {
22288                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22289                point_to_lsp(end)
22290            };
22291            let lsp_end = to_lsp(&buffer_position);
22292
22293            let candidates = snippets
22294                .iter()
22295                .enumerate()
22296                .flat_map(|(ix, snippet)| {
22297                    snippet
22298                        .prefix
22299                        .iter()
22300                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22301                })
22302                .collect::<Vec<StringMatchCandidate>>();
22303
22304            const MAX_RESULTS: usize = 100;
22305            let mut matches = fuzzy::match_strings(
22306                &candidates,
22307                &last_word,
22308                last_word.chars().any(|c| c.is_uppercase()),
22309                true,
22310                MAX_RESULTS,
22311                &Default::default(),
22312                executor.clone(),
22313            )
22314            .await;
22315
22316            if matches.len() >= MAX_RESULTS {
22317                is_incomplete = true;
22318            }
22319
22320            // Remove all candidates where the query's start does not match the start of any word in the candidate
22321            if let Some(query_start) = last_word.chars().next() {
22322                matches.retain(|string_match| {
22323                    split_words(&string_match.string).any(|word| {
22324                        // Check that the first codepoint of the word as lowercase matches the first
22325                        // codepoint of the query as lowercase
22326                        word.chars()
22327                            .flat_map(|codepoint| codepoint.to_lowercase())
22328                            .zip(query_start.to_lowercase())
22329                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22330                    })
22331                });
22332            }
22333
22334            let matched_strings = matches
22335                .into_iter()
22336                .map(|m| m.string)
22337                .collect::<HashSet<_>>();
22338
22339            completions.extend(snippets.iter().filter_map(|snippet| {
22340                let matching_prefix = snippet
22341                    .prefix
22342                    .iter()
22343                    .find(|prefix| matched_strings.contains(*prefix))?;
22344                let start = as_offset - last_word.len();
22345                let start = snapshot.anchor_before(start);
22346                let range = start..buffer_position;
22347                let lsp_start = to_lsp(&start);
22348                let lsp_range = lsp::Range {
22349                    start: lsp_start,
22350                    end: lsp_end,
22351                };
22352                Some(Completion {
22353                    replace_range: range,
22354                    new_text: snippet.body.clone(),
22355                    source: CompletionSource::Lsp {
22356                        insert_range: None,
22357                        server_id: LanguageServerId(usize::MAX),
22358                        resolved: true,
22359                        lsp_completion: Box::new(lsp::CompletionItem {
22360                            label: snippet.prefix.first().unwrap().clone(),
22361                            kind: Some(CompletionItemKind::SNIPPET),
22362                            label_details: snippet.description.as_ref().map(|description| {
22363                                lsp::CompletionItemLabelDetails {
22364                                    detail: Some(description.clone()),
22365                                    description: None,
22366                                }
22367                            }),
22368                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22369                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22370                                lsp::InsertReplaceEdit {
22371                                    new_text: snippet.body.clone(),
22372                                    insert: lsp_range,
22373                                    replace: lsp_range,
22374                                },
22375                            )),
22376                            filter_text: Some(snippet.body.clone()),
22377                            sort_text: Some(char::MAX.to_string()),
22378                            ..lsp::CompletionItem::default()
22379                        }),
22380                        lsp_defaults: None,
22381                    },
22382                    label: CodeLabel {
22383                        text: matching_prefix.clone(),
22384                        runs: Vec::new(),
22385                        filter_range: 0..matching_prefix.len(),
22386                    },
22387                    icon_path: None,
22388                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22389                        single_line: snippet.name.clone().into(),
22390                        plain_text: snippet
22391                            .description
22392                            .clone()
22393                            .map(|description| description.into()),
22394                    }),
22395                    insert_text_mode: None,
22396                    confirm: None,
22397                })
22398            }))
22399        }
22400
22401        Ok(CompletionResponse {
22402            completions,
22403            is_incomplete,
22404        })
22405    })
22406}
22407
22408impl CompletionProvider for Entity<Project> {
22409    fn completions(
22410        &self,
22411        _excerpt_id: ExcerptId,
22412        buffer: &Entity<Buffer>,
22413        buffer_position: text::Anchor,
22414        options: CompletionContext,
22415        _window: &mut Window,
22416        cx: &mut Context<Editor>,
22417    ) -> Task<Result<Vec<CompletionResponse>>> {
22418        self.update(cx, |project, cx| {
22419            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22420            let project_completions = project.completions(buffer, buffer_position, options, cx);
22421            cx.background_spawn(async move {
22422                let mut responses = project_completions.await?;
22423                let snippets = snippets.await?;
22424                if !snippets.completions.is_empty() {
22425                    responses.push(snippets);
22426                }
22427                Ok(responses)
22428            })
22429        })
22430    }
22431
22432    fn resolve_completions(
22433        &self,
22434        buffer: Entity<Buffer>,
22435        completion_indices: Vec<usize>,
22436        completions: Rc<RefCell<Box<[Completion]>>>,
22437        cx: &mut Context<Editor>,
22438    ) -> Task<Result<bool>> {
22439        self.update(cx, |project, cx| {
22440            project.lsp_store().update(cx, |lsp_store, cx| {
22441                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22442            })
22443        })
22444    }
22445
22446    fn apply_additional_edits_for_completion(
22447        &self,
22448        buffer: Entity<Buffer>,
22449        completions: Rc<RefCell<Box<[Completion]>>>,
22450        completion_index: usize,
22451        push_to_history: bool,
22452        cx: &mut Context<Editor>,
22453    ) -> Task<Result<Option<language::Transaction>>> {
22454        self.update(cx, |project, cx| {
22455            project.lsp_store().update(cx, |lsp_store, cx| {
22456                lsp_store.apply_additional_edits_for_completion(
22457                    buffer,
22458                    completions,
22459                    completion_index,
22460                    push_to_history,
22461                    cx,
22462                )
22463            })
22464        })
22465    }
22466
22467    fn is_completion_trigger(
22468        &self,
22469        buffer: &Entity<Buffer>,
22470        position: language::Anchor,
22471        text: &str,
22472        trigger_in_words: bool,
22473        menu_is_open: bool,
22474        cx: &mut Context<Editor>,
22475    ) -> bool {
22476        let mut chars = text.chars();
22477        let char = if let Some(char) = chars.next() {
22478            char
22479        } else {
22480            return false;
22481        };
22482        if chars.next().is_some() {
22483            return false;
22484        }
22485
22486        let buffer = buffer.read(cx);
22487        let snapshot = buffer.snapshot();
22488        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22489            return false;
22490        }
22491        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22492        if trigger_in_words && classifier.is_word(char) {
22493            return true;
22494        }
22495
22496        buffer.completion_triggers().contains(text)
22497    }
22498}
22499
22500impl SemanticsProvider for Entity<Project> {
22501    fn hover(
22502        &self,
22503        buffer: &Entity<Buffer>,
22504        position: text::Anchor,
22505        cx: &mut App,
22506    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22507        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22508    }
22509
22510    fn document_highlights(
22511        &self,
22512        buffer: &Entity<Buffer>,
22513        position: text::Anchor,
22514        cx: &mut App,
22515    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22516        Some(self.update(cx, |project, cx| {
22517            project.document_highlights(buffer, position, cx)
22518        }))
22519    }
22520
22521    fn definitions(
22522        &self,
22523        buffer: &Entity<Buffer>,
22524        position: text::Anchor,
22525        kind: GotoDefinitionKind,
22526        cx: &mut App,
22527    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22528        Some(self.update(cx, |project, cx| match kind {
22529            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22530            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22531            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22532            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22533        }))
22534    }
22535
22536    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22537        self.update(cx, |project, cx| {
22538            if project
22539                .active_debug_session(cx)
22540                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22541            {
22542                return true;
22543            }
22544
22545            buffer.update(cx, |buffer, cx| {
22546                project.any_language_server_supports_inlay_hints(buffer, cx)
22547            })
22548        })
22549    }
22550
22551    fn inline_values(
22552        &self,
22553        buffer_handle: Entity<Buffer>,
22554        range: Range<text::Anchor>,
22555        cx: &mut App,
22556    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22557        self.update(cx, |project, cx| {
22558            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22559
22560            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22561        })
22562    }
22563
22564    fn inlay_hints(
22565        &self,
22566        buffer_handle: Entity<Buffer>,
22567        range: Range<text::Anchor>,
22568        cx: &mut App,
22569    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22570        Some(self.update(cx, |project, cx| {
22571            project.inlay_hints(buffer_handle, range, cx)
22572        }))
22573    }
22574
22575    fn resolve_inlay_hint(
22576        &self,
22577        hint: InlayHint,
22578        buffer_handle: Entity<Buffer>,
22579        server_id: LanguageServerId,
22580        cx: &mut App,
22581    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22582        Some(self.update(cx, |project, cx| {
22583            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22584        }))
22585    }
22586
22587    fn range_for_rename(
22588        &self,
22589        buffer: &Entity<Buffer>,
22590        position: text::Anchor,
22591        cx: &mut App,
22592    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22593        Some(self.update(cx, |project, cx| {
22594            let buffer = buffer.clone();
22595            let task = project.prepare_rename(buffer.clone(), position, cx);
22596            cx.spawn(async move |_, cx| {
22597                Ok(match task.await? {
22598                    PrepareRenameResponse::Success(range) => Some(range),
22599                    PrepareRenameResponse::InvalidPosition => None,
22600                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22601                        // Fallback on using TreeSitter info to determine identifier range
22602                        buffer.read_with(cx, |buffer, _| {
22603                            let snapshot = buffer.snapshot();
22604                            let (range, kind) = snapshot.surrounding_word(position, false);
22605                            if kind != Some(CharKind::Word) {
22606                                return None;
22607                            }
22608                            Some(
22609                                snapshot.anchor_before(range.start)
22610                                    ..snapshot.anchor_after(range.end),
22611                            )
22612                        })?
22613                    }
22614                })
22615            })
22616        }))
22617    }
22618
22619    fn perform_rename(
22620        &self,
22621        buffer: &Entity<Buffer>,
22622        position: text::Anchor,
22623        new_name: String,
22624        cx: &mut App,
22625    ) -> Option<Task<Result<ProjectTransaction>>> {
22626        Some(self.update(cx, |project, cx| {
22627            project.perform_rename(buffer.clone(), position, new_name, cx)
22628        }))
22629    }
22630}
22631
22632fn inlay_hint_settings(
22633    location: Anchor,
22634    snapshot: &MultiBufferSnapshot,
22635    cx: &mut Context<Editor>,
22636) -> InlayHintSettings {
22637    let file = snapshot.file_at(location);
22638    let language = snapshot.language_at(location).map(|l| l.name());
22639    language_settings(language, file, cx).inlay_hints
22640}
22641
22642fn consume_contiguous_rows(
22643    contiguous_row_selections: &mut Vec<Selection<Point>>,
22644    selection: &Selection<Point>,
22645    display_map: &DisplaySnapshot,
22646    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22647) -> (MultiBufferRow, MultiBufferRow) {
22648    contiguous_row_selections.push(selection.clone());
22649    let start_row = starting_row(selection, display_map);
22650    let mut end_row = ending_row(selection, display_map);
22651
22652    while let Some(next_selection) = selections.peek() {
22653        if next_selection.start.row <= end_row.0 {
22654            end_row = ending_row(next_selection, display_map);
22655            contiguous_row_selections.push(selections.next().unwrap().clone());
22656        } else {
22657            break;
22658        }
22659    }
22660    (start_row, end_row)
22661}
22662
22663fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22664    if selection.start.column > 0 {
22665        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22666    } else {
22667        MultiBufferRow(selection.start.row)
22668    }
22669}
22670
22671fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22672    if next_selection.end.column > 0 || next_selection.is_empty() {
22673        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22674    } else {
22675        MultiBufferRow(next_selection.end.row)
22676    }
22677}
22678
22679impl EditorSnapshot {
22680    pub fn remote_selections_in_range<'a>(
22681        &'a self,
22682        range: &'a Range<Anchor>,
22683        collaboration_hub: &dyn CollaborationHub,
22684        cx: &'a App,
22685    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22686        let participant_names = collaboration_hub.user_names(cx);
22687        let participant_indices = collaboration_hub.user_participant_indices(cx);
22688        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22689        let collaborators_by_replica_id = collaborators_by_peer_id
22690            .values()
22691            .map(|collaborator| (collaborator.replica_id, collaborator))
22692            .collect::<HashMap<_, _>>();
22693        self.buffer_snapshot
22694            .selections_in_range(range, false)
22695            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22696                if replica_id == AGENT_REPLICA_ID {
22697                    Some(RemoteSelection {
22698                        replica_id,
22699                        selection,
22700                        cursor_shape,
22701                        line_mode,
22702                        collaborator_id: CollaboratorId::Agent,
22703                        user_name: Some("Agent".into()),
22704                        color: cx.theme().players().agent(),
22705                    })
22706                } else {
22707                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22708                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22709                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22710                    Some(RemoteSelection {
22711                        replica_id,
22712                        selection,
22713                        cursor_shape,
22714                        line_mode,
22715                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22716                        user_name,
22717                        color: if let Some(index) = participant_index {
22718                            cx.theme().players().color_for_participant(index.0)
22719                        } else {
22720                            cx.theme().players().absent()
22721                        },
22722                    })
22723                }
22724            })
22725    }
22726
22727    pub fn hunks_for_ranges(
22728        &self,
22729        ranges: impl IntoIterator<Item = Range<Point>>,
22730    ) -> Vec<MultiBufferDiffHunk> {
22731        let mut hunks = Vec::new();
22732        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22733            HashMap::default();
22734        for query_range in ranges {
22735            let query_rows =
22736                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22737            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22738                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22739            ) {
22740                // Include deleted hunks that are adjacent to the query range, because
22741                // otherwise they would be missed.
22742                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22743                if hunk.status().is_deleted() {
22744                    intersects_range |= hunk.row_range.start == query_rows.end;
22745                    intersects_range |= hunk.row_range.end == query_rows.start;
22746                }
22747                if intersects_range {
22748                    if !processed_buffer_rows
22749                        .entry(hunk.buffer_id)
22750                        .or_default()
22751                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22752                    {
22753                        continue;
22754                    }
22755                    hunks.push(hunk);
22756                }
22757            }
22758        }
22759
22760        hunks
22761    }
22762
22763    fn display_diff_hunks_for_rows<'a>(
22764        &'a self,
22765        display_rows: Range<DisplayRow>,
22766        folded_buffers: &'a HashSet<BufferId>,
22767    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22768        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22769        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22770
22771        self.buffer_snapshot
22772            .diff_hunks_in_range(buffer_start..buffer_end)
22773            .filter_map(|hunk| {
22774                if folded_buffers.contains(&hunk.buffer_id) {
22775                    return None;
22776                }
22777
22778                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22779                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22780
22781                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22782                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22783
22784                let display_hunk = if hunk_display_start.column() != 0 {
22785                    DisplayDiffHunk::Folded {
22786                        display_row: hunk_display_start.row(),
22787                    }
22788                } else {
22789                    let mut end_row = hunk_display_end.row();
22790                    if hunk_display_end.column() > 0 {
22791                        end_row.0 += 1;
22792                    }
22793                    let is_created_file = hunk.is_created_file();
22794                    DisplayDiffHunk::Unfolded {
22795                        status: hunk.status(),
22796                        diff_base_byte_range: hunk.diff_base_byte_range,
22797                        display_row_range: hunk_display_start.row()..end_row,
22798                        multi_buffer_range: Anchor::range_in_buffer(
22799                            hunk.excerpt_id,
22800                            hunk.buffer_id,
22801                            hunk.buffer_range,
22802                        ),
22803                        is_created_file,
22804                    }
22805                };
22806
22807                Some(display_hunk)
22808            })
22809    }
22810
22811    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22812        self.display_snapshot.buffer_snapshot.language_at(position)
22813    }
22814
22815    pub fn is_focused(&self) -> bool {
22816        self.is_focused
22817    }
22818
22819    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22820        self.placeholder_text.as_ref()
22821    }
22822
22823    pub fn scroll_position(&self) -> gpui::Point<f32> {
22824        self.scroll_anchor.scroll_position(&self.display_snapshot)
22825    }
22826
22827    fn gutter_dimensions(
22828        &self,
22829        font_id: FontId,
22830        font_size: Pixels,
22831        max_line_number_width: Pixels,
22832        cx: &App,
22833    ) -> Option<GutterDimensions> {
22834        if !self.show_gutter {
22835            return None;
22836        }
22837
22838        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22839        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22840
22841        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22842            matches!(
22843                ProjectSettings::get_global(cx).git.git_gutter,
22844                Some(GitGutterSetting::TrackedFiles)
22845            )
22846        });
22847        let gutter_settings = EditorSettings::get_global(cx).gutter;
22848        let show_line_numbers = self
22849            .show_line_numbers
22850            .unwrap_or(gutter_settings.line_numbers);
22851        let line_gutter_width = if show_line_numbers {
22852            // Avoid flicker-like gutter resizes when the line number gains another digit by
22853            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22854            let min_width_for_number_on_gutter =
22855                ch_advance * gutter_settings.min_line_number_digits as f32;
22856            max_line_number_width.max(min_width_for_number_on_gutter)
22857        } else {
22858            0.0.into()
22859        };
22860
22861        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22862        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22863
22864        let git_blame_entries_width =
22865            self.git_blame_gutter_max_author_length
22866                .map(|max_author_length| {
22867                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22868                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22869
22870                    /// The number of characters to dedicate to gaps and margins.
22871                    const SPACING_WIDTH: usize = 4;
22872
22873                    let max_char_count = max_author_length.min(renderer.max_author_length())
22874                        + ::git::SHORT_SHA_LENGTH
22875                        + MAX_RELATIVE_TIMESTAMP.len()
22876                        + SPACING_WIDTH;
22877
22878                    ch_advance * max_char_count
22879                });
22880
22881        let is_singleton = self.buffer_snapshot.is_singleton();
22882
22883        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22884        left_padding += if !is_singleton {
22885            ch_width * 4.0
22886        } else if show_runnables || show_breakpoints {
22887            ch_width * 3.0
22888        } else if show_git_gutter && show_line_numbers {
22889            ch_width * 2.0
22890        } else if show_git_gutter || show_line_numbers {
22891            ch_width
22892        } else {
22893            px(0.)
22894        };
22895
22896        let shows_folds = is_singleton && gutter_settings.folds;
22897
22898        let right_padding = if shows_folds && show_line_numbers {
22899            ch_width * 4.0
22900        } else if shows_folds || (!is_singleton && show_line_numbers) {
22901            ch_width * 3.0
22902        } else if show_line_numbers {
22903            ch_width
22904        } else {
22905            px(0.)
22906        };
22907
22908        Some(GutterDimensions {
22909            left_padding,
22910            right_padding,
22911            width: line_gutter_width + left_padding + right_padding,
22912            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22913            git_blame_entries_width,
22914        })
22915    }
22916
22917    pub fn render_crease_toggle(
22918        &self,
22919        buffer_row: MultiBufferRow,
22920        row_contains_cursor: bool,
22921        editor: Entity<Editor>,
22922        window: &mut Window,
22923        cx: &mut App,
22924    ) -> Option<AnyElement> {
22925        let folded = self.is_line_folded(buffer_row);
22926        let mut is_foldable = false;
22927
22928        if let Some(crease) = self
22929            .crease_snapshot
22930            .query_row(buffer_row, &self.buffer_snapshot)
22931        {
22932            is_foldable = true;
22933            match crease {
22934                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22935                    if let Some(render_toggle) = render_toggle {
22936                        let toggle_callback =
22937                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22938                                if folded {
22939                                    editor.update(cx, |editor, cx| {
22940                                        editor.fold_at(buffer_row, window, cx)
22941                                    });
22942                                } else {
22943                                    editor.update(cx, |editor, cx| {
22944                                        editor.unfold_at(buffer_row, window, cx)
22945                                    });
22946                                }
22947                            });
22948                        return Some((render_toggle)(
22949                            buffer_row,
22950                            folded,
22951                            toggle_callback,
22952                            window,
22953                            cx,
22954                        ));
22955                    }
22956                }
22957            }
22958        }
22959
22960        is_foldable |= self.starts_indent(buffer_row);
22961
22962        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22963            Some(
22964                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22965                    .toggle_state(folded)
22966                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22967                        if folded {
22968                            this.unfold_at(buffer_row, window, cx);
22969                        } else {
22970                            this.fold_at(buffer_row, window, cx);
22971                        }
22972                    }))
22973                    .into_any_element(),
22974            )
22975        } else {
22976            None
22977        }
22978    }
22979
22980    pub fn render_crease_trailer(
22981        &self,
22982        buffer_row: MultiBufferRow,
22983        window: &mut Window,
22984        cx: &mut App,
22985    ) -> Option<AnyElement> {
22986        let folded = self.is_line_folded(buffer_row);
22987        if let Crease::Inline { render_trailer, .. } = self
22988            .crease_snapshot
22989            .query_row(buffer_row, &self.buffer_snapshot)?
22990        {
22991            let render_trailer = render_trailer.as_ref()?;
22992            Some(render_trailer(buffer_row, folded, window, cx))
22993        } else {
22994            None
22995        }
22996    }
22997}
22998
22999impl Deref for EditorSnapshot {
23000    type Target = DisplaySnapshot;
23001
23002    fn deref(&self) -> &Self::Target {
23003        &self.display_snapshot
23004    }
23005}
23006
23007#[derive(Clone, Debug, PartialEq, Eq)]
23008pub enum EditorEvent {
23009    InputIgnored {
23010        text: Arc<str>,
23011    },
23012    InputHandled {
23013        utf16_range_to_replace: Option<Range<isize>>,
23014        text: Arc<str>,
23015    },
23016    ExcerptsAdded {
23017        buffer: Entity<Buffer>,
23018        predecessor: ExcerptId,
23019        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23020    },
23021    ExcerptsRemoved {
23022        ids: Vec<ExcerptId>,
23023        removed_buffer_ids: Vec<BufferId>,
23024    },
23025    BufferFoldToggled {
23026        ids: Vec<ExcerptId>,
23027        folded: bool,
23028    },
23029    ExcerptsEdited {
23030        ids: Vec<ExcerptId>,
23031    },
23032    ExcerptsExpanded {
23033        ids: Vec<ExcerptId>,
23034    },
23035    BufferEdited,
23036    Edited {
23037        transaction_id: clock::Lamport,
23038    },
23039    Reparsed(BufferId),
23040    Focused,
23041    FocusedIn,
23042    Blurred,
23043    DirtyChanged,
23044    Saved,
23045    TitleChanged,
23046    DiffBaseChanged,
23047    SelectionsChanged {
23048        local: bool,
23049    },
23050    ScrollPositionChanged {
23051        local: bool,
23052        autoscroll: bool,
23053    },
23054    Closed,
23055    TransactionUndone {
23056        transaction_id: clock::Lamport,
23057    },
23058    TransactionBegun {
23059        transaction_id: clock::Lamport,
23060    },
23061    Reloaded,
23062    CursorShapeChanged,
23063    BreadcrumbsChanged,
23064    PushedToNavHistory {
23065        anchor: Anchor,
23066        is_deactivate: bool,
23067    },
23068}
23069
23070impl EventEmitter<EditorEvent> for Editor {}
23071
23072impl Focusable for Editor {
23073    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23074        self.focus_handle.clone()
23075    }
23076}
23077
23078impl Render for Editor {
23079    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23080        let settings = ThemeSettings::get_global(cx);
23081
23082        let mut text_style = match self.mode {
23083            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23084                color: cx.theme().colors().editor_foreground,
23085                font_family: settings.ui_font.family.clone(),
23086                font_features: settings.ui_font.features.clone(),
23087                font_fallbacks: settings.ui_font.fallbacks.clone(),
23088                font_size: rems(0.875).into(),
23089                font_weight: settings.ui_font.weight,
23090                line_height: relative(settings.buffer_line_height.value()),
23091                ..Default::default()
23092            },
23093            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23094                color: cx.theme().colors().editor_foreground,
23095                font_family: settings.buffer_font.family.clone(),
23096                font_features: settings.buffer_font.features.clone(),
23097                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23098                font_size: settings.buffer_font_size(cx).into(),
23099                font_weight: settings.buffer_font.weight,
23100                line_height: relative(settings.buffer_line_height.value()),
23101                ..Default::default()
23102            },
23103        };
23104        if let Some(text_style_refinement) = &self.text_style_refinement {
23105            text_style.refine(text_style_refinement)
23106        }
23107
23108        let background = match self.mode {
23109            EditorMode::SingleLine => cx.theme().system().transparent,
23110            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23111            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23112            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23113        };
23114
23115        EditorElement::new(
23116            &cx.entity(),
23117            EditorStyle {
23118                background,
23119                border: cx.theme().colors().border,
23120                local_player: cx.theme().players().local(),
23121                text: text_style,
23122                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23123                syntax: cx.theme().syntax().clone(),
23124                status: cx.theme().status().clone(),
23125                inlay_hints_style: make_inlay_hints_style(cx),
23126                edit_prediction_styles: make_suggestion_styles(cx),
23127                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23128                show_underlines: self.diagnostics_enabled(),
23129            },
23130        )
23131    }
23132}
23133
23134impl EntityInputHandler for Editor {
23135    fn text_for_range(
23136        &mut self,
23137        range_utf16: Range<usize>,
23138        adjusted_range: &mut Option<Range<usize>>,
23139        _: &mut Window,
23140        cx: &mut Context<Self>,
23141    ) -> Option<String> {
23142        let snapshot = self.buffer.read(cx).read(cx);
23143        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23144        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23145        if (start.0..end.0) != range_utf16 {
23146            adjusted_range.replace(start.0..end.0);
23147        }
23148        Some(snapshot.text_for_range(start..end).collect())
23149    }
23150
23151    fn selected_text_range(
23152        &mut self,
23153        ignore_disabled_input: bool,
23154        _: &mut Window,
23155        cx: &mut Context<Self>,
23156    ) -> Option<UTF16Selection> {
23157        // Prevent the IME menu from appearing when holding down an alphabetic key
23158        // while input is disabled.
23159        if !ignore_disabled_input && !self.input_enabled {
23160            return None;
23161        }
23162
23163        let selection = self.selections.newest::<OffsetUtf16>(cx);
23164        let range = selection.range();
23165
23166        Some(UTF16Selection {
23167            range: range.start.0..range.end.0,
23168            reversed: selection.reversed,
23169        })
23170    }
23171
23172    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23173        let snapshot = self.buffer.read(cx).read(cx);
23174        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23175        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23176    }
23177
23178    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23179        self.clear_highlights::<InputComposition>(cx);
23180        self.ime_transaction.take();
23181    }
23182
23183    fn replace_text_in_range(
23184        &mut self,
23185        range_utf16: Option<Range<usize>>,
23186        text: &str,
23187        window: &mut Window,
23188        cx: &mut Context<Self>,
23189    ) {
23190        if !self.input_enabled {
23191            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23192            return;
23193        }
23194
23195        self.transact(window, cx, |this, window, cx| {
23196            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23197                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23198                Some(this.selection_replacement_ranges(range_utf16, cx))
23199            } else {
23200                this.marked_text_ranges(cx)
23201            };
23202
23203            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23204                let newest_selection_id = this.selections.newest_anchor().id;
23205                this.selections
23206                    .all::<OffsetUtf16>(cx)
23207                    .iter()
23208                    .zip(ranges_to_replace.iter())
23209                    .find_map(|(selection, range)| {
23210                        if selection.id == newest_selection_id {
23211                            Some(
23212                                (range.start.0 as isize - selection.head().0 as isize)
23213                                    ..(range.end.0 as isize - selection.head().0 as isize),
23214                            )
23215                        } else {
23216                            None
23217                        }
23218                    })
23219            });
23220
23221            cx.emit(EditorEvent::InputHandled {
23222                utf16_range_to_replace: range_to_replace,
23223                text: text.into(),
23224            });
23225
23226            if let Some(new_selected_ranges) = new_selected_ranges {
23227                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23228                    selections.select_ranges(new_selected_ranges)
23229                });
23230                this.backspace(&Default::default(), window, cx);
23231            }
23232
23233            this.handle_input(text, window, cx);
23234        });
23235
23236        if let Some(transaction) = self.ime_transaction {
23237            self.buffer.update(cx, |buffer, cx| {
23238                buffer.group_until_transaction(transaction, cx);
23239            });
23240        }
23241
23242        self.unmark_text(window, cx);
23243    }
23244
23245    fn replace_and_mark_text_in_range(
23246        &mut self,
23247        range_utf16: Option<Range<usize>>,
23248        text: &str,
23249        new_selected_range_utf16: Option<Range<usize>>,
23250        window: &mut Window,
23251        cx: &mut Context<Self>,
23252    ) {
23253        if !self.input_enabled {
23254            return;
23255        }
23256
23257        let transaction = self.transact(window, cx, |this, window, cx| {
23258            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23259                let snapshot = this.buffer.read(cx).read(cx);
23260                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23261                    for marked_range in &mut marked_ranges {
23262                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23263                        marked_range.start.0 += relative_range_utf16.start;
23264                        marked_range.start =
23265                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23266                        marked_range.end =
23267                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23268                    }
23269                }
23270                Some(marked_ranges)
23271            } else if let Some(range_utf16) = range_utf16 {
23272                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23273                Some(this.selection_replacement_ranges(range_utf16, cx))
23274            } else {
23275                None
23276            };
23277
23278            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23279                let newest_selection_id = this.selections.newest_anchor().id;
23280                this.selections
23281                    .all::<OffsetUtf16>(cx)
23282                    .iter()
23283                    .zip(ranges_to_replace.iter())
23284                    .find_map(|(selection, range)| {
23285                        if selection.id == newest_selection_id {
23286                            Some(
23287                                (range.start.0 as isize - selection.head().0 as isize)
23288                                    ..(range.end.0 as isize - selection.head().0 as isize),
23289                            )
23290                        } else {
23291                            None
23292                        }
23293                    })
23294            });
23295
23296            cx.emit(EditorEvent::InputHandled {
23297                utf16_range_to_replace: range_to_replace,
23298                text: text.into(),
23299            });
23300
23301            if let Some(ranges) = ranges_to_replace {
23302                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23303                    s.select_ranges(ranges)
23304                });
23305            }
23306
23307            let marked_ranges = {
23308                let snapshot = this.buffer.read(cx).read(cx);
23309                this.selections
23310                    .disjoint_anchors()
23311                    .iter()
23312                    .map(|selection| {
23313                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23314                    })
23315                    .collect::<Vec<_>>()
23316            };
23317
23318            if text.is_empty() {
23319                this.unmark_text(window, cx);
23320            } else {
23321                this.highlight_text::<InputComposition>(
23322                    marked_ranges.clone(),
23323                    HighlightStyle {
23324                        underline: Some(UnderlineStyle {
23325                            thickness: px(1.),
23326                            color: None,
23327                            wavy: false,
23328                        }),
23329                        ..Default::default()
23330                    },
23331                    cx,
23332                );
23333            }
23334
23335            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23336            let use_autoclose = this.use_autoclose;
23337            let use_auto_surround = this.use_auto_surround;
23338            this.set_use_autoclose(false);
23339            this.set_use_auto_surround(false);
23340            this.handle_input(text, window, cx);
23341            this.set_use_autoclose(use_autoclose);
23342            this.set_use_auto_surround(use_auto_surround);
23343
23344            if let Some(new_selected_range) = new_selected_range_utf16 {
23345                let snapshot = this.buffer.read(cx).read(cx);
23346                let new_selected_ranges = marked_ranges
23347                    .into_iter()
23348                    .map(|marked_range| {
23349                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23350                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23351                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23352                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23353                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23354                    })
23355                    .collect::<Vec<_>>();
23356
23357                drop(snapshot);
23358                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23359                    selections.select_ranges(new_selected_ranges)
23360                });
23361            }
23362        });
23363
23364        self.ime_transaction = self.ime_transaction.or(transaction);
23365        if let Some(transaction) = self.ime_transaction {
23366            self.buffer.update(cx, |buffer, cx| {
23367                buffer.group_until_transaction(transaction, cx);
23368            });
23369        }
23370
23371        if self.text_highlights::<InputComposition>(cx).is_none() {
23372            self.ime_transaction.take();
23373        }
23374    }
23375
23376    fn bounds_for_range(
23377        &mut self,
23378        range_utf16: Range<usize>,
23379        element_bounds: gpui::Bounds<Pixels>,
23380        window: &mut Window,
23381        cx: &mut Context<Self>,
23382    ) -> Option<gpui::Bounds<Pixels>> {
23383        let text_layout_details = self.text_layout_details(window);
23384        let CharacterDimensions {
23385            em_width,
23386            em_advance,
23387            line_height,
23388        } = self.character_dimensions(window);
23389
23390        let snapshot = self.snapshot(window, cx);
23391        let scroll_position = snapshot.scroll_position();
23392        let scroll_left = scroll_position.x * em_advance;
23393
23394        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23395        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23396            + self.gutter_dimensions.full_width();
23397        let y = line_height * (start.row().as_f32() - scroll_position.y);
23398
23399        Some(Bounds {
23400            origin: element_bounds.origin + point(x, y),
23401            size: size(em_width, line_height),
23402        })
23403    }
23404
23405    fn character_index_for_point(
23406        &mut self,
23407        point: gpui::Point<Pixels>,
23408        _window: &mut Window,
23409        _cx: &mut Context<Self>,
23410    ) -> Option<usize> {
23411        let position_map = self.last_position_map.as_ref()?;
23412        if !position_map.text_hitbox.contains(&point) {
23413            return None;
23414        }
23415        let display_point = position_map.point_for_position(point).previous_valid;
23416        let anchor = position_map
23417            .snapshot
23418            .display_point_to_anchor(display_point, Bias::Left);
23419        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23420        Some(utf16_offset.0)
23421    }
23422}
23423
23424trait SelectionExt {
23425    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23426    fn spanned_rows(
23427        &self,
23428        include_end_if_at_line_start: bool,
23429        map: &DisplaySnapshot,
23430    ) -> Range<MultiBufferRow>;
23431}
23432
23433impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23434    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23435        let start = self
23436            .start
23437            .to_point(&map.buffer_snapshot)
23438            .to_display_point(map);
23439        let end = self
23440            .end
23441            .to_point(&map.buffer_snapshot)
23442            .to_display_point(map);
23443        if self.reversed {
23444            end..start
23445        } else {
23446            start..end
23447        }
23448    }
23449
23450    fn spanned_rows(
23451        &self,
23452        include_end_if_at_line_start: bool,
23453        map: &DisplaySnapshot,
23454    ) -> Range<MultiBufferRow> {
23455        let start = self.start.to_point(&map.buffer_snapshot);
23456        let mut end = self.end.to_point(&map.buffer_snapshot);
23457        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23458            end.row -= 1;
23459        }
23460
23461        let buffer_start = map.prev_line_boundary(start).0;
23462        let buffer_end = map.next_line_boundary(end).0;
23463        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23464    }
23465}
23466
23467impl<T: InvalidationRegion> InvalidationStack<T> {
23468    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23469    where
23470        S: Clone + ToOffset,
23471    {
23472        while let Some(region) = self.last() {
23473            let all_selections_inside_invalidation_ranges =
23474                if selections.len() == region.ranges().len() {
23475                    selections
23476                        .iter()
23477                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23478                        .all(|(selection, invalidation_range)| {
23479                            let head = selection.head().to_offset(buffer);
23480                            invalidation_range.start <= head && invalidation_range.end >= head
23481                        })
23482                } else {
23483                    false
23484                };
23485
23486            if all_selections_inside_invalidation_ranges {
23487                break;
23488            } else {
23489                self.pop();
23490            }
23491        }
23492    }
23493}
23494
23495impl<T> Default for InvalidationStack<T> {
23496    fn default() -> Self {
23497        Self(Default::default())
23498    }
23499}
23500
23501impl<T> Deref for InvalidationStack<T> {
23502    type Target = Vec<T>;
23503
23504    fn deref(&self) -> &Self::Target {
23505        &self.0
23506    }
23507}
23508
23509impl<T> DerefMut for InvalidationStack<T> {
23510    fn deref_mut(&mut self) -> &mut Self::Target {
23511        &mut self.0
23512    }
23513}
23514
23515impl InvalidationRegion for SnippetState {
23516    fn ranges(&self) -> &[Range<Anchor>] {
23517        &self.ranges[self.active_index]
23518    }
23519}
23520
23521fn edit_prediction_edit_text(
23522    current_snapshot: &BufferSnapshot,
23523    edits: &[(Range<Anchor>, String)],
23524    edit_preview: &EditPreview,
23525    include_deletions: bool,
23526    cx: &App,
23527) -> HighlightedText {
23528    let edits = edits
23529        .iter()
23530        .map(|(anchor, text)| {
23531            (
23532                anchor.start.text_anchor..anchor.end.text_anchor,
23533                text.clone(),
23534            )
23535        })
23536        .collect::<Vec<_>>();
23537
23538    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23539}
23540
23541fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23542    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23543    // Just show the raw edit text with basic styling
23544    let mut text = String::new();
23545    let mut highlights = Vec::new();
23546
23547    let insertion_highlight_style = HighlightStyle {
23548        color: Some(cx.theme().colors().text),
23549        ..Default::default()
23550    };
23551
23552    for (_, edit_text) in edits {
23553        let start_offset = text.len();
23554        text.push_str(edit_text);
23555        let end_offset = text.len();
23556
23557        if start_offset < end_offset {
23558            highlights.push((start_offset..end_offset, insertion_highlight_style));
23559        }
23560    }
23561
23562    HighlightedText {
23563        text: text.into(),
23564        highlights,
23565    }
23566}
23567
23568pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23569    match severity {
23570        lsp::DiagnosticSeverity::ERROR => colors.error,
23571        lsp::DiagnosticSeverity::WARNING => colors.warning,
23572        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23573        lsp::DiagnosticSeverity::HINT => colors.info,
23574        _ => colors.ignored,
23575    }
23576}
23577
23578pub fn styled_runs_for_code_label<'a>(
23579    label: &'a CodeLabel,
23580    syntax_theme: &'a theme::SyntaxTheme,
23581) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23582    let fade_out = HighlightStyle {
23583        fade_out: Some(0.35),
23584        ..Default::default()
23585    };
23586
23587    let mut prev_end = label.filter_range.end;
23588    label
23589        .runs
23590        .iter()
23591        .enumerate()
23592        .flat_map(move |(ix, (range, highlight_id))| {
23593            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23594                style
23595            } else {
23596                return Default::default();
23597            };
23598            let mut muted_style = style;
23599            muted_style.highlight(fade_out);
23600
23601            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23602            if range.start >= label.filter_range.end {
23603                if range.start > prev_end {
23604                    runs.push((prev_end..range.start, fade_out));
23605                }
23606                runs.push((range.clone(), muted_style));
23607            } else if range.end <= label.filter_range.end {
23608                runs.push((range.clone(), style));
23609            } else {
23610                runs.push((range.start..label.filter_range.end, style));
23611                runs.push((label.filter_range.end..range.end, muted_style));
23612            }
23613            prev_end = cmp::max(prev_end, range.end);
23614
23615            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23616                runs.push((prev_end..label.text.len(), fade_out));
23617            }
23618
23619            runs
23620        })
23621}
23622
23623pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23624    let mut prev_index = 0;
23625    let mut prev_codepoint: Option<char> = None;
23626    text.char_indices()
23627        .chain([(text.len(), '\0')])
23628        .filter_map(move |(index, codepoint)| {
23629            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23630            let is_boundary = index == text.len()
23631                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23632                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23633            if is_boundary {
23634                let chunk = &text[prev_index..index];
23635                prev_index = index;
23636                Some(chunk)
23637            } else {
23638                None
23639            }
23640        })
23641}
23642
23643pub trait RangeToAnchorExt: Sized {
23644    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23645
23646    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23647        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23648        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23649    }
23650}
23651
23652impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23653    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23654        let start_offset = self.start.to_offset(snapshot);
23655        let end_offset = self.end.to_offset(snapshot);
23656        if start_offset == end_offset {
23657            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23658        } else {
23659            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23660        }
23661    }
23662}
23663
23664pub trait RowExt {
23665    fn as_f32(&self) -> f32;
23666
23667    fn next_row(&self) -> Self;
23668
23669    fn previous_row(&self) -> Self;
23670
23671    fn minus(&self, other: Self) -> u32;
23672}
23673
23674impl RowExt for DisplayRow {
23675    fn as_f32(&self) -> f32 {
23676        self.0 as f32
23677    }
23678
23679    fn next_row(&self) -> Self {
23680        Self(self.0 + 1)
23681    }
23682
23683    fn previous_row(&self) -> Self {
23684        Self(self.0.saturating_sub(1))
23685    }
23686
23687    fn minus(&self, other: Self) -> u32 {
23688        self.0 - other.0
23689    }
23690}
23691
23692impl RowExt for MultiBufferRow {
23693    fn as_f32(&self) -> f32 {
23694        self.0 as f32
23695    }
23696
23697    fn next_row(&self) -> Self {
23698        Self(self.0 + 1)
23699    }
23700
23701    fn previous_row(&self) -> Self {
23702        Self(self.0.saturating_sub(1))
23703    }
23704
23705    fn minus(&self, other: Self) -> u32 {
23706        self.0 - other.0
23707    }
23708}
23709
23710trait RowRangeExt {
23711    type Row;
23712
23713    fn len(&self) -> usize;
23714
23715    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23716}
23717
23718impl RowRangeExt for Range<MultiBufferRow> {
23719    type Row = MultiBufferRow;
23720
23721    fn len(&self) -> usize {
23722        (self.end.0 - self.start.0) as usize
23723    }
23724
23725    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23726        (self.start.0..self.end.0).map(MultiBufferRow)
23727    }
23728}
23729
23730impl RowRangeExt for Range<DisplayRow> {
23731    type Row = DisplayRow;
23732
23733    fn len(&self) -> usize {
23734        (self.end.0 - self.start.0) as usize
23735    }
23736
23737    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23738        (self.start.0..self.end.0).map(DisplayRow)
23739    }
23740}
23741
23742/// If select range has more than one line, we
23743/// just point the cursor to range.start.
23744fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23745    if range.start.row == range.end.row {
23746        range
23747    } else {
23748        range.start..range.start
23749    }
23750}
23751pub struct KillRing(ClipboardItem);
23752impl Global for KillRing {}
23753
23754const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23755
23756enum BreakpointPromptEditAction {
23757    Log,
23758    Condition,
23759    HitCondition,
23760}
23761
23762struct BreakpointPromptEditor {
23763    pub(crate) prompt: Entity<Editor>,
23764    editor: WeakEntity<Editor>,
23765    breakpoint_anchor: Anchor,
23766    breakpoint: Breakpoint,
23767    edit_action: BreakpointPromptEditAction,
23768    block_ids: HashSet<CustomBlockId>,
23769    editor_margins: Arc<Mutex<EditorMargins>>,
23770    _subscriptions: Vec<Subscription>,
23771}
23772
23773impl BreakpointPromptEditor {
23774    const MAX_LINES: u8 = 4;
23775
23776    fn new(
23777        editor: WeakEntity<Editor>,
23778        breakpoint_anchor: Anchor,
23779        breakpoint: Breakpoint,
23780        edit_action: BreakpointPromptEditAction,
23781        window: &mut Window,
23782        cx: &mut Context<Self>,
23783    ) -> Self {
23784        let base_text = match edit_action {
23785            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23786            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23787            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23788        }
23789        .map(|msg| msg.to_string())
23790        .unwrap_or_default();
23791
23792        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23793        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23794
23795        let prompt = cx.new(|cx| {
23796            let mut prompt = Editor::new(
23797                EditorMode::AutoHeight {
23798                    min_lines: 1,
23799                    max_lines: Some(Self::MAX_LINES as usize),
23800                },
23801                buffer,
23802                None,
23803                window,
23804                cx,
23805            );
23806            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23807            prompt.set_show_cursor_when_unfocused(false, cx);
23808            prompt.set_placeholder_text(
23809                match edit_action {
23810                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23811                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23812                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23813                },
23814                cx,
23815            );
23816
23817            prompt
23818        });
23819
23820        Self {
23821            prompt,
23822            editor,
23823            breakpoint_anchor,
23824            breakpoint,
23825            edit_action,
23826            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23827            block_ids: Default::default(),
23828            _subscriptions: vec![],
23829        }
23830    }
23831
23832    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23833        self.block_ids.extend(block_ids)
23834    }
23835
23836    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23837        if let Some(editor) = self.editor.upgrade() {
23838            let message = self
23839                .prompt
23840                .read(cx)
23841                .buffer
23842                .read(cx)
23843                .as_singleton()
23844                .expect("A multi buffer in breakpoint prompt isn't possible")
23845                .read(cx)
23846                .as_rope()
23847                .to_string();
23848
23849            editor.update(cx, |editor, cx| {
23850                editor.edit_breakpoint_at_anchor(
23851                    self.breakpoint_anchor,
23852                    self.breakpoint.clone(),
23853                    match self.edit_action {
23854                        BreakpointPromptEditAction::Log => {
23855                            BreakpointEditAction::EditLogMessage(message.into())
23856                        }
23857                        BreakpointPromptEditAction::Condition => {
23858                            BreakpointEditAction::EditCondition(message.into())
23859                        }
23860                        BreakpointPromptEditAction::HitCondition => {
23861                            BreakpointEditAction::EditHitCondition(message.into())
23862                        }
23863                    },
23864                    cx,
23865                );
23866
23867                editor.remove_blocks(self.block_ids.clone(), None, cx);
23868                cx.focus_self(window);
23869            });
23870        }
23871    }
23872
23873    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23874        self.editor
23875            .update(cx, |editor, cx| {
23876                editor.remove_blocks(self.block_ids.clone(), None, cx);
23877                window.focus(&editor.focus_handle);
23878            })
23879            .log_err();
23880    }
23881
23882    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23883        let settings = ThemeSettings::get_global(cx);
23884        let text_style = TextStyle {
23885            color: if self.prompt.read(cx).read_only(cx) {
23886                cx.theme().colors().text_disabled
23887            } else {
23888                cx.theme().colors().text
23889            },
23890            font_family: settings.buffer_font.family.clone(),
23891            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23892            font_size: settings.buffer_font_size(cx).into(),
23893            font_weight: settings.buffer_font.weight,
23894            line_height: relative(settings.buffer_line_height.value()),
23895            ..Default::default()
23896        };
23897        EditorElement::new(
23898            &self.prompt,
23899            EditorStyle {
23900                background: cx.theme().colors().editor_background,
23901                local_player: cx.theme().players().local(),
23902                text: text_style,
23903                ..Default::default()
23904            },
23905        )
23906    }
23907}
23908
23909impl Render for BreakpointPromptEditor {
23910    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23911        let editor_margins = *self.editor_margins.lock();
23912        let gutter_dimensions = editor_margins.gutter;
23913        h_flex()
23914            .key_context("Editor")
23915            .bg(cx.theme().colors().editor_background)
23916            .border_y_1()
23917            .border_color(cx.theme().status().info_border)
23918            .size_full()
23919            .py(window.line_height() / 2.5)
23920            .on_action(cx.listener(Self::confirm))
23921            .on_action(cx.listener(Self::cancel))
23922            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23923            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23924    }
23925}
23926
23927impl Focusable for BreakpointPromptEditor {
23928    fn focus_handle(&self, cx: &App) -> FocusHandle {
23929        self.prompt.focus_handle(cx)
23930    }
23931}
23932
23933fn all_edits_insertions_or_deletions(
23934    edits: &Vec<(Range<Anchor>, String)>,
23935    snapshot: &MultiBufferSnapshot,
23936) -> bool {
23937    let mut all_insertions = true;
23938    let mut all_deletions = true;
23939
23940    for (range, new_text) in edits.iter() {
23941        let range_is_empty = range.to_offset(snapshot).is_empty();
23942        let text_is_empty = new_text.is_empty();
23943
23944        if range_is_empty != text_is_empty {
23945            if range_is_empty {
23946                all_deletions = false;
23947            } else {
23948                all_insertions = false;
23949            }
23950        } else {
23951            return false;
23952        }
23953
23954        if !all_insertions && !all_deletions {
23955            return false;
23956        }
23957    }
23958    all_insertions || all_deletions
23959}
23960
23961struct MissingEditPredictionKeybindingTooltip;
23962
23963impl Render for MissingEditPredictionKeybindingTooltip {
23964    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23965        ui::tooltip_container(window, cx, |container, _, cx| {
23966            container
23967                .flex_shrink_0()
23968                .max_w_80()
23969                .min_h(rems_from_px(124.))
23970                .justify_between()
23971                .child(
23972                    v_flex()
23973                        .flex_1()
23974                        .text_ui_sm(cx)
23975                        .child(Label::new("Conflict with Accept Keybinding"))
23976                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23977                )
23978                .child(
23979                    h_flex()
23980                        .pb_1()
23981                        .gap_1()
23982                        .items_end()
23983                        .w_full()
23984                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23985                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23986                        }))
23987                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23988                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23989                        })),
23990                )
23991        })
23992    }
23993}
23994
23995#[derive(Debug, Clone, Copy, PartialEq)]
23996pub struct LineHighlight {
23997    pub background: Background,
23998    pub border: Option<gpui::Hsla>,
23999    pub include_gutter: bool,
24000    pub type_id: Option<TypeId>,
24001}
24002
24003struct LineManipulationResult {
24004    pub new_text: String,
24005    pub line_count_before: usize,
24006    pub line_count_after: usize,
24007}
24008
24009fn render_diff_hunk_controls(
24010    row: u32,
24011    status: &DiffHunkStatus,
24012    hunk_range: Range<Anchor>,
24013    is_created_file: bool,
24014    line_height: Pixels,
24015    editor: &Entity<Editor>,
24016    _window: &mut Window,
24017    cx: &mut App,
24018) -> AnyElement {
24019    h_flex()
24020        .h(line_height)
24021        .mr_1()
24022        .gap_1()
24023        .px_0p5()
24024        .pb_1()
24025        .border_x_1()
24026        .border_b_1()
24027        .border_color(cx.theme().colors().border_variant)
24028        .rounded_b_lg()
24029        .bg(cx.theme().colors().editor_background)
24030        .gap_1()
24031        .block_mouse_except_scroll()
24032        .shadow_md()
24033        .child(if status.has_secondary_hunk() {
24034            Button::new(("stage", row as u64), "Stage")
24035                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24036                .tooltip({
24037                    let focus_handle = editor.focus_handle(cx);
24038                    move |window, cx| {
24039                        Tooltip::for_action_in(
24040                            "Stage Hunk",
24041                            &::git::ToggleStaged,
24042                            &focus_handle,
24043                            window,
24044                            cx,
24045                        )
24046                    }
24047                })
24048                .on_click({
24049                    let editor = editor.clone();
24050                    move |_event, _window, cx| {
24051                        editor.update(cx, |editor, cx| {
24052                            editor.stage_or_unstage_diff_hunks(
24053                                true,
24054                                vec![hunk_range.start..hunk_range.start],
24055                                cx,
24056                            );
24057                        });
24058                    }
24059                })
24060        } else {
24061            Button::new(("unstage", row as u64), "Unstage")
24062                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24063                .tooltip({
24064                    let focus_handle = editor.focus_handle(cx);
24065                    move |window, cx| {
24066                        Tooltip::for_action_in(
24067                            "Unstage Hunk",
24068                            &::git::ToggleStaged,
24069                            &focus_handle,
24070                            window,
24071                            cx,
24072                        )
24073                    }
24074                })
24075                .on_click({
24076                    let editor = editor.clone();
24077                    move |_event, _window, cx| {
24078                        editor.update(cx, |editor, cx| {
24079                            editor.stage_or_unstage_diff_hunks(
24080                                false,
24081                                vec![hunk_range.start..hunk_range.start],
24082                                cx,
24083                            );
24084                        });
24085                    }
24086                })
24087        })
24088        .child(
24089            Button::new(("restore", row as u64), "Restore")
24090                .tooltip({
24091                    let focus_handle = editor.focus_handle(cx);
24092                    move |window, cx| {
24093                        Tooltip::for_action_in(
24094                            "Restore Hunk",
24095                            &::git::Restore,
24096                            &focus_handle,
24097                            window,
24098                            cx,
24099                        )
24100                    }
24101                })
24102                .on_click({
24103                    let editor = editor.clone();
24104                    move |_event, window, cx| {
24105                        editor.update(cx, |editor, cx| {
24106                            let snapshot = editor.snapshot(window, cx);
24107                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24108                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24109                        });
24110                    }
24111                })
24112                .disabled(is_created_file),
24113        )
24114        .when(
24115            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24116            |el| {
24117                el.child(
24118                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24119                        .shape(IconButtonShape::Square)
24120                        .icon_size(IconSize::Small)
24121                        // .disabled(!has_multiple_hunks)
24122                        .tooltip({
24123                            let focus_handle = editor.focus_handle(cx);
24124                            move |window, cx| {
24125                                Tooltip::for_action_in(
24126                                    "Next Hunk",
24127                                    &GoToHunk,
24128                                    &focus_handle,
24129                                    window,
24130                                    cx,
24131                                )
24132                            }
24133                        })
24134                        .on_click({
24135                            let editor = editor.clone();
24136                            move |_event, window, cx| {
24137                                editor.update(cx, |editor, cx| {
24138                                    let snapshot = editor.snapshot(window, cx);
24139                                    let position =
24140                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24141                                    editor.go_to_hunk_before_or_after_position(
24142                                        &snapshot,
24143                                        position,
24144                                        Direction::Next,
24145                                        window,
24146                                        cx,
24147                                    );
24148                                    editor.expand_selected_diff_hunks(cx);
24149                                });
24150                            }
24151                        }),
24152                )
24153                .child(
24154                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24155                        .shape(IconButtonShape::Square)
24156                        .icon_size(IconSize::Small)
24157                        // .disabled(!has_multiple_hunks)
24158                        .tooltip({
24159                            let focus_handle = editor.focus_handle(cx);
24160                            move |window, cx| {
24161                                Tooltip::for_action_in(
24162                                    "Previous Hunk",
24163                                    &GoToPreviousHunk,
24164                                    &focus_handle,
24165                                    window,
24166                                    cx,
24167                                )
24168                            }
24169                        })
24170                        .on_click({
24171                            let editor = editor.clone();
24172                            move |_event, window, cx| {
24173                                editor.update(cx, |editor, cx| {
24174                                    let snapshot = editor.snapshot(window, cx);
24175                                    let point =
24176                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24177                                    editor.go_to_hunk_before_or_after_position(
24178                                        &snapshot,
24179                                        point,
24180                                        Direction::Prev,
24181                                        window,
24182                                        cx,
24183                                    );
24184                                    editor.expand_selected_diff_hunks(cx);
24185                                });
24186                            }
24187                        }),
24188                )
24189            },
24190        )
24191        .into_any_element()
24192}
24193
24194pub fn multibuffer_context_lines(cx: &App) -> u32 {
24195    EditorSettings::try_get(cx)
24196        .map(|settings| settings.excerpt_context_lines)
24197        .unwrap_or(2)
24198        .clamp(1, 32)
24199}