editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlay_hint_cache;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   69    RowInfo, ToOffset, ToPoint,
   70};
   71pub use proposed_changes_editor::{
   72    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   73};
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79};
   80use aho_corasick::AhoCorasick;
   81use anyhow::{Context as _, Result, anyhow};
   82use blink_manager::BlinkManager;
   83use buffer_diff::DiffHunkStatus;
   84use client::{Collaborator, ParticipantIndex, parse_zed_link};
   85use clock::ReplicaId;
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   91use convert_case::{Case, Casing};
   92use dap::TelemetrySpawnLocation;
   93use display_map::*;
   94use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   95use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   96use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   97use futures::{
   98    FutureExt, StreamExt as _,
   99    future::{self, Shared, join},
  100    stream::FuturesUnordered,
  101};
  102use fuzzy::{StringMatch, StringMatchCandidate};
  103use git::blame::{GitBlame, GlobalBlameRenderer};
  104use gpui::{
  105    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  106    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  107    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  108    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  109    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  110    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  111    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  112    div, point, prelude::*, pulsating_between, px, relative, size,
  113};
  114use highlight_matching_bracket::refresh_matching_bracket_highlights;
  115use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  125    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  128        all_language_settings, language_settings,
  129    },
  130    point_from_lsp, point_to_lsp, text_diff_with_options,
  131};
  132use linked_editing_ranges::refresh_linked_ranges;
  133use lsp::{
  134    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  135    LanguageServerId,
  136};
  137use lsp_colors::LspColorData;
  138use markdown::Markdown;
  139use mouse_context_menu::MouseContextMenu;
  140use movement::TextLayoutDetails;
  141use multi_buffer::{
  142    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  143    ToOffsetUtf16,
  144};
  145use parking_lot::Mutex;
  146use persistence::DB;
  147use project::{
  148    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  149    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  150    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  151    ProjectTransaction, TaskSourceKind,
  152    debugger::{
  153        breakpoint_store::{
  154            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  155            BreakpointStore, BreakpointStoreEvent,
  156        },
  157        session::{Session, SessionEvent},
  158    },
  159    git_store::{GitStoreEvent, RepositoryEvent},
  160    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  161    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  162};
  163use rand::seq::SliceRandom;
  164use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  165use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  166use selections_collection::{
  167    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  168};
  169use serde::{Deserialize, Serialize};
  170use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  171use smallvec::{SmallVec, smallvec};
  172use snippet::Snippet;
  173use std::{
  174    any::{Any, TypeId},
  175    borrow::Cow,
  176    cell::{OnceCell, RefCell},
  177    cmp::{self, Ordering, Reverse},
  178    iter::{self, Peekable},
  179    mem,
  180    num::NonZeroU32,
  181    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  182    path::{Path, PathBuf},
  183    rc::Rc,
  184    sync::Arc,
  185    time::{Duration, Instant},
  186};
  187use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  188use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::{
  208    code_context_menus::CompletionsMenuSource,
  209    editor_settings::MultiCursorModifier,
  210    hover_links::{find_url, find_url_from_range},
  211    scroll::{ScrollOffset, ScrollPixelOffset},
  212    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  213};
  214
  215pub const FILE_HEADER_HEIGHT: u32 = 2;
  216pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  217const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  218const MAX_LINE_LEN: usize = 1024;
  219const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  220const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  221pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  222#[doc(hidden)]
  223pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  224pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  225
  226pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  227pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  229pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  230
  231pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  232pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  233pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  234
  235pub type RenderDiffHunkControlsFn = Arc<
  236    dyn Fn(
  237        u32,
  238        &DiffHunkStatus,
  239        Range<Anchor>,
  240        bool,
  241        Pixels,
  242        &Entity<Editor>,
  243        &mut Window,
  244        &mut App,
  245    ) -> AnyElement,
  246>;
  247
  248enum ReportEditorEvent {
  249    Saved { auto_saved: bool },
  250    EditorOpened,
  251    Closed,
  252}
  253
  254impl ReportEditorEvent {
  255    pub fn event_type(&self) -> &'static str {
  256        match self {
  257            Self::Saved { .. } => "Editor Saved",
  258            Self::EditorOpened => "Editor Opened",
  259            Self::Closed => "Editor Closed",
  260        }
  261    }
  262}
  263
  264struct InlineValueCache {
  265    enabled: bool,
  266    inlays: Vec<InlayId>,
  267    refresh_task: Task<Option<()>>,
  268}
  269
  270impl InlineValueCache {
  271    fn new(enabled: bool) -> Self {
  272        Self {
  273            enabled,
  274            inlays: Vec::new(),
  275            refresh_task: Task::ready(None),
  276        }
  277    }
  278}
  279
  280#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  281pub enum InlayId {
  282    EditPrediction(u32),
  283    DebuggerValue(u32),
  284    // LSP
  285    Hint(u32),
  286    Color(u32),
  287}
  288
  289impl InlayId {
  290    fn id(&self) -> u32 {
  291        match self {
  292            Self::EditPrediction(id) => *id,
  293            Self::DebuggerValue(id) => *id,
  294            Self::Hint(id) => *id,
  295            Self::Color(id) => *id,
  296        }
  297    }
  298}
  299
  300pub enum ActiveDebugLine {}
  301pub enum DebugStackFrameLine {}
  302enum DocumentHighlightRead {}
  303enum DocumentHighlightWrite {}
  304enum InputComposition {}
  305pub enum PendingInput {}
  306enum SelectedTextHighlight {}
  307
  308pub enum ConflictsOuter {}
  309pub enum ConflictsOurs {}
  310pub enum ConflictsTheirs {}
  311pub enum ConflictsOursMarker {}
  312pub enum ConflictsTheirsMarker {}
  313
  314#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  315pub enum Navigated {
  316    Yes,
  317    No,
  318}
  319
  320impl Navigated {
  321    pub fn from_bool(yes: bool) -> Navigated {
  322        if yes { Navigated::Yes } else { Navigated::No }
  323    }
  324}
  325
  326#[derive(Debug, Clone, PartialEq, Eq)]
  327enum DisplayDiffHunk {
  328    Folded {
  329        display_row: DisplayRow,
  330    },
  331    Unfolded {
  332        is_created_file: bool,
  333        diff_base_byte_range: Range<usize>,
  334        display_row_range: Range<DisplayRow>,
  335        multi_buffer_range: Range<Anchor>,
  336        status: DiffHunkStatus,
  337    },
  338}
  339
  340pub enum HideMouseCursorOrigin {
  341    TypingAction,
  342    MovementAction,
  343}
  344
  345pub fn init_settings(cx: &mut App) {
  346    EditorSettings::register(cx);
  347}
  348
  349pub fn init(cx: &mut App) {
  350    init_settings(cx);
  351
  352    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  353
  354    workspace::register_project_item::<Editor>(cx);
  355    workspace::FollowableViewRegistry::register::<Editor>(cx);
  356    workspace::register_serializable_item::<Editor>(cx);
  357
  358    cx.observe_new(
  359        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  360            workspace.register_action(Editor::new_file);
  361            workspace.register_action(Editor::new_file_split);
  362            workspace.register_action(Editor::new_file_vertical);
  363            workspace.register_action(Editor::new_file_horizontal);
  364            workspace.register_action(Editor::cancel_language_server_work);
  365            workspace.register_action(Editor::toggle_focus);
  366        },
  367    )
  368    .detach();
  369
  370    cx.on_action(move |_: &workspace::NewFile, cx| {
  371        let app_state = workspace::AppState::global(cx);
  372        if let Some(app_state) = app_state.upgrade() {
  373            workspace::open_new(
  374                Default::default(),
  375                app_state,
  376                cx,
  377                |workspace, window, cx| {
  378                    Editor::new_file(workspace, &Default::default(), window, cx)
  379                },
  380            )
  381            .detach();
  382        }
  383    });
  384    cx.on_action(move |_: &workspace::NewWindow, cx| {
  385        let app_state = workspace::AppState::global(cx);
  386        if let Some(app_state) = app_state.upgrade() {
  387            workspace::open_new(
  388                Default::default(),
  389                app_state,
  390                cx,
  391                |workspace, window, cx| {
  392                    cx.activate(true);
  393                    Editor::new_file(workspace, &Default::default(), window, cx)
  394                },
  395            )
  396            .detach();
  397        }
  398    });
  399}
  400
  401pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  402    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  403}
  404
  405pub trait DiagnosticRenderer {
  406    fn render_group(
  407        &self,
  408        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  409        buffer_id: BufferId,
  410        snapshot: EditorSnapshot,
  411        editor: WeakEntity<Editor>,
  412        cx: &mut App,
  413    ) -> Vec<BlockProperties<Anchor>>;
  414
  415    fn render_hover(
  416        &self,
  417        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  418        range: Range<Point>,
  419        buffer_id: BufferId,
  420        cx: &mut App,
  421    ) -> Option<Entity<markdown::Markdown>>;
  422
  423    fn open_link(
  424        &self,
  425        editor: &mut Editor,
  426        link: SharedString,
  427        window: &mut Window,
  428        cx: &mut Context<Editor>,
  429    );
  430}
  431
  432pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  433
  434impl GlobalDiagnosticRenderer {
  435    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  436        cx.try_global::<Self>().map(|g| g.0.clone())
  437    }
  438}
  439
  440impl gpui::Global for GlobalDiagnosticRenderer {}
  441pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  442    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  443}
  444
  445pub struct SearchWithinRange;
  446
  447trait InvalidationRegion {
  448    fn ranges(&self) -> &[Range<Anchor>];
  449}
  450
  451#[derive(Clone, Debug, PartialEq)]
  452pub enum SelectPhase {
  453    Begin {
  454        position: DisplayPoint,
  455        add: bool,
  456        click_count: usize,
  457    },
  458    BeginColumnar {
  459        position: DisplayPoint,
  460        reset: bool,
  461        mode: ColumnarMode,
  462        goal_column: u32,
  463    },
  464    Extend {
  465        position: DisplayPoint,
  466        click_count: usize,
  467    },
  468    Update {
  469        position: DisplayPoint,
  470        goal_column: u32,
  471        scroll_delta: gpui::Point<f32>,
  472    },
  473    End,
  474}
  475
  476#[derive(Clone, Debug, PartialEq)]
  477pub enum ColumnarMode {
  478    FromMouse,
  479    FromSelection,
  480}
  481
  482#[derive(Clone, Debug)]
  483pub enum SelectMode {
  484    Character,
  485    Word(Range<Anchor>),
  486    Line(Range<Anchor>),
  487    All,
  488}
  489
  490#[derive(Clone, PartialEq, Eq, Debug)]
  491pub enum EditorMode {
  492    SingleLine,
  493    AutoHeight {
  494        min_lines: usize,
  495        max_lines: Option<usize>,
  496    },
  497    Full {
  498        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  499        scale_ui_elements_with_buffer_font_size: bool,
  500        /// When set to `true`, the editor will render a background for the active line.
  501        show_active_line_background: bool,
  502        /// When set to `true`, the editor's height will be determined by its content.
  503        sized_by_content: bool,
  504    },
  505    Minimap {
  506        parent: WeakEntity<Editor>,
  507    },
  508}
  509
  510impl EditorMode {
  511    pub fn full() -> Self {
  512        Self::Full {
  513            scale_ui_elements_with_buffer_font_size: true,
  514            show_active_line_background: true,
  515            sized_by_content: false,
  516        }
  517    }
  518
  519    #[inline]
  520    pub fn is_full(&self) -> bool {
  521        matches!(self, Self::Full { .. })
  522    }
  523
  524    #[inline]
  525    pub fn is_single_line(&self) -> bool {
  526        matches!(self, Self::SingleLine { .. })
  527    }
  528
  529    #[inline]
  530    fn is_minimap(&self) -> bool {
  531        matches!(self, Self::Minimap { .. })
  532    }
  533}
  534
  535#[derive(Copy, Clone, Debug)]
  536pub enum SoftWrap {
  537    /// Prefer not to wrap at all.
  538    ///
  539    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  540    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  541    GitDiff,
  542    /// Prefer a single line generally, unless an overly long line is encountered.
  543    None,
  544    /// Soft wrap lines that exceed the editor width.
  545    EditorWidth,
  546    /// Soft wrap lines at the preferred line length.
  547    Column(u32),
  548    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  549    Bounded(u32),
  550}
  551
  552#[derive(Clone)]
  553pub struct EditorStyle {
  554    pub background: Hsla,
  555    pub border: Hsla,
  556    pub local_player: PlayerColor,
  557    pub text: TextStyle,
  558    pub scrollbar_width: Pixels,
  559    pub syntax: Arc<SyntaxTheme>,
  560    pub status: StatusColors,
  561    pub inlay_hints_style: HighlightStyle,
  562    pub edit_prediction_styles: EditPredictionStyles,
  563    pub unnecessary_code_fade: f32,
  564    pub show_underlines: bool,
  565}
  566
  567impl Default for EditorStyle {
  568    fn default() -> Self {
  569        Self {
  570            background: Hsla::default(),
  571            border: Hsla::default(),
  572            local_player: PlayerColor::default(),
  573            text: TextStyle::default(),
  574            scrollbar_width: Pixels::default(),
  575            syntax: Default::default(),
  576            // HACK: Status colors don't have a real default.
  577            // We should look into removing the status colors from the editor
  578            // style and retrieve them directly from the theme.
  579            status: StatusColors::dark(),
  580            inlay_hints_style: HighlightStyle::default(),
  581            edit_prediction_styles: EditPredictionStyles {
  582                insertion: HighlightStyle::default(),
  583                whitespace: HighlightStyle::default(),
  584            },
  585            unnecessary_code_fade: Default::default(),
  586            show_underlines: true,
  587        }
  588    }
  589}
  590
  591pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  592    let show_background = language_settings::language_settings(None, None, cx)
  593        .inlay_hints
  594        .show_background;
  595
  596    let mut style = cx.theme().syntax().get("hint");
  597
  598    if style.color.is_none() {
  599        style.color = Some(cx.theme().status().hint);
  600    }
  601
  602    if !show_background {
  603        style.background_color = None;
  604        return style;
  605    }
  606
  607    if style.background_color.is_none() {
  608        style.background_color = Some(cx.theme().status().hint_background);
  609    }
  610
  611    style
  612}
  613
  614pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  615    EditPredictionStyles {
  616        insertion: HighlightStyle {
  617            color: Some(cx.theme().status().predictive),
  618            ..HighlightStyle::default()
  619        },
  620        whitespace: HighlightStyle {
  621            background_color: Some(cx.theme().status().created_background),
  622            ..HighlightStyle::default()
  623        },
  624    }
  625}
  626
  627type CompletionId = usize;
  628
  629pub(crate) enum EditDisplayMode {
  630    TabAccept,
  631    DiffPopover,
  632    Inline,
  633}
  634
  635enum EditPrediction {
  636    Edit {
  637        edits: Vec<(Range<Anchor>, String)>,
  638        edit_preview: Option<EditPreview>,
  639        display_mode: EditDisplayMode,
  640        snapshot: BufferSnapshot,
  641    },
  642    /// Move to a specific location in the active editor
  643    MoveWithin {
  644        target: Anchor,
  645        snapshot: BufferSnapshot,
  646    },
  647    /// Move to a specific location in a different editor (not the active one)
  648    MoveOutside {
  649        target: language::Anchor,
  650        snapshot: BufferSnapshot,
  651    },
  652}
  653
  654struct EditPredictionState {
  655    inlay_ids: Vec<InlayId>,
  656    completion: EditPrediction,
  657    completion_id: Option<SharedString>,
  658    invalidation_range: Option<Range<Anchor>>,
  659}
  660
  661enum EditPredictionSettings {
  662    Disabled,
  663    Enabled {
  664        show_in_menu: bool,
  665        preview_requires_modifier: bool,
  666    },
  667}
  668
  669enum EditPredictionHighlight {}
  670
  671#[derive(Debug, Clone)]
  672struct InlineDiagnostic {
  673    message: SharedString,
  674    group_id: usize,
  675    is_primary: bool,
  676    start: Point,
  677    severity: lsp::DiagnosticSeverity,
  678}
  679
  680pub enum MenuEditPredictionsPolicy {
  681    Never,
  682    ByProvider,
  683}
  684
  685pub enum EditPredictionPreview {
  686    /// Modifier is not pressed
  687    Inactive { released_too_fast: bool },
  688    /// Modifier pressed
  689    Active {
  690        since: Instant,
  691        previous_scroll_position: Option<ScrollAnchor>,
  692    },
  693}
  694
  695impl EditPredictionPreview {
  696    pub fn released_too_fast(&self) -> bool {
  697        match self {
  698            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  699            EditPredictionPreview::Active { .. } => false,
  700        }
  701    }
  702
  703    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  704        if let EditPredictionPreview::Active {
  705            previous_scroll_position,
  706            ..
  707        } = self
  708        {
  709            *previous_scroll_position = scroll_position;
  710        }
  711    }
  712}
  713
  714pub struct ContextMenuOptions {
  715    pub min_entries_visible: usize,
  716    pub max_entries_visible: usize,
  717    pub placement: Option<ContextMenuPlacement>,
  718}
  719
  720#[derive(Debug, Clone, PartialEq, Eq)]
  721pub enum ContextMenuPlacement {
  722    Above,
  723    Below,
  724}
  725
  726#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  727struct EditorActionId(usize);
  728
  729impl EditorActionId {
  730    pub fn post_inc(&mut self) -> Self {
  731        let answer = self.0;
  732
  733        *self = Self(answer + 1);
  734
  735        Self(answer)
  736    }
  737}
  738
  739// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  740// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  741
  742type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  743type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  744
  745#[derive(Default)]
  746struct ScrollbarMarkerState {
  747    scrollbar_size: Size<Pixels>,
  748    dirty: bool,
  749    markers: Arc<[PaintQuad]>,
  750    pending_refresh: Option<Task<Result<()>>>,
  751}
  752
  753impl ScrollbarMarkerState {
  754    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  755        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  756    }
  757}
  758
  759#[derive(Clone, Copy, PartialEq, Eq)]
  760pub enum MinimapVisibility {
  761    Disabled,
  762    Enabled {
  763        /// The configuration currently present in the users settings.
  764        setting_configuration: bool,
  765        /// Whether to override the currently set visibility from the users setting.
  766        toggle_override: bool,
  767    },
  768}
  769
  770impl MinimapVisibility {
  771    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  772        if mode.is_full() {
  773            Self::Enabled {
  774                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  775                toggle_override: false,
  776            }
  777        } else {
  778            Self::Disabled
  779        }
  780    }
  781
  782    fn hidden(&self) -> Self {
  783        match *self {
  784            Self::Enabled {
  785                setting_configuration,
  786                ..
  787            } => Self::Enabled {
  788                setting_configuration,
  789                toggle_override: setting_configuration,
  790            },
  791            Self::Disabled => Self::Disabled,
  792        }
  793    }
  794
  795    fn disabled(&self) -> bool {
  796        matches!(*self, Self::Disabled)
  797    }
  798
  799    fn settings_visibility(&self) -> bool {
  800        match *self {
  801            Self::Enabled {
  802                setting_configuration,
  803                ..
  804            } => setting_configuration,
  805            _ => false,
  806        }
  807    }
  808
  809    fn visible(&self) -> bool {
  810        match *self {
  811            Self::Enabled {
  812                setting_configuration,
  813                toggle_override,
  814            } => setting_configuration ^ toggle_override,
  815            _ => false,
  816        }
  817    }
  818
  819    fn toggle_visibility(&self) -> Self {
  820        match *self {
  821            Self::Enabled {
  822                toggle_override,
  823                setting_configuration,
  824            } => Self::Enabled {
  825                setting_configuration,
  826                toggle_override: !toggle_override,
  827            },
  828            Self::Disabled => Self::Disabled,
  829        }
  830    }
  831}
  832
  833#[derive(Clone, Debug)]
  834struct RunnableTasks {
  835    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  836    offset: multi_buffer::Anchor,
  837    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  838    column: u32,
  839    // Values of all named captures, including those starting with '_'
  840    extra_variables: HashMap<String, String>,
  841    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  842    context_range: Range<BufferOffset>,
  843}
  844
  845impl RunnableTasks {
  846    fn resolve<'a>(
  847        &'a self,
  848        cx: &'a task::TaskContext,
  849    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  850        self.templates.iter().filter_map(|(kind, template)| {
  851            template
  852                .resolve_task(&kind.to_id_base(), cx)
  853                .map(|task| (kind.clone(), task))
  854        })
  855    }
  856}
  857
  858#[derive(Clone)]
  859pub struct ResolvedTasks {
  860    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  861    position: Anchor,
  862}
  863
  864#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  865struct BufferOffset(usize);
  866
  867/// Addons allow storing per-editor state in other crates (e.g. Vim)
  868pub trait Addon: 'static {
  869    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  870
  871    fn render_buffer_header_controls(
  872        &self,
  873        _: &ExcerptInfo,
  874        _: &Window,
  875        _: &App,
  876    ) -> Option<AnyElement> {
  877        None
  878    }
  879
  880    fn to_any(&self) -> &dyn std::any::Any;
  881
  882    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  883        None
  884    }
  885}
  886
  887struct ChangeLocation {
  888    current: Option<Vec<Anchor>>,
  889    original: Vec<Anchor>,
  890}
  891impl ChangeLocation {
  892    fn locations(&self) -> &[Anchor] {
  893        self.current.as_ref().unwrap_or(&self.original)
  894    }
  895}
  896
  897/// A set of caret positions, registered when the editor was edited.
  898pub struct ChangeList {
  899    changes: Vec<ChangeLocation>,
  900    /// Currently "selected" change.
  901    position: Option<usize>,
  902}
  903
  904impl ChangeList {
  905    pub fn new() -> Self {
  906        Self {
  907            changes: Vec::new(),
  908            position: None,
  909        }
  910    }
  911
  912    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  913    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  914    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  915        if self.changes.is_empty() {
  916            return None;
  917        }
  918
  919        let prev = self.position.unwrap_or(self.changes.len());
  920        let next = if direction == Direction::Prev {
  921            prev.saturating_sub(count)
  922        } else {
  923            (prev + count).min(self.changes.len() - 1)
  924        };
  925        self.position = Some(next);
  926        self.changes.get(next).map(|change| change.locations())
  927    }
  928
  929    /// Adds a new change to the list, resetting the change list position.
  930    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  931        self.position.take();
  932        if let Some(last) = self.changes.last_mut()
  933            && group
  934        {
  935            last.current = Some(new_positions)
  936        } else {
  937            self.changes.push(ChangeLocation {
  938                original: new_positions,
  939                current: None,
  940            });
  941        }
  942    }
  943
  944    pub fn last(&self) -> Option<&[Anchor]> {
  945        self.changes.last().map(|change| change.locations())
  946    }
  947
  948    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  949        self.changes.last().map(|change| change.original.as_slice())
  950    }
  951
  952    pub fn invert_last_group(&mut self) {
  953        if let Some(last) = self.changes.last_mut()
  954            && let Some(current) = last.current.as_mut()
  955        {
  956            mem::swap(&mut last.original, current);
  957        }
  958    }
  959}
  960
  961#[derive(Clone)]
  962struct InlineBlamePopoverState {
  963    scroll_handle: ScrollHandle,
  964    commit_message: Option<ParsedCommitMessage>,
  965    markdown: Entity<Markdown>,
  966}
  967
  968struct InlineBlamePopover {
  969    position: gpui::Point<Pixels>,
  970    hide_task: Option<Task<()>>,
  971    popover_bounds: Option<Bounds<Pixels>>,
  972    popover_state: InlineBlamePopoverState,
  973    keyboard_grace: bool,
  974}
  975
  976enum SelectionDragState {
  977    /// State when no drag related activity is detected.
  978    None,
  979    /// State when the mouse is down on a selection that is about to be dragged.
  980    ReadyToDrag {
  981        selection: Selection<Anchor>,
  982        click_position: gpui::Point<Pixels>,
  983        mouse_down_time: Instant,
  984    },
  985    /// State when the mouse is dragging the selection in the editor.
  986    Dragging {
  987        selection: Selection<Anchor>,
  988        drop_cursor: Selection<Anchor>,
  989        hide_drop_cursor: bool,
  990    },
  991}
  992
  993enum ColumnarSelectionState {
  994    FromMouse {
  995        selection_tail: Anchor,
  996        display_point: Option<DisplayPoint>,
  997    },
  998    FromSelection {
  999        selection_tail: Anchor,
 1000    },
 1001}
 1002
 1003/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1004/// a breakpoint on them.
 1005#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1006struct PhantomBreakpointIndicator {
 1007    display_row: DisplayRow,
 1008    /// There's a small debounce between hovering over the line and showing the indicator.
 1009    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1010    is_active: bool,
 1011    collides_with_existing_breakpoint: bool,
 1012}
 1013
 1014/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1015///
 1016/// See the [module level documentation](self) for more information.
 1017pub struct Editor {
 1018    focus_handle: FocusHandle,
 1019    last_focused_descendant: Option<WeakFocusHandle>,
 1020    /// The text buffer being edited
 1021    buffer: Entity<MultiBuffer>,
 1022    /// Map of how text in the buffer should be displayed.
 1023    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1024    pub display_map: Entity<DisplayMap>,
 1025    placeholder_display_map: Option<Entity<DisplayMap>>,
 1026    pub selections: SelectionsCollection,
 1027    pub scroll_manager: ScrollManager,
 1028    /// When inline assist editors are linked, they all render cursors because
 1029    /// typing enters text into each of them, even the ones that aren't focused.
 1030    pub(crate) show_cursor_when_unfocused: bool,
 1031    columnar_selection_state: Option<ColumnarSelectionState>,
 1032    add_selections_state: Option<AddSelectionsState>,
 1033    select_next_state: Option<SelectNextState>,
 1034    select_prev_state: Option<SelectNextState>,
 1035    selection_history: SelectionHistory,
 1036    defer_selection_effects: bool,
 1037    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1038    autoclose_regions: Vec<AutocloseRegion>,
 1039    snippet_stack: InvalidationStack<SnippetState>,
 1040    select_syntax_node_history: SelectSyntaxNodeHistory,
 1041    ime_transaction: Option<TransactionId>,
 1042    pub diagnostics_max_severity: DiagnosticSeverity,
 1043    active_diagnostics: ActiveDiagnostic,
 1044    show_inline_diagnostics: bool,
 1045    inline_diagnostics_update: Task<()>,
 1046    inline_diagnostics_enabled: bool,
 1047    diagnostics_enabled: bool,
 1048    word_completions_enabled: bool,
 1049    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1050    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1051    hard_wrap: Option<usize>,
 1052    project: Option<Entity<Project>>,
 1053    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1054    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1055    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1056    blink_manager: Entity<BlinkManager>,
 1057    show_cursor_names: bool,
 1058    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1059    pub show_local_selections: bool,
 1060    mode: EditorMode,
 1061    show_breadcrumbs: bool,
 1062    show_gutter: bool,
 1063    show_scrollbars: ScrollbarAxes,
 1064    minimap_visibility: MinimapVisibility,
 1065    offset_content: bool,
 1066    disable_expand_excerpt_buttons: bool,
 1067    show_line_numbers: Option<bool>,
 1068    use_relative_line_numbers: Option<bool>,
 1069    show_git_diff_gutter: Option<bool>,
 1070    show_code_actions: Option<bool>,
 1071    show_runnables: Option<bool>,
 1072    show_breakpoints: Option<bool>,
 1073    show_wrap_guides: Option<bool>,
 1074    show_indent_guides: Option<bool>,
 1075    highlight_order: usize,
 1076    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1077    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1078    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1079    scrollbar_marker_state: ScrollbarMarkerState,
 1080    active_indent_guides_state: ActiveIndentGuidesState,
 1081    nav_history: Option<ItemNavHistory>,
 1082    context_menu: RefCell<Option<CodeContextMenu>>,
 1083    context_menu_options: Option<ContextMenuOptions>,
 1084    mouse_context_menu: Option<MouseContextMenu>,
 1085    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1086    inline_blame_popover: Option<InlineBlamePopover>,
 1087    inline_blame_popover_show_task: Option<Task<()>>,
 1088    signature_help_state: SignatureHelpState,
 1089    auto_signature_help: Option<bool>,
 1090    find_all_references_task_sources: Vec<Anchor>,
 1091    next_completion_id: CompletionId,
 1092    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1093    code_actions_task: Option<Task<Result<()>>>,
 1094    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1096    document_highlights_task: Option<Task<()>>,
 1097    linked_editing_range_task: Option<Task<Option<()>>>,
 1098    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1099    pending_rename: Option<RenameState>,
 1100    searchable: bool,
 1101    cursor_shape: CursorShape,
 1102    current_line_highlight: Option<CurrentLineHighlight>,
 1103    collapse_matches: bool,
 1104    autoindent_mode: Option<AutoindentMode>,
 1105    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1106    input_enabled: bool,
 1107    use_modal_editing: bool,
 1108    read_only: bool,
 1109    leader_id: Option<CollaboratorId>,
 1110    remote_id: Option<ViewId>,
 1111    pub hover_state: HoverState,
 1112    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1113    gutter_hovered: bool,
 1114    hovered_link_state: Option<HoveredLinkState>,
 1115    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1116    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1117    active_edit_prediction: Option<EditPredictionState>,
 1118    /// Used to prevent flickering as the user types while the menu is open
 1119    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1120    edit_prediction_settings: EditPredictionSettings,
 1121    edit_predictions_hidden_for_vim_mode: bool,
 1122    show_edit_predictions_override: Option<bool>,
 1123    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1124    edit_prediction_preview: EditPredictionPreview,
 1125    edit_prediction_indent_conflict: bool,
 1126    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1127    inlay_hint_cache: InlayHintCache,
 1128    next_inlay_id: u32,
 1129    next_color_inlay_id: u32,
 1130    _subscriptions: Vec<Subscription>,
 1131    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1132    gutter_dimensions: GutterDimensions,
 1133    style: Option<EditorStyle>,
 1134    text_style_refinement: Option<TextStyleRefinement>,
 1135    next_editor_action_id: EditorActionId,
 1136    editor_actions: Rc<
 1137        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1138    >,
 1139    use_autoclose: bool,
 1140    use_auto_surround: bool,
 1141    auto_replace_emoji_shortcode: bool,
 1142    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1143    show_git_blame_gutter: bool,
 1144    show_git_blame_inline: bool,
 1145    show_git_blame_inline_delay_task: Option<Task<()>>,
 1146    git_blame_inline_enabled: bool,
 1147    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1148    serialize_dirty_buffers: bool,
 1149    show_selection_menu: Option<bool>,
 1150    blame: Option<Entity<GitBlame>>,
 1151    blame_subscription: Option<Subscription>,
 1152    custom_context_menu: Option<
 1153        Box<
 1154            dyn 'static
 1155                + Fn(
 1156                    &mut Self,
 1157                    DisplayPoint,
 1158                    &mut Window,
 1159                    &mut Context<Self>,
 1160                ) -> Option<Entity<ui::ContextMenu>>,
 1161        >,
 1162    >,
 1163    last_bounds: Option<Bounds<Pixels>>,
 1164    last_position_map: Option<Rc<PositionMap>>,
 1165    expect_bounds_change: Option<Bounds<Pixels>>,
 1166    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1167    tasks_update_task: Option<Task<()>>,
 1168    breakpoint_store: Option<Entity<BreakpointStore>>,
 1169    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1170    hovered_diff_hunk_row: Option<DisplayRow>,
 1171    pull_diagnostics_task: Task<()>,
 1172    in_project_search: bool,
 1173    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1174    breadcrumb_header: Option<String>,
 1175    focused_block: Option<FocusedBlock>,
 1176    next_scroll_position: NextScrollCursorCenterTopBottom,
 1177    addons: HashMap<TypeId, Box<dyn Addon>>,
 1178    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1179    load_diff_task: Option<Shared<Task<()>>>,
 1180    /// Whether we are temporarily displaying a diff other than git's
 1181    temporary_diff_override: bool,
 1182    selection_mark_mode: bool,
 1183    toggle_fold_multiple_buffers: Task<()>,
 1184    _scroll_cursor_center_top_bottom_task: Task<()>,
 1185    serialize_selections: Task<()>,
 1186    serialize_folds: Task<()>,
 1187    mouse_cursor_hidden: bool,
 1188    minimap: Option<Entity<Self>>,
 1189    hide_mouse_mode: HideMouseMode,
 1190    pub change_list: ChangeList,
 1191    inline_value_cache: InlineValueCache,
 1192    selection_drag_state: SelectionDragState,
 1193    colors: Option<LspColorData>,
 1194    post_scroll_update: Task<()>,
 1195    refresh_colors_task: Task<()>,
 1196    folding_newlines: Task<()>,
 1197    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1198}
 1199
 1200#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1201enum NextScrollCursorCenterTopBottom {
 1202    #[default]
 1203    Center,
 1204    Top,
 1205    Bottom,
 1206}
 1207
 1208impl NextScrollCursorCenterTopBottom {
 1209    fn next(&self) -> Self {
 1210        match self {
 1211            Self::Center => Self::Top,
 1212            Self::Top => Self::Bottom,
 1213            Self::Bottom => Self::Center,
 1214        }
 1215    }
 1216}
 1217
 1218#[derive(Clone)]
 1219pub struct EditorSnapshot {
 1220    pub mode: EditorMode,
 1221    show_gutter: bool,
 1222    show_line_numbers: Option<bool>,
 1223    show_git_diff_gutter: Option<bool>,
 1224    show_code_actions: Option<bool>,
 1225    show_runnables: Option<bool>,
 1226    show_breakpoints: Option<bool>,
 1227    git_blame_gutter_max_author_length: Option<usize>,
 1228    pub display_snapshot: DisplaySnapshot,
 1229    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1230    is_focused: bool,
 1231    scroll_anchor: ScrollAnchor,
 1232    ongoing_scroll: OngoingScroll,
 1233    current_line_highlight: CurrentLineHighlight,
 1234    gutter_hovered: bool,
 1235}
 1236
 1237#[derive(Default, Debug, Clone, Copy)]
 1238pub struct GutterDimensions {
 1239    pub left_padding: Pixels,
 1240    pub right_padding: Pixels,
 1241    pub width: Pixels,
 1242    pub margin: Pixels,
 1243    pub git_blame_entries_width: Option<Pixels>,
 1244}
 1245
 1246impl GutterDimensions {
 1247    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1248        Self {
 1249            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1250            ..Default::default()
 1251        }
 1252    }
 1253
 1254    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1255        -cx.text_system().descent(font_id, font_size)
 1256    }
 1257    /// The full width of the space taken up by the gutter.
 1258    pub fn full_width(&self) -> Pixels {
 1259        self.margin + self.width
 1260    }
 1261
 1262    /// The width of the space reserved for the fold indicators,
 1263    /// use alongside 'justify_end' and `gutter_width` to
 1264    /// right align content with the line numbers
 1265    pub fn fold_area_width(&self) -> Pixels {
 1266        self.margin + self.right_padding
 1267    }
 1268}
 1269
 1270struct CharacterDimensions {
 1271    em_width: Pixels,
 1272    em_advance: Pixels,
 1273    line_height: Pixels,
 1274}
 1275
 1276#[derive(Debug)]
 1277pub struct RemoteSelection {
 1278    pub replica_id: ReplicaId,
 1279    pub selection: Selection<Anchor>,
 1280    pub cursor_shape: CursorShape,
 1281    pub collaborator_id: CollaboratorId,
 1282    pub line_mode: bool,
 1283    pub user_name: Option<SharedString>,
 1284    pub color: PlayerColor,
 1285}
 1286
 1287#[derive(Clone, Debug)]
 1288struct SelectionHistoryEntry {
 1289    selections: Arc<[Selection<Anchor>]>,
 1290    select_next_state: Option<SelectNextState>,
 1291    select_prev_state: Option<SelectNextState>,
 1292    add_selections_state: Option<AddSelectionsState>,
 1293}
 1294
 1295#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1296enum SelectionHistoryMode {
 1297    Normal,
 1298    Undoing,
 1299    Redoing,
 1300    Skipping,
 1301}
 1302
 1303#[derive(Clone, PartialEq, Eq, Hash)]
 1304struct HoveredCursor {
 1305    replica_id: ReplicaId,
 1306    selection_id: usize,
 1307}
 1308
 1309impl Default for SelectionHistoryMode {
 1310    fn default() -> Self {
 1311        Self::Normal
 1312    }
 1313}
 1314
 1315#[derive(Debug)]
 1316/// SelectionEffects controls the side-effects of updating the selection.
 1317///
 1318/// The default behaviour does "what you mostly want":
 1319/// - it pushes to the nav history if the cursor moved by >10 lines
 1320/// - it re-triggers completion requests
 1321/// - it scrolls to fit
 1322///
 1323/// You might want to modify these behaviours. For example when doing a "jump"
 1324/// like go to definition, we always want to add to nav history; but when scrolling
 1325/// in vim mode we never do.
 1326///
 1327/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1328/// move.
 1329#[derive(Clone)]
 1330pub struct SelectionEffects {
 1331    nav_history: Option<bool>,
 1332    completions: bool,
 1333    scroll: Option<Autoscroll>,
 1334}
 1335
 1336impl Default for SelectionEffects {
 1337    fn default() -> Self {
 1338        Self {
 1339            nav_history: None,
 1340            completions: true,
 1341            scroll: Some(Autoscroll::fit()),
 1342        }
 1343    }
 1344}
 1345impl SelectionEffects {
 1346    pub fn scroll(scroll: Autoscroll) -> Self {
 1347        Self {
 1348            scroll: Some(scroll),
 1349            ..Default::default()
 1350        }
 1351    }
 1352
 1353    pub fn no_scroll() -> Self {
 1354        Self {
 1355            scroll: None,
 1356            ..Default::default()
 1357        }
 1358    }
 1359
 1360    pub fn completions(self, completions: bool) -> Self {
 1361        Self {
 1362            completions,
 1363            ..self
 1364        }
 1365    }
 1366
 1367    pub fn nav_history(self, nav_history: bool) -> Self {
 1368        Self {
 1369            nav_history: Some(nav_history),
 1370            ..self
 1371        }
 1372    }
 1373}
 1374
 1375struct DeferredSelectionEffectsState {
 1376    changed: bool,
 1377    effects: SelectionEffects,
 1378    old_cursor_position: Anchor,
 1379    history_entry: SelectionHistoryEntry,
 1380}
 1381
 1382#[derive(Default)]
 1383struct SelectionHistory {
 1384    #[allow(clippy::type_complexity)]
 1385    selections_by_transaction:
 1386        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1387    mode: SelectionHistoryMode,
 1388    undo_stack: VecDeque<SelectionHistoryEntry>,
 1389    redo_stack: VecDeque<SelectionHistoryEntry>,
 1390}
 1391
 1392impl SelectionHistory {
 1393    #[track_caller]
 1394    fn insert_transaction(
 1395        &mut self,
 1396        transaction_id: TransactionId,
 1397        selections: Arc<[Selection<Anchor>]>,
 1398    ) {
 1399        if selections.is_empty() {
 1400            log::error!(
 1401                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1402                std::panic::Location::caller()
 1403            );
 1404            return;
 1405        }
 1406        self.selections_by_transaction
 1407            .insert(transaction_id, (selections, None));
 1408    }
 1409
 1410    #[allow(clippy::type_complexity)]
 1411    fn transaction(
 1412        &self,
 1413        transaction_id: TransactionId,
 1414    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1415        self.selections_by_transaction.get(&transaction_id)
 1416    }
 1417
 1418    #[allow(clippy::type_complexity)]
 1419    fn transaction_mut(
 1420        &mut self,
 1421        transaction_id: TransactionId,
 1422    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1423        self.selections_by_transaction.get_mut(&transaction_id)
 1424    }
 1425
 1426    fn push(&mut self, entry: SelectionHistoryEntry) {
 1427        if !entry.selections.is_empty() {
 1428            match self.mode {
 1429                SelectionHistoryMode::Normal => {
 1430                    self.push_undo(entry);
 1431                    self.redo_stack.clear();
 1432                }
 1433                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1434                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1435                SelectionHistoryMode::Skipping => {}
 1436            }
 1437        }
 1438    }
 1439
 1440    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1441        if self
 1442            .undo_stack
 1443            .back()
 1444            .is_none_or(|e| e.selections != entry.selections)
 1445        {
 1446            self.undo_stack.push_back(entry);
 1447            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1448                self.undo_stack.pop_front();
 1449            }
 1450        }
 1451    }
 1452
 1453    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1454        if self
 1455            .redo_stack
 1456            .back()
 1457            .is_none_or(|e| e.selections != entry.selections)
 1458        {
 1459            self.redo_stack.push_back(entry);
 1460            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1461                self.redo_stack.pop_front();
 1462            }
 1463        }
 1464    }
 1465}
 1466
 1467#[derive(Clone, Copy)]
 1468pub struct RowHighlightOptions {
 1469    pub autoscroll: bool,
 1470    pub include_gutter: bool,
 1471}
 1472
 1473impl Default for RowHighlightOptions {
 1474    fn default() -> Self {
 1475        Self {
 1476            autoscroll: Default::default(),
 1477            include_gutter: true,
 1478        }
 1479    }
 1480}
 1481
 1482struct RowHighlight {
 1483    index: usize,
 1484    range: Range<Anchor>,
 1485    color: Hsla,
 1486    options: RowHighlightOptions,
 1487    type_id: TypeId,
 1488}
 1489
 1490#[derive(Clone, Debug)]
 1491struct AddSelectionsState {
 1492    groups: Vec<AddSelectionsGroup>,
 1493}
 1494
 1495#[derive(Clone, Debug)]
 1496struct AddSelectionsGroup {
 1497    above: bool,
 1498    stack: Vec<usize>,
 1499}
 1500
 1501#[derive(Clone)]
 1502struct SelectNextState {
 1503    query: AhoCorasick,
 1504    wordwise: bool,
 1505    done: bool,
 1506}
 1507
 1508impl std::fmt::Debug for SelectNextState {
 1509    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1510        f.debug_struct(std::any::type_name::<Self>())
 1511            .field("wordwise", &self.wordwise)
 1512            .field("done", &self.done)
 1513            .finish()
 1514    }
 1515}
 1516
 1517#[derive(Debug)]
 1518struct AutocloseRegion {
 1519    selection_id: usize,
 1520    range: Range<Anchor>,
 1521    pair: BracketPair,
 1522}
 1523
 1524#[derive(Debug)]
 1525struct SnippetState {
 1526    ranges: Vec<Vec<Range<Anchor>>>,
 1527    active_index: usize,
 1528    choices: Vec<Option<Vec<String>>>,
 1529}
 1530
 1531#[doc(hidden)]
 1532pub struct RenameState {
 1533    pub range: Range<Anchor>,
 1534    pub old_name: Arc<str>,
 1535    pub editor: Entity<Editor>,
 1536    block_id: CustomBlockId,
 1537}
 1538
 1539struct InvalidationStack<T>(Vec<T>);
 1540
 1541struct RegisteredEditPredictionProvider {
 1542    provider: Arc<dyn EditPredictionProviderHandle>,
 1543    _subscription: Subscription,
 1544}
 1545
 1546#[derive(Debug, PartialEq, Eq)]
 1547pub struct ActiveDiagnosticGroup {
 1548    pub active_range: Range<Anchor>,
 1549    pub active_message: String,
 1550    pub group_id: usize,
 1551    pub blocks: HashSet<CustomBlockId>,
 1552}
 1553
 1554#[derive(Debug, PartialEq, Eq)]
 1555
 1556pub(crate) enum ActiveDiagnostic {
 1557    None,
 1558    All,
 1559    Group(ActiveDiagnosticGroup),
 1560}
 1561
 1562#[derive(Serialize, Deserialize, Clone, Debug)]
 1563pub struct ClipboardSelection {
 1564    /// The number of bytes in this selection.
 1565    pub len: usize,
 1566    /// Whether this was a full-line selection.
 1567    pub is_entire_line: bool,
 1568    /// The indentation of the first line when this content was originally copied.
 1569    pub first_line_indent: u32,
 1570}
 1571
 1572// selections, scroll behavior, was newest selection reversed
 1573type SelectSyntaxNodeHistoryState = (
 1574    Box<[Selection<usize>]>,
 1575    SelectSyntaxNodeScrollBehavior,
 1576    bool,
 1577);
 1578
 1579#[derive(Default)]
 1580struct SelectSyntaxNodeHistory {
 1581    stack: Vec<SelectSyntaxNodeHistoryState>,
 1582    // disable temporarily to allow changing selections without losing the stack
 1583    pub disable_clearing: bool,
 1584}
 1585
 1586impl SelectSyntaxNodeHistory {
 1587    pub fn try_clear(&mut self) {
 1588        if !self.disable_clearing {
 1589            self.stack.clear();
 1590        }
 1591    }
 1592
 1593    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1594        self.stack.push(selection);
 1595    }
 1596
 1597    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1598        self.stack.pop()
 1599    }
 1600}
 1601
 1602enum SelectSyntaxNodeScrollBehavior {
 1603    CursorTop,
 1604    FitSelection,
 1605    CursorBottom,
 1606}
 1607
 1608#[derive(Debug)]
 1609pub(crate) struct NavigationData {
 1610    cursor_anchor: Anchor,
 1611    cursor_position: Point,
 1612    scroll_anchor: ScrollAnchor,
 1613    scroll_top_row: u32,
 1614}
 1615
 1616#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1617pub enum GotoDefinitionKind {
 1618    Symbol,
 1619    Declaration,
 1620    Type,
 1621    Implementation,
 1622}
 1623
 1624#[derive(Debug, Clone)]
 1625enum InlayHintRefreshReason {
 1626    ModifiersChanged(bool),
 1627    Toggle(bool),
 1628    SettingsChange(InlayHintSettings),
 1629    NewLinesShown,
 1630    BufferEdited(HashSet<Arc<Language>>),
 1631    RefreshRequested,
 1632    ExcerptsRemoved(Vec<ExcerptId>),
 1633}
 1634
 1635impl InlayHintRefreshReason {
 1636    fn description(&self) -> &'static str {
 1637        match self {
 1638            Self::ModifiersChanged(_) => "modifiers changed",
 1639            Self::Toggle(_) => "toggle",
 1640            Self::SettingsChange(_) => "settings change",
 1641            Self::NewLinesShown => "new lines shown",
 1642            Self::BufferEdited(_) => "buffer edited",
 1643            Self::RefreshRequested => "refresh requested",
 1644            Self::ExcerptsRemoved(_) => "excerpts removed",
 1645        }
 1646    }
 1647}
 1648
 1649pub enum FormatTarget {
 1650    Buffers(HashSet<Entity<Buffer>>),
 1651    Ranges(Vec<Range<MultiBufferPoint>>),
 1652}
 1653
 1654pub(crate) struct FocusedBlock {
 1655    id: BlockId,
 1656    focus_handle: WeakFocusHandle,
 1657}
 1658
 1659#[derive(Clone)]
 1660enum JumpData {
 1661    MultiBufferRow {
 1662        row: MultiBufferRow,
 1663        line_offset_from_top: u32,
 1664    },
 1665    MultiBufferPoint {
 1666        excerpt_id: ExcerptId,
 1667        position: Point,
 1668        anchor: text::Anchor,
 1669        line_offset_from_top: u32,
 1670    },
 1671}
 1672
 1673pub enum MultibufferSelectionMode {
 1674    First,
 1675    All,
 1676}
 1677
 1678#[derive(Clone, Copy, Debug, Default)]
 1679pub struct RewrapOptions {
 1680    pub override_language_settings: bool,
 1681    pub preserve_existing_whitespace: bool,
 1682}
 1683
 1684impl Editor {
 1685    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1686        let buffer = cx.new(|cx| Buffer::local("", cx));
 1687        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1688        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1689    }
 1690
 1691    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1692        let buffer = cx.new(|cx| Buffer::local("", cx));
 1693        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1694        Self::new(EditorMode::full(), buffer, None, window, cx)
 1695    }
 1696
 1697    pub fn auto_height(
 1698        min_lines: usize,
 1699        max_lines: usize,
 1700        window: &mut Window,
 1701        cx: &mut Context<Self>,
 1702    ) -> Self {
 1703        let buffer = cx.new(|cx| Buffer::local("", cx));
 1704        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1705        Self::new(
 1706            EditorMode::AutoHeight {
 1707                min_lines,
 1708                max_lines: Some(max_lines),
 1709            },
 1710            buffer,
 1711            None,
 1712            window,
 1713            cx,
 1714        )
 1715    }
 1716
 1717    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1718    /// The editor grows as tall as needed to fit its content.
 1719    pub fn auto_height_unbounded(
 1720        min_lines: usize,
 1721        window: &mut Window,
 1722        cx: &mut Context<Self>,
 1723    ) -> Self {
 1724        let buffer = cx.new(|cx| Buffer::local("", cx));
 1725        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1726        Self::new(
 1727            EditorMode::AutoHeight {
 1728                min_lines,
 1729                max_lines: None,
 1730            },
 1731            buffer,
 1732            None,
 1733            window,
 1734            cx,
 1735        )
 1736    }
 1737
 1738    pub fn for_buffer(
 1739        buffer: Entity<Buffer>,
 1740        project: Option<Entity<Project>>,
 1741        window: &mut Window,
 1742        cx: &mut Context<Self>,
 1743    ) -> Self {
 1744        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1745        Self::new(EditorMode::full(), buffer, project, window, cx)
 1746    }
 1747
 1748    pub fn for_multibuffer(
 1749        buffer: Entity<MultiBuffer>,
 1750        project: Option<Entity<Project>>,
 1751        window: &mut Window,
 1752        cx: &mut Context<Self>,
 1753    ) -> Self {
 1754        Self::new(EditorMode::full(), buffer, project, window, cx)
 1755    }
 1756
 1757    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1758        let mut clone = Self::new(
 1759            self.mode.clone(),
 1760            self.buffer.clone(),
 1761            self.project.clone(),
 1762            window,
 1763            cx,
 1764        );
 1765        self.display_map.update(cx, |display_map, cx| {
 1766            let snapshot = display_map.snapshot(cx);
 1767            clone.display_map.update(cx, |display_map, cx| {
 1768                display_map.set_state(&snapshot, cx);
 1769            });
 1770        });
 1771        clone.folds_did_change(cx);
 1772        clone.selections.clone_state(&self.selections);
 1773        clone.scroll_manager.clone_state(&self.scroll_manager);
 1774        clone.searchable = self.searchable;
 1775        clone.read_only = self.read_only;
 1776        clone
 1777    }
 1778
 1779    pub fn new(
 1780        mode: EditorMode,
 1781        buffer: Entity<MultiBuffer>,
 1782        project: Option<Entity<Project>>,
 1783        window: &mut Window,
 1784        cx: &mut Context<Self>,
 1785    ) -> Self {
 1786        Editor::new_internal(mode, buffer, project, None, window, cx)
 1787    }
 1788
 1789    fn new_internal(
 1790        mode: EditorMode,
 1791        multi_buffer: Entity<MultiBuffer>,
 1792        project: Option<Entity<Project>>,
 1793        display_map: Option<Entity<DisplayMap>>,
 1794        window: &mut Window,
 1795        cx: &mut Context<Self>,
 1796    ) -> Self {
 1797        debug_assert!(
 1798            display_map.is_none() || mode.is_minimap(),
 1799            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1800        );
 1801
 1802        let full_mode = mode.is_full();
 1803        let is_minimap = mode.is_minimap();
 1804        let diagnostics_max_severity = if full_mode {
 1805            EditorSettings::get_global(cx)
 1806                .diagnostics_max_severity
 1807                .unwrap_or(DiagnosticSeverity::Hint)
 1808        } else {
 1809            DiagnosticSeverity::Off
 1810        };
 1811        let style = window.text_style();
 1812        let font_size = style.font_size.to_pixels(window.rem_size());
 1813        let editor = cx.entity().downgrade();
 1814        let fold_placeholder = FoldPlaceholder {
 1815            constrain_width: false,
 1816            render: Arc::new(move |fold_id, fold_range, cx| {
 1817                let editor = editor.clone();
 1818                div()
 1819                    .id(fold_id)
 1820                    .bg(cx.theme().colors().ghost_element_background)
 1821                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1822                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1823                    .rounded_xs()
 1824                    .size_full()
 1825                    .cursor_pointer()
 1826                    .child("")
 1827                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1828                    .on_click(move |_, _window, cx| {
 1829                        editor
 1830                            .update(cx, |editor, cx| {
 1831                                editor.unfold_ranges(
 1832                                    &[fold_range.start..fold_range.end],
 1833                                    true,
 1834                                    false,
 1835                                    cx,
 1836                                );
 1837                                cx.stop_propagation();
 1838                            })
 1839                            .ok();
 1840                    })
 1841                    .into_any()
 1842            }),
 1843            merge_adjacent: true,
 1844            ..FoldPlaceholder::default()
 1845        };
 1846        let display_map = display_map.unwrap_or_else(|| {
 1847            cx.new(|cx| {
 1848                DisplayMap::new(
 1849                    multi_buffer.clone(),
 1850                    style.font(),
 1851                    font_size,
 1852                    None,
 1853                    FILE_HEADER_HEIGHT,
 1854                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1855                    fold_placeholder,
 1856                    diagnostics_max_severity,
 1857                    cx,
 1858                )
 1859            })
 1860        });
 1861
 1862        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1863
 1864        let blink_manager = cx.new(|cx| {
 1865            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1866            if is_minimap {
 1867                blink_manager.disable(cx);
 1868            }
 1869            blink_manager
 1870        });
 1871
 1872        let soft_wrap_mode_override =
 1873            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1874
 1875        let mut project_subscriptions = Vec::new();
 1876        if full_mode && let Some(project) = project.as_ref() {
 1877            project_subscriptions.push(cx.subscribe_in(
 1878                project,
 1879                window,
 1880                |editor, _, event, window, cx| match event {
 1881                    project::Event::RefreshCodeLens => {
 1882                        // we always query lens with actions, without storing them, always refreshing them
 1883                    }
 1884                    project::Event::RefreshInlayHints => {
 1885                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1886                    }
 1887                    project::Event::LanguageServerRemoved(..) => {
 1888                        if editor.tasks_update_task.is_none() {
 1889                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1890                        }
 1891                        editor.registered_buffers.clear();
 1892                        editor.register_visible_buffers(cx);
 1893                    }
 1894                    project::Event::LanguageServerAdded(..) => {
 1895                        if editor.tasks_update_task.is_none() {
 1896                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1897                        }
 1898                    }
 1899                    project::Event::SnippetEdit(id, snippet_edits) => {
 1900                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1901                            let focus_handle = editor.focus_handle(cx);
 1902                            if focus_handle.is_focused(window) {
 1903                                let snapshot = buffer.read(cx).snapshot();
 1904                                for (range, snippet) in snippet_edits {
 1905                                    let editor_range =
 1906                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1907                                    editor
 1908                                        .insert_snippet(
 1909                                            &[editor_range],
 1910                                            snippet.clone(),
 1911                                            window,
 1912                                            cx,
 1913                                        )
 1914                                        .ok();
 1915                                }
 1916                            }
 1917                        }
 1918                    }
 1919                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1920                        let buffer_id = *buffer_id;
 1921                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1922                            let registered = editor.register_buffer(buffer_id, cx);
 1923                            if registered {
 1924                                editor.update_lsp_data(Some(buffer_id), window, cx);
 1925                                editor.refresh_inlay_hints(
 1926                                    InlayHintRefreshReason::RefreshRequested,
 1927                                    cx,
 1928                                );
 1929                                refresh_linked_ranges(editor, window, cx);
 1930                                editor.refresh_code_actions(window, cx);
 1931                                editor.refresh_document_highlights(cx);
 1932                            }
 1933                        }
 1934                    }
 1935
 1936                    project::Event::EntryRenamed(transaction) => {
 1937                        let Some(workspace) = editor.workspace() else {
 1938                            return;
 1939                        };
 1940                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1941                        else {
 1942                            return;
 1943                        };
 1944                        if active_editor.entity_id() == cx.entity_id() {
 1945                            let edited_buffers_already_open = {
 1946                                let other_editors: Vec<Entity<Editor>> = workspace
 1947                                    .read(cx)
 1948                                    .panes()
 1949                                    .iter()
 1950                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1951                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1952                                    .collect();
 1953
 1954                                transaction.0.keys().all(|buffer| {
 1955                                    other_editors.iter().any(|editor| {
 1956                                        let multi_buffer = editor.read(cx).buffer();
 1957                                        multi_buffer.read(cx).is_singleton()
 1958                                            && multi_buffer.read(cx).as_singleton().map_or(
 1959                                                false,
 1960                                                |singleton| {
 1961                                                    singleton.entity_id() == buffer.entity_id()
 1962                                                },
 1963                                            )
 1964                                    })
 1965                                })
 1966                            };
 1967
 1968                            if !edited_buffers_already_open {
 1969                                let workspace = workspace.downgrade();
 1970                                let transaction = transaction.clone();
 1971                                cx.defer_in(window, move |_, window, cx| {
 1972                                    cx.spawn_in(window, async move |editor, cx| {
 1973                                        Self::open_project_transaction(
 1974                                            &editor,
 1975                                            workspace,
 1976                                            transaction,
 1977                                            "Rename".to_string(),
 1978                                            cx,
 1979                                        )
 1980                                        .await
 1981                                        .ok()
 1982                                    })
 1983                                    .detach();
 1984                                });
 1985                            }
 1986                        }
 1987                    }
 1988
 1989                    _ => {}
 1990                },
 1991            ));
 1992            if let Some(task_inventory) = project
 1993                .read(cx)
 1994                .task_store()
 1995                .read(cx)
 1996                .task_inventory()
 1997                .cloned()
 1998            {
 1999                project_subscriptions.push(cx.observe_in(
 2000                    &task_inventory,
 2001                    window,
 2002                    |editor, _, window, cx| {
 2003                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2004                    },
 2005                ));
 2006            };
 2007
 2008            project_subscriptions.push(cx.subscribe_in(
 2009                &project.read(cx).breakpoint_store(),
 2010                window,
 2011                |editor, _, event, window, cx| match event {
 2012                    BreakpointStoreEvent::ClearDebugLines => {
 2013                        editor.clear_row_highlights::<ActiveDebugLine>();
 2014                        editor.refresh_inline_values(cx);
 2015                    }
 2016                    BreakpointStoreEvent::SetDebugLine => {
 2017                        if editor.go_to_active_debug_line(window, cx) {
 2018                            cx.stop_propagation();
 2019                        }
 2020
 2021                        editor.refresh_inline_values(cx);
 2022                    }
 2023                    _ => {}
 2024                },
 2025            ));
 2026            let git_store = project.read(cx).git_store().clone();
 2027            let project = project.clone();
 2028            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2029                if let GitStoreEvent::RepositoryUpdated(
 2030                    _,
 2031                    RepositoryEvent::Updated {
 2032                        new_instance: true, ..
 2033                    },
 2034                    _,
 2035                ) = event
 2036                {
 2037                    this.load_diff_task = Some(
 2038                        update_uncommitted_diff_for_buffer(
 2039                            cx.entity(),
 2040                            &project,
 2041                            this.buffer.read(cx).all_buffers(),
 2042                            this.buffer.clone(),
 2043                            cx,
 2044                        )
 2045                        .shared(),
 2046                    );
 2047                }
 2048            }));
 2049        }
 2050
 2051        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2052
 2053        let inlay_hint_settings =
 2054            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2055        let focus_handle = cx.focus_handle();
 2056        if !is_minimap {
 2057            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2058                .detach();
 2059            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2060                .detach();
 2061            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2062                .detach();
 2063            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2064                .detach();
 2065            cx.observe_pending_input(window, Self::observe_pending_input)
 2066                .detach();
 2067        }
 2068
 2069        let show_indent_guides =
 2070            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2071                Some(false)
 2072            } else {
 2073                None
 2074            };
 2075
 2076        let breakpoint_store = match (&mode, project.as_ref()) {
 2077            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2078            _ => None,
 2079        };
 2080
 2081        let mut code_action_providers = Vec::new();
 2082        let mut load_uncommitted_diff = None;
 2083        if let Some(project) = project.clone() {
 2084            load_uncommitted_diff = Some(
 2085                update_uncommitted_diff_for_buffer(
 2086                    cx.entity(),
 2087                    &project,
 2088                    multi_buffer.read(cx).all_buffers(),
 2089                    multi_buffer.clone(),
 2090                    cx,
 2091                )
 2092                .shared(),
 2093            );
 2094            code_action_providers.push(Rc::new(project) as Rc<_>);
 2095        }
 2096
 2097        let mut editor = Self {
 2098            focus_handle,
 2099            show_cursor_when_unfocused: false,
 2100            last_focused_descendant: None,
 2101            buffer: multi_buffer.clone(),
 2102            display_map: display_map.clone(),
 2103            placeholder_display_map: None,
 2104            selections,
 2105            scroll_manager: ScrollManager::new(cx),
 2106            columnar_selection_state: None,
 2107            add_selections_state: None,
 2108            select_next_state: None,
 2109            select_prev_state: None,
 2110            selection_history: SelectionHistory::default(),
 2111            defer_selection_effects: false,
 2112            deferred_selection_effects_state: None,
 2113            autoclose_regions: Vec::new(),
 2114            snippet_stack: InvalidationStack::default(),
 2115            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2116            ime_transaction: None,
 2117            active_diagnostics: ActiveDiagnostic::None,
 2118            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2119            inline_diagnostics_update: Task::ready(()),
 2120            inline_diagnostics: Vec::new(),
 2121            soft_wrap_mode_override,
 2122            diagnostics_max_severity,
 2123            hard_wrap: None,
 2124            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2125            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2126            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2127            project,
 2128            blink_manager: blink_manager.clone(),
 2129            show_local_selections: true,
 2130            show_scrollbars: ScrollbarAxes {
 2131                horizontal: full_mode,
 2132                vertical: full_mode,
 2133            },
 2134            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2135            offset_content: !matches!(mode, EditorMode::SingleLine),
 2136            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2137            show_gutter: full_mode,
 2138            show_line_numbers: (!full_mode).then_some(false),
 2139            use_relative_line_numbers: None,
 2140            disable_expand_excerpt_buttons: !full_mode,
 2141            show_git_diff_gutter: None,
 2142            show_code_actions: None,
 2143            show_runnables: None,
 2144            show_breakpoints: None,
 2145            show_wrap_guides: None,
 2146            show_indent_guides,
 2147            highlight_order: 0,
 2148            highlighted_rows: HashMap::default(),
 2149            background_highlights: HashMap::default(),
 2150            gutter_highlights: HashMap::default(),
 2151            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2152            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2153            nav_history: None,
 2154            context_menu: RefCell::new(None),
 2155            context_menu_options: None,
 2156            mouse_context_menu: None,
 2157            completion_tasks: Vec::new(),
 2158            inline_blame_popover: None,
 2159            inline_blame_popover_show_task: None,
 2160            signature_help_state: SignatureHelpState::default(),
 2161            auto_signature_help: None,
 2162            find_all_references_task_sources: Vec::new(),
 2163            next_completion_id: 0,
 2164            next_inlay_id: 0,
 2165            code_action_providers,
 2166            available_code_actions: None,
 2167            code_actions_task: None,
 2168            quick_selection_highlight_task: None,
 2169            debounced_selection_highlight_task: None,
 2170            document_highlights_task: None,
 2171            linked_editing_range_task: None,
 2172            pending_rename: None,
 2173            searchable: !is_minimap,
 2174            cursor_shape: EditorSettings::get_global(cx)
 2175                .cursor_shape
 2176                .unwrap_or_default(),
 2177            current_line_highlight: None,
 2178            autoindent_mode: Some(AutoindentMode::EachLine),
 2179            collapse_matches: false,
 2180            workspace: None,
 2181            input_enabled: !is_minimap,
 2182            use_modal_editing: full_mode,
 2183            read_only: is_minimap,
 2184            use_autoclose: true,
 2185            use_auto_surround: true,
 2186            auto_replace_emoji_shortcode: false,
 2187            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2188            leader_id: None,
 2189            remote_id: None,
 2190            hover_state: HoverState::default(),
 2191            pending_mouse_down: None,
 2192            hovered_link_state: None,
 2193            edit_prediction_provider: None,
 2194            active_edit_prediction: None,
 2195            stale_edit_prediction_in_menu: None,
 2196            edit_prediction_preview: EditPredictionPreview::Inactive {
 2197                released_too_fast: false,
 2198            },
 2199            inline_diagnostics_enabled: full_mode,
 2200            diagnostics_enabled: full_mode,
 2201            word_completions_enabled: full_mode,
 2202            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2203            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2204            gutter_hovered: false,
 2205            pixel_position_of_newest_cursor: None,
 2206            last_bounds: None,
 2207            last_position_map: None,
 2208            expect_bounds_change: None,
 2209            gutter_dimensions: GutterDimensions::default(),
 2210            style: None,
 2211            show_cursor_names: false,
 2212            hovered_cursors: HashMap::default(),
 2213            next_editor_action_id: EditorActionId::default(),
 2214            editor_actions: Rc::default(),
 2215            edit_predictions_hidden_for_vim_mode: false,
 2216            show_edit_predictions_override: None,
 2217            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2218            edit_prediction_settings: EditPredictionSettings::Disabled,
 2219            edit_prediction_indent_conflict: false,
 2220            edit_prediction_requires_modifier_in_indent_conflict: true,
 2221            custom_context_menu: None,
 2222            show_git_blame_gutter: false,
 2223            show_git_blame_inline: false,
 2224            show_selection_menu: None,
 2225            show_git_blame_inline_delay_task: None,
 2226            git_blame_inline_enabled: full_mode
 2227                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2228            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2229            serialize_dirty_buffers: !is_minimap
 2230                && ProjectSettings::get_global(cx)
 2231                    .session
 2232                    .restore_unsaved_buffers,
 2233            blame: None,
 2234            blame_subscription: None,
 2235            tasks: BTreeMap::default(),
 2236
 2237            breakpoint_store,
 2238            gutter_breakpoint_indicator: (None, None),
 2239            hovered_diff_hunk_row: None,
 2240            _subscriptions: (!is_minimap)
 2241                .then(|| {
 2242                    vec![
 2243                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2244                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2245                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2246                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2247                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2248                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2249                        cx.observe_window_activation(window, |editor, window, cx| {
 2250                            let active = window.is_window_active();
 2251                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2252                                if active {
 2253                                    blink_manager.enable(cx);
 2254                                } else {
 2255                                    blink_manager.disable(cx);
 2256                                }
 2257                            });
 2258                            if active {
 2259                                editor.show_mouse_cursor(cx);
 2260                            }
 2261                        }),
 2262                    ]
 2263                })
 2264                .unwrap_or_default(),
 2265            tasks_update_task: None,
 2266            pull_diagnostics_task: Task::ready(()),
 2267            colors: None,
 2268            refresh_colors_task: Task::ready(()),
 2269            next_color_inlay_id: 0,
 2270            post_scroll_update: Task::ready(()),
 2271            linked_edit_ranges: Default::default(),
 2272            in_project_search: false,
 2273            previous_search_ranges: None,
 2274            breadcrumb_header: None,
 2275            focused_block: None,
 2276            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2277            addons: HashMap::default(),
 2278            registered_buffers: HashMap::default(),
 2279            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2280            selection_mark_mode: false,
 2281            toggle_fold_multiple_buffers: Task::ready(()),
 2282            serialize_selections: Task::ready(()),
 2283            serialize_folds: Task::ready(()),
 2284            text_style_refinement: None,
 2285            load_diff_task: load_uncommitted_diff,
 2286            temporary_diff_override: false,
 2287            mouse_cursor_hidden: false,
 2288            minimap: None,
 2289            hide_mouse_mode: EditorSettings::get_global(cx)
 2290                .hide_mouse
 2291                .unwrap_or_default(),
 2292            change_list: ChangeList::new(),
 2293            mode,
 2294            selection_drag_state: SelectionDragState::None,
 2295            folding_newlines: Task::ready(()),
 2296            lookup_key: None,
 2297        };
 2298
 2299        if is_minimap {
 2300            return editor;
 2301        }
 2302
 2303        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2304            editor
 2305                ._subscriptions
 2306                .push(cx.observe(breakpoints, |_, _, cx| {
 2307                    cx.notify();
 2308                }));
 2309        }
 2310        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2311        editor._subscriptions.extend(project_subscriptions);
 2312
 2313        editor._subscriptions.push(cx.subscribe_in(
 2314            &cx.entity(),
 2315            window,
 2316            |editor, _, e: &EditorEvent, window, cx| match e {
 2317                EditorEvent::ScrollPositionChanged { local, .. } => {
 2318                    if *local {
 2319                        let new_anchor = editor.scroll_manager.anchor();
 2320                        let snapshot = editor.snapshot(window, cx);
 2321                        editor.update_restoration_data(cx, move |data| {
 2322                            data.scroll_position = (
 2323                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2324                                new_anchor.offset,
 2325                            );
 2326                        });
 2327                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2328                        editor.inline_blame_popover.take();
 2329                    }
 2330                }
 2331                EditorEvent::Edited { .. } => {
 2332                    if !vim_enabled(cx) {
 2333                        let display_map = editor.display_snapshot(cx);
 2334                        let selections = editor.selections.all_adjusted_display(&display_map);
 2335                        let pop_state = editor
 2336                            .change_list
 2337                            .last()
 2338                            .map(|previous| {
 2339                                previous.len() == selections.len()
 2340                                    && previous.iter().enumerate().all(|(ix, p)| {
 2341                                        p.to_display_point(&display_map).row()
 2342                                            == selections[ix].head().row()
 2343                                    })
 2344                            })
 2345                            .unwrap_or(false);
 2346                        let new_positions = selections
 2347                            .into_iter()
 2348                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2349                            .collect();
 2350                        editor
 2351                            .change_list
 2352                            .push_to_change_list(pop_state, new_positions);
 2353                    }
 2354                }
 2355                _ => (),
 2356            },
 2357        ));
 2358
 2359        if let Some(dap_store) = editor
 2360            .project
 2361            .as_ref()
 2362            .map(|project| project.read(cx).dap_store())
 2363        {
 2364            let weak_editor = cx.weak_entity();
 2365
 2366            editor
 2367                ._subscriptions
 2368                .push(
 2369                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2370                        let session_entity = cx.entity();
 2371                        weak_editor
 2372                            .update(cx, |editor, cx| {
 2373                                editor._subscriptions.push(
 2374                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2375                                );
 2376                            })
 2377                            .ok();
 2378                    }),
 2379                );
 2380
 2381            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2382                editor
 2383                    ._subscriptions
 2384                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2385            }
 2386        }
 2387
 2388        // skip adding the initial selection to selection history
 2389        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2390        editor.end_selection(window, cx);
 2391        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2392
 2393        editor.scroll_manager.show_scrollbars(window, cx);
 2394        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2395
 2396        if full_mode {
 2397            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2398            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2399
 2400            if editor.git_blame_inline_enabled {
 2401                editor.start_git_blame_inline(false, window, cx);
 2402            }
 2403
 2404            editor.go_to_active_debug_line(window, cx);
 2405
 2406            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2407                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2408            }
 2409
 2410            editor.minimap =
 2411                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2412            editor.colors = Some(LspColorData::new(cx));
 2413            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2414        }
 2415
 2416        editor
 2417    }
 2418
 2419    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2420        self.selections.display_map(cx)
 2421    }
 2422
 2423    pub fn deploy_mouse_context_menu(
 2424        &mut self,
 2425        position: gpui::Point<Pixels>,
 2426        context_menu: Entity<ContextMenu>,
 2427        window: &mut Window,
 2428        cx: &mut Context<Self>,
 2429    ) {
 2430        self.mouse_context_menu = Some(MouseContextMenu::new(
 2431            self,
 2432            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2433            context_menu,
 2434            window,
 2435            cx,
 2436        ));
 2437    }
 2438
 2439    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2440        self.mouse_context_menu
 2441            .as_ref()
 2442            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2443    }
 2444
 2445    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2446        if self
 2447            .selections
 2448            .pending_anchor()
 2449            .is_some_and(|pending_selection| {
 2450                let snapshot = self.buffer().read(cx).snapshot(cx);
 2451                pending_selection.range().includes(range, &snapshot)
 2452            })
 2453        {
 2454            return true;
 2455        }
 2456
 2457        self.selections
 2458            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2459            .into_iter()
 2460            .any(|selection| {
 2461                // This is needed to cover a corner case, if we just check for an existing
 2462                // selection in the fold range, having a cursor at the start of the fold
 2463                // marks it as selected. Non-empty selections don't cause this.
 2464                let length = selection.end - selection.start;
 2465                length > 0
 2466            })
 2467    }
 2468
 2469    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2470        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2471    }
 2472
 2473    fn key_context_internal(
 2474        &self,
 2475        has_active_edit_prediction: bool,
 2476        window: &mut Window,
 2477        cx: &mut App,
 2478    ) -> KeyContext {
 2479        let mut key_context = KeyContext::new_with_defaults();
 2480        key_context.add("Editor");
 2481        let mode = match self.mode {
 2482            EditorMode::SingleLine => "single_line",
 2483            EditorMode::AutoHeight { .. } => "auto_height",
 2484            EditorMode::Minimap { .. } => "minimap",
 2485            EditorMode::Full { .. } => "full",
 2486        };
 2487
 2488        if EditorSettings::jupyter_enabled(cx) {
 2489            key_context.add("jupyter");
 2490        }
 2491
 2492        key_context.set("mode", mode);
 2493        if self.pending_rename.is_some() {
 2494            key_context.add("renaming");
 2495        }
 2496
 2497        match self.context_menu.borrow().as_ref() {
 2498            Some(CodeContextMenu::Completions(menu)) => {
 2499                if menu.visible() {
 2500                    key_context.add("menu");
 2501                    key_context.add("showing_completions");
 2502                }
 2503            }
 2504            Some(CodeContextMenu::CodeActions(menu)) => {
 2505                if menu.visible() {
 2506                    key_context.add("menu");
 2507                    key_context.add("showing_code_actions")
 2508                }
 2509            }
 2510            None => {}
 2511        }
 2512
 2513        if self.signature_help_state.has_multiple_signatures() {
 2514            key_context.add("showing_signature_help");
 2515        }
 2516
 2517        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2518        if !self.focus_handle(cx).contains_focused(window, cx)
 2519            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2520        {
 2521            for addon in self.addons.values() {
 2522                addon.extend_key_context(&mut key_context, cx)
 2523            }
 2524        }
 2525
 2526        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2527            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2528                Some(
 2529                    file.full_path(cx)
 2530                        .extension()?
 2531                        .to_string_lossy()
 2532                        .into_owned(),
 2533                )
 2534            }) {
 2535                key_context.set("extension", extension);
 2536            }
 2537        } else {
 2538            key_context.add("multibuffer");
 2539        }
 2540
 2541        if has_active_edit_prediction {
 2542            if self.edit_prediction_in_conflict() {
 2543                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2544            } else {
 2545                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2546                key_context.add("copilot_suggestion");
 2547            }
 2548        }
 2549
 2550        if self.selection_mark_mode {
 2551            key_context.add("selection_mode");
 2552        }
 2553
 2554        let disjoint = self.selections.disjoint_anchors();
 2555        let snapshot = self.snapshot(window, cx);
 2556        let snapshot = snapshot.buffer_snapshot();
 2557        if self.mode == EditorMode::SingleLine
 2558            && let [selection] = disjoint
 2559            && selection.start == selection.end
 2560            && selection.end.to_offset(snapshot) == snapshot.len()
 2561        {
 2562            key_context.add("end_of_input");
 2563        }
 2564
 2565        key_context
 2566    }
 2567
 2568    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2569        self.last_bounds.as_ref()
 2570    }
 2571
 2572    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2573        if self.mouse_cursor_hidden {
 2574            self.mouse_cursor_hidden = false;
 2575            cx.notify();
 2576        }
 2577    }
 2578
 2579    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2580        let hide_mouse_cursor = match origin {
 2581            HideMouseCursorOrigin::TypingAction => {
 2582                matches!(
 2583                    self.hide_mouse_mode,
 2584                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2585                )
 2586            }
 2587            HideMouseCursorOrigin::MovementAction => {
 2588                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2589            }
 2590        };
 2591        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2592            self.mouse_cursor_hidden = hide_mouse_cursor;
 2593            cx.notify();
 2594        }
 2595    }
 2596
 2597    pub fn edit_prediction_in_conflict(&self) -> bool {
 2598        if !self.show_edit_predictions_in_menu() {
 2599            return false;
 2600        }
 2601
 2602        let showing_completions = self
 2603            .context_menu
 2604            .borrow()
 2605            .as_ref()
 2606            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2607
 2608        showing_completions
 2609            || self.edit_prediction_requires_modifier()
 2610            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2611            // bindings to insert tab characters.
 2612            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2613    }
 2614
 2615    pub fn accept_edit_prediction_keybind(
 2616        &self,
 2617        accept_partial: bool,
 2618        window: &mut Window,
 2619        cx: &mut App,
 2620    ) -> AcceptEditPredictionBinding {
 2621        let key_context = self.key_context_internal(true, window, cx);
 2622        let in_conflict = self.edit_prediction_in_conflict();
 2623
 2624        let bindings = if accept_partial {
 2625            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2626        } else {
 2627            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2628        };
 2629
 2630        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2631        // just the first one.
 2632        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2633            !in_conflict
 2634                || binding
 2635                    .keystrokes()
 2636                    .first()
 2637                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2638        }))
 2639    }
 2640
 2641    pub fn new_file(
 2642        workspace: &mut Workspace,
 2643        _: &workspace::NewFile,
 2644        window: &mut Window,
 2645        cx: &mut Context<Workspace>,
 2646    ) {
 2647        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2648            "Failed to create buffer",
 2649            window,
 2650            cx,
 2651            |e, _, _| match e.error_code() {
 2652                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2653                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2654                e.error_tag("required").unwrap_or("the latest version")
 2655            )),
 2656                _ => None,
 2657            },
 2658        );
 2659    }
 2660
 2661    pub fn new_in_workspace(
 2662        workspace: &mut Workspace,
 2663        window: &mut Window,
 2664        cx: &mut Context<Workspace>,
 2665    ) -> Task<Result<Entity<Editor>>> {
 2666        let project = workspace.project().clone();
 2667        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2668
 2669        cx.spawn_in(window, async move |workspace, cx| {
 2670            let buffer = create.await?;
 2671            workspace.update_in(cx, |workspace, window, cx| {
 2672                let editor =
 2673                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2674                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2675                editor
 2676            })
 2677        })
 2678    }
 2679
 2680    fn new_file_vertical(
 2681        workspace: &mut Workspace,
 2682        _: &workspace::NewFileSplitVertical,
 2683        window: &mut Window,
 2684        cx: &mut Context<Workspace>,
 2685    ) {
 2686        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2687    }
 2688
 2689    fn new_file_horizontal(
 2690        workspace: &mut Workspace,
 2691        _: &workspace::NewFileSplitHorizontal,
 2692        window: &mut Window,
 2693        cx: &mut Context<Workspace>,
 2694    ) {
 2695        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2696    }
 2697
 2698    fn new_file_split(
 2699        workspace: &mut Workspace,
 2700        action: &workspace::NewFileSplit,
 2701        window: &mut Window,
 2702        cx: &mut Context<Workspace>,
 2703    ) {
 2704        Self::new_file_in_direction(workspace, action.0, window, cx)
 2705    }
 2706
 2707    fn new_file_in_direction(
 2708        workspace: &mut Workspace,
 2709        direction: SplitDirection,
 2710        window: &mut Window,
 2711        cx: &mut Context<Workspace>,
 2712    ) {
 2713        let project = workspace.project().clone();
 2714        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2715
 2716        cx.spawn_in(window, async move |workspace, cx| {
 2717            let buffer = create.await?;
 2718            workspace.update_in(cx, move |workspace, window, cx| {
 2719                workspace.split_item(
 2720                    direction,
 2721                    Box::new(
 2722                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2723                    ),
 2724                    window,
 2725                    cx,
 2726                )
 2727            })?;
 2728            anyhow::Ok(())
 2729        })
 2730        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2731            match e.error_code() {
 2732                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2733                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2734                e.error_tag("required").unwrap_or("the latest version")
 2735            )),
 2736                _ => None,
 2737            }
 2738        });
 2739    }
 2740
 2741    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2742        self.leader_id
 2743    }
 2744
 2745    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2746        &self.buffer
 2747    }
 2748
 2749    pub fn project(&self) -> Option<&Entity<Project>> {
 2750        self.project.as_ref()
 2751    }
 2752
 2753    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2754        self.workspace.as_ref()?.0.upgrade()
 2755    }
 2756
 2757    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2758        self.buffer().read(cx).title(cx)
 2759    }
 2760
 2761    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2762        let git_blame_gutter_max_author_length = self
 2763            .render_git_blame_gutter(cx)
 2764            .then(|| {
 2765                if let Some(blame) = self.blame.as_ref() {
 2766                    let max_author_length =
 2767                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2768                    Some(max_author_length)
 2769                } else {
 2770                    None
 2771                }
 2772            })
 2773            .flatten();
 2774
 2775        EditorSnapshot {
 2776            mode: self.mode.clone(),
 2777            show_gutter: self.show_gutter,
 2778            show_line_numbers: self.show_line_numbers,
 2779            show_git_diff_gutter: self.show_git_diff_gutter,
 2780            show_code_actions: self.show_code_actions,
 2781            show_runnables: self.show_runnables,
 2782            show_breakpoints: self.show_breakpoints,
 2783            git_blame_gutter_max_author_length,
 2784            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2785            placeholder_display_snapshot: self
 2786                .placeholder_display_map
 2787                .as_ref()
 2788                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2789            scroll_anchor: self.scroll_manager.anchor(),
 2790            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2791            is_focused: self.focus_handle.is_focused(window),
 2792            current_line_highlight: self
 2793                .current_line_highlight
 2794                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2795            gutter_hovered: self.gutter_hovered,
 2796        }
 2797    }
 2798
 2799    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2800        self.buffer.read(cx).language_at(point, cx)
 2801    }
 2802
 2803    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2804        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2805    }
 2806
 2807    pub fn active_excerpt(
 2808        &self,
 2809        cx: &App,
 2810    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2811        self.buffer
 2812            .read(cx)
 2813            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2814    }
 2815
 2816    pub fn mode(&self) -> &EditorMode {
 2817        &self.mode
 2818    }
 2819
 2820    pub fn set_mode(&mut self, mode: EditorMode) {
 2821        self.mode = mode;
 2822    }
 2823
 2824    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2825        self.collaboration_hub.as_deref()
 2826    }
 2827
 2828    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2829        self.collaboration_hub = Some(hub);
 2830    }
 2831
 2832    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2833        self.in_project_search = in_project_search;
 2834    }
 2835
 2836    pub fn set_custom_context_menu(
 2837        &mut self,
 2838        f: impl 'static
 2839        + Fn(
 2840            &mut Self,
 2841            DisplayPoint,
 2842            &mut Window,
 2843            &mut Context<Self>,
 2844        ) -> Option<Entity<ui::ContextMenu>>,
 2845    ) {
 2846        self.custom_context_menu = Some(Box::new(f))
 2847    }
 2848
 2849    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2850        self.completion_provider = provider;
 2851    }
 2852
 2853    #[cfg(any(test, feature = "test-support"))]
 2854    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2855        self.completion_provider.clone()
 2856    }
 2857
 2858    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2859        self.semantics_provider.clone()
 2860    }
 2861
 2862    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2863        self.semantics_provider = provider;
 2864    }
 2865
 2866    pub fn set_edit_prediction_provider<T>(
 2867        &mut self,
 2868        provider: Option<Entity<T>>,
 2869        window: &mut Window,
 2870        cx: &mut Context<Self>,
 2871    ) where
 2872        T: EditPredictionProvider,
 2873    {
 2874        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2875            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2876                if this.focus_handle.is_focused(window) {
 2877                    this.update_visible_edit_prediction(window, cx);
 2878                }
 2879            }),
 2880            provider: Arc::new(provider),
 2881        });
 2882        self.update_edit_prediction_settings(cx);
 2883        self.refresh_edit_prediction(false, false, window, cx);
 2884    }
 2885
 2886    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2887        self.placeholder_display_map
 2888            .as_ref()
 2889            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2890    }
 2891
 2892    pub fn set_placeholder_text(
 2893        &mut self,
 2894        placeholder_text: &str,
 2895        window: &mut Window,
 2896        cx: &mut Context<Self>,
 2897    ) {
 2898        let multibuffer = cx
 2899            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2900
 2901        let style = window.text_style();
 2902
 2903        self.placeholder_display_map = Some(cx.new(|cx| {
 2904            DisplayMap::new(
 2905                multibuffer,
 2906                style.font(),
 2907                style.font_size.to_pixels(window.rem_size()),
 2908                None,
 2909                FILE_HEADER_HEIGHT,
 2910                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2911                Default::default(),
 2912                DiagnosticSeverity::Off,
 2913                cx,
 2914            )
 2915        }));
 2916        cx.notify();
 2917    }
 2918
 2919    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2920        self.cursor_shape = cursor_shape;
 2921
 2922        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2923        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2924
 2925        cx.notify();
 2926    }
 2927
 2928    pub fn set_current_line_highlight(
 2929        &mut self,
 2930        current_line_highlight: Option<CurrentLineHighlight>,
 2931    ) {
 2932        self.current_line_highlight = current_line_highlight;
 2933    }
 2934
 2935    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2936        self.collapse_matches = collapse_matches;
 2937    }
 2938
 2939    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2940        if self.collapse_matches {
 2941            return range.start..range.start;
 2942        }
 2943        range.clone()
 2944    }
 2945
 2946    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2947        if self.display_map.read(cx).clip_at_line_ends != clip {
 2948            self.display_map
 2949                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2950        }
 2951    }
 2952
 2953    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2954        self.input_enabled = input_enabled;
 2955    }
 2956
 2957    pub fn set_edit_predictions_hidden_for_vim_mode(
 2958        &mut self,
 2959        hidden: bool,
 2960        window: &mut Window,
 2961        cx: &mut Context<Self>,
 2962    ) {
 2963        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2964            self.edit_predictions_hidden_for_vim_mode = hidden;
 2965            if hidden {
 2966                self.update_visible_edit_prediction(window, cx);
 2967            } else {
 2968                self.refresh_edit_prediction(true, false, window, cx);
 2969            }
 2970        }
 2971    }
 2972
 2973    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2974        self.menu_edit_predictions_policy = value;
 2975    }
 2976
 2977    pub fn set_autoindent(&mut self, autoindent: bool) {
 2978        if autoindent {
 2979            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2980        } else {
 2981            self.autoindent_mode = None;
 2982        }
 2983    }
 2984
 2985    pub fn read_only(&self, cx: &App) -> bool {
 2986        self.read_only || self.buffer.read(cx).read_only()
 2987    }
 2988
 2989    pub fn set_read_only(&mut self, read_only: bool) {
 2990        self.read_only = read_only;
 2991    }
 2992
 2993    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2994        self.use_autoclose = autoclose;
 2995    }
 2996
 2997    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2998        self.use_auto_surround = auto_surround;
 2999    }
 3000
 3001    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3002        self.auto_replace_emoji_shortcode = auto_replace;
 3003    }
 3004
 3005    pub fn toggle_edit_predictions(
 3006        &mut self,
 3007        _: &ToggleEditPrediction,
 3008        window: &mut Window,
 3009        cx: &mut Context<Self>,
 3010    ) {
 3011        if self.show_edit_predictions_override.is_some() {
 3012            self.set_show_edit_predictions(None, window, cx);
 3013        } else {
 3014            let show_edit_predictions = !self.edit_predictions_enabled();
 3015            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3016        }
 3017    }
 3018
 3019    pub fn set_show_edit_predictions(
 3020        &mut self,
 3021        show_edit_predictions: Option<bool>,
 3022        window: &mut Window,
 3023        cx: &mut Context<Self>,
 3024    ) {
 3025        self.show_edit_predictions_override = show_edit_predictions;
 3026        self.update_edit_prediction_settings(cx);
 3027
 3028        if let Some(false) = show_edit_predictions {
 3029            self.discard_edit_prediction(false, cx);
 3030        } else {
 3031            self.refresh_edit_prediction(false, true, window, cx);
 3032        }
 3033    }
 3034
 3035    fn edit_predictions_disabled_in_scope(
 3036        &self,
 3037        buffer: &Entity<Buffer>,
 3038        buffer_position: language::Anchor,
 3039        cx: &App,
 3040    ) -> bool {
 3041        let snapshot = buffer.read(cx).snapshot();
 3042        let settings = snapshot.settings_at(buffer_position, cx);
 3043
 3044        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3045            return false;
 3046        };
 3047
 3048        scope.override_name().is_some_and(|scope_name| {
 3049            settings
 3050                .edit_predictions_disabled_in
 3051                .iter()
 3052                .any(|s| s == scope_name)
 3053        })
 3054    }
 3055
 3056    pub fn set_use_modal_editing(&mut self, to: bool) {
 3057        self.use_modal_editing = to;
 3058    }
 3059
 3060    pub fn use_modal_editing(&self) -> bool {
 3061        self.use_modal_editing
 3062    }
 3063
 3064    fn selections_did_change(
 3065        &mut self,
 3066        local: bool,
 3067        old_cursor_position: &Anchor,
 3068        effects: SelectionEffects,
 3069        window: &mut Window,
 3070        cx: &mut Context<Self>,
 3071    ) {
 3072        window.invalidate_character_coordinates();
 3073
 3074        // Copy selections to primary selection buffer
 3075        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3076        if local {
 3077            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3078            let buffer_handle = self.buffer.read(cx).read(cx);
 3079
 3080            let mut text = String::new();
 3081            for (index, selection) in selections.iter().enumerate() {
 3082                let text_for_selection = buffer_handle
 3083                    .text_for_range(selection.start..selection.end)
 3084                    .collect::<String>();
 3085
 3086                text.push_str(&text_for_selection);
 3087                if index != selections.len() - 1 {
 3088                    text.push('\n');
 3089                }
 3090            }
 3091
 3092            if !text.is_empty() {
 3093                cx.write_to_primary(ClipboardItem::new_string(text));
 3094            }
 3095        }
 3096
 3097        let selection_anchors = self.selections.disjoint_anchors_arc();
 3098
 3099        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3100            self.buffer.update(cx, |buffer, cx| {
 3101                buffer.set_active_selections(
 3102                    &selection_anchors,
 3103                    self.selections.line_mode(),
 3104                    self.cursor_shape,
 3105                    cx,
 3106                )
 3107            });
 3108        }
 3109        let display_map = self
 3110            .display_map
 3111            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3112        let buffer = display_map.buffer_snapshot();
 3113        if self.selections.count() == 1 {
 3114            self.add_selections_state = None;
 3115        }
 3116        self.select_next_state = None;
 3117        self.select_prev_state = None;
 3118        self.select_syntax_node_history.try_clear();
 3119        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3120        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3121        self.take_rename(false, window, cx);
 3122
 3123        let newest_selection = self.selections.newest_anchor();
 3124        let new_cursor_position = newest_selection.head();
 3125        let selection_start = newest_selection.start;
 3126
 3127        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3128            self.push_to_nav_history(
 3129                *old_cursor_position,
 3130                Some(new_cursor_position.to_point(buffer)),
 3131                false,
 3132                effects.nav_history == Some(true),
 3133                cx,
 3134            );
 3135        }
 3136
 3137        if local {
 3138            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3139                self.register_buffer(buffer_id, cx);
 3140            }
 3141
 3142            let mut context_menu = self.context_menu.borrow_mut();
 3143            let completion_menu = match context_menu.as_ref() {
 3144                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3145                Some(CodeContextMenu::CodeActions(_)) => {
 3146                    *context_menu = None;
 3147                    None
 3148                }
 3149                None => None,
 3150            };
 3151            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3152            drop(context_menu);
 3153
 3154            if effects.completions
 3155                && let Some(completion_position) = completion_position
 3156            {
 3157                let start_offset = selection_start.to_offset(buffer);
 3158                let position_matches = start_offset == completion_position.to_offset(buffer);
 3159                let continue_showing = if position_matches {
 3160                    if self.snippet_stack.is_empty() {
 3161                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3162                            == Some(CharKind::Word)
 3163                    } else {
 3164                        // Snippet choices can be shown even when the cursor is in whitespace.
 3165                        // Dismissing the menu with actions like backspace is handled by
 3166                        // invalidation regions.
 3167                        true
 3168                    }
 3169                } else {
 3170                    false
 3171                };
 3172
 3173                if continue_showing {
 3174                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3175                } else {
 3176                    self.hide_context_menu(window, cx);
 3177                }
 3178            }
 3179
 3180            hide_hover(self, cx);
 3181
 3182            if old_cursor_position.to_display_point(&display_map).row()
 3183                != new_cursor_position.to_display_point(&display_map).row()
 3184            {
 3185                self.available_code_actions.take();
 3186            }
 3187            self.refresh_code_actions(window, cx);
 3188            self.refresh_document_highlights(cx);
 3189            refresh_linked_ranges(self, window, cx);
 3190
 3191            self.refresh_selected_text_highlights(false, window, cx);
 3192            refresh_matching_bracket_highlights(self, cx);
 3193            self.update_visible_edit_prediction(window, cx);
 3194            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3195            self.inline_blame_popover.take();
 3196            if self.git_blame_inline_enabled {
 3197                self.start_inline_blame_timer(window, cx);
 3198            }
 3199        }
 3200
 3201        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3202        cx.emit(EditorEvent::SelectionsChanged { local });
 3203
 3204        let selections = &self.selections.disjoint_anchors_arc();
 3205        if selections.len() == 1 {
 3206            cx.emit(SearchEvent::ActiveMatchChanged)
 3207        }
 3208        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3209            let inmemory_selections = selections
 3210                .iter()
 3211                .map(|s| {
 3212                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3213                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3214                })
 3215                .collect();
 3216            self.update_restoration_data(cx, |data| {
 3217                data.selections = inmemory_selections;
 3218            });
 3219
 3220            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3221                && let Some(workspace_id) =
 3222                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3223            {
 3224                let snapshot = self.buffer().read(cx).snapshot(cx);
 3225                let selections = selections.clone();
 3226                let background_executor = cx.background_executor().clone();
 3227                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3228                self.serialize_selections = cx.background_spawn(async move {
 3229                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3230                    let db_selections = selections
 3231                        .iter()
 3232                        .map(|selection| {
 3233                            (
 3234                                selection.start.to_offset(&snapshot),
 3235                                selection.end.to_offset(&snapshot),
 3236                            )
 3237                        })
 3238                        .collect();
 3239
 3240                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3241                        .await
 3242                        .with_context(|| {
 3243                            format!(
 3244                                "persisting editor selections for editor {editor_id}, \
 3245                                workspace {workspace_id:?}"
 3246                            )
 3247                        })
 3248                        .log_err();
 3249                });
 3250            }
 3251        }
 3252
 3253        cx.notify();
 3254    }
 3255
 3256    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3257        use text::ToOffset as _;
 3258        use text::ToPoint as _;
 3259
 3260        if self.mode.is_minimap()
 3261            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3262        {
 3263            return;
 3264        }
 3265
 3266        if !self.buffer().read(cx).is_singleton() {
 3267            return;
 3268        }
 3269
 3270        let display_snapshot = self
 3271            .display_map
 3272            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3273        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3274            return;
 3275        };
 3276        let inmemory_folds = display_snapshot
 3277            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3278            .map(|fold| {
 3279                fold.range.start.text_anchor.to_point(&snapshot)
 3280                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3281            })
 3282            .collect();
 3283        self.update_restoration_data(cx, |data| {
 3284            data.folds = inmemory_folds;
 3285        });
 3286
 3287        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3288            return;
 3289        };
 3290        let background_executor = cx.background_executor().clone();
 3291        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3292        let db_folds = display_snapshot
 3293            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3294            .map(|fold| {
 3295                (
 3296                    fold.range.start.text_anchor.to_offset(&snapshot),
 3297                    fold.range.end.text_anchor.to_offset(&snapshot),
 3298                )
 3299            })
 3300            .collect();
 3301        self.serialize_folds = cx.background_spawn(async move {
 3302            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3303            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3304                .await
 3305                .with_context(|| {
 3306                    format!(
 3307                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3308                    )
 3309                })
 3310                .log_err();
 3311        });
 3312    }
 3313
 3314    pub fn sync_selections(
 3315        &mut self,
 3316        other: Entity<Editor>,
 3317        cx: &mut Context<Self>,
 3318    ) -> gpui::Subscription {
 3319        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3320        if !other_selections.is_empty() {
 3321            self.selections.change_with(cx, |selections| {
 3322                selections.select_anchors(other_selections);
 3323            });
 3324        }
 3325
 3326        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3327            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3328                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3329                if other_selections.is_empty() {
 3330                    return;
 3331                }
 3332                this.selections.change_with(cx, |selections| {
 3333                    selections.select_anchors(other_selections);
 3334                });
 3335            }
 3336        });
 3337
 3338        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3339            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3340                let these_selections = this.selections.disjoint_anchors().to_vec();
 3341                if these_selections.is_empty() {
 3342                    return;
 3343                }
 3344                other.update(cx, |other_editor, cx| {
 3345                    other_editor.selections.change_with(cx, |selections| {
 3346                        selections.select_anchors(these_selections);
 3347                    })
 3348                });
 3349            }
 3350        });
 3351
 3352        Subscription::join(other_subscription, this_subscription)
 3353    }
 3354
 3355    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3356    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3357    /// effects of selection change occur at the end of the transaction.
 3358    pub fn change_selections<R>(
 3359        &mut self,
 3360        effects: SelectionEffects,
 3361        window: &mut Window,
 3362        cx: &mut Context<Self>,
 3363        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3364    ) -> R {
 3365        if let Some(state) = &mut self.deferred_selection_effects_state {
 3366            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3367            state.effects.completions = effects.completions;
 3368            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3369            let (changed, result) = self.selections.change_with(cx, change);
 3370            state.changed |= changed;
 3371            return result;
 3372        }
 3373        let mut state = DeferredSelectionEffectsState {
 3374            changed: false,
 3375            effects,
 3376            old_cursor_position: self.selections.newest_anchor().head(),
 3377            history_entry: SelectionHistoryEntry {
 3378                selections: self.selections.disjoint_anchors_arc(),
 3379                select_next_state: self.select_next_state.clone(),
 3380                select_prev_state: self.select_prev_state.clone(),
 3381                add_selections_state: self.add_selections_state.clone(),
 3382            },
 3383        };
 3384        let (changed, result) = self.selections.change_with(cx, change);
 3385        state.changed = state.changed || changed;
 3386        if self.defer_selection_effects {
 3387            self.deferred_selection_effects_state = Some(state);
 3388        } else {
 3389            self.apply_selection_effects(state, window, cx);
 3390        }
 3391        result
 3392    }
 3393
 3394    /// Defers the effects of selection change, so that the effects of multiple calls to
 3395    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3396    /// to selection history and the state of popovers based on selection position aren't
 3397    /// erroneously updated.
 3398    pub fn with_selection_effects_deferred<R>(
 3399        &mut self,
 3400        window: &mut Window,
 3401        cx: &mut Context<Self>,
 3402        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3403    ) -> R {
 3404        let already_deferred = self.defer_selection_effects;
 3405        self.defer_selection_effects = true;
 3406        let result = update(self, window, cx);
 3407        if !already_deferred {
 3408            self.defer_selection_effects = false;
 3409            if let Some(state) = self.deferred_selection_effects_state.take() {
 3410                self.apply_selection_effects(state, window, cx);
 3411            }
 3412        }
 3413        result
 3414    }
 3415
 3416    fn apply_selection_effects(
 3417        &mut self,
 3418        state: DeferredSelectionEffectsState,
 3419        window: &mut Window,
 3420        cx: &mut Context<Self>,
 3421    ) {
 3422        if state.changed {
 3423            self.selection_history.push(state.history_entry);
 3424
 3425            if let Some(autoscroll) = state.effects.scroll {
 3426                self.request_autoscroll(autoscroll, cx);
 3427            }
 3428
 3429            let old_cursor_position = &state.old_cursor_position;
 3430
 3431            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3432
 3433            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3434                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3435            }
 3436        }
 3437    }
 3438
 3439    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3440    where
 3441        I: IntoIterator<Item = (Range<S>, T)>,
 3442        S: ToOffset,
 3443        T: Into<Arc<str>>,
 3444    {
 3445        if self.read_only(cx) {
 3446            return;
 3447        }
 3448
 3449        self.buffer
 3450            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3451    }
 3452
 3453    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3454    where
 3455        I: IntoIterator<Item = (Range<S>, T)>,
 3456        S: ToOffset,
 3457        T: Into<Arc<str>>,
 3458    {
 3459        if self.read_only(cx) {
 3460            return;
 3461        }
 3462
 3463        self.buffer.update(cx, |buffer, cx| {
 3464            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3465        });
 3466    }
 3467
 3468    pub fn edit_with_block_indent<I, S, T>(
 3469        &mut self,
 3470        edits: I,
 3471        original_indent_columns: Vec<Option<u32>>,
 3472        cx: &mut Context<Self>,
 3473    ) where
 3474        I: IntoIterator<Item = (Range<S>, T)>,
 3475        S: ToOffset,
 3476        T: Into<Arc<str>>,
 3477    {
 3478        if self.read_only(cx) {
 3479            return;
 3480        }
 3481
 3482        self.buffer.update(cx, |buffer, cx| {
 3483            buffer.edit(
 3484                edits,
 3485                Some(AutoindentMode::Block {
 3486                    original_indent_columns,
 3487                }),
 3488                cx,
 3489            )
 3490        });
 3491    }
 3492
 3493    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3494        self.hide_context_menu(window, cx);
 3495
 3496        match phase {
 3497            SelectPhase::Begin {
 3498                position,
 3499                add,
 3500                click_count,
 3501            } => self.begin_selection(position, add, click_count, window, cx),
 3502            SelectPhase::BeginColumnar {
 3503                position,
 3504                goal_column,
 3505                reset,
 3506                mode,
 3507            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3508            SelectPhase::Extend {
 3509                position,
 3510                click_count,
 3511            } => self.extend_selection(position, click_count, window, cx),
 3512            SelectPhase::Update {
 3513                position,
 3514                goal_column,
 3515                scroll_delta,
 3516            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3517            SelectPhase::End => self.end_selection(window, cx),
 3518        }
 3519    }
 3520
 3521    fn extend_selection(
 3522        &mut self,
 3523        position: DisplayPoint,
 3524        click_count: usize,
 3525        window: &mut Window,
 3526        cx: &mut Context<Self>,
 3527    ) {
 3528        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3529        let tail = self.selections.newest::<usize>(&display_map).tail();
 3530        let click_count = click_count.max(match self.selections.select_mode() {
 3531            SelectMode::Character => 1,
 3532            SelectMode::Word(_) => 2,
 3533            SelectMode::Line(_) => 3,
 3534            SelectMode::All => 4,
 3535        });
 3536        self.begin_selection(position, false, click_count, window, cx);
 3537
 3538        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3539
 3540        let current_selection = match self.selections.select_mode() {
 3541            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3542            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3543        };
 3544
 3545        let mut pending_selection = self
 3546            .selections
 3547            .pending_anchor()
 3548            .cloned()
 3549            .expect("extend_selection not called with pending selection");
 3550
 3551        if pending_selection
 3552            .start
 3553            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3554            == Ordering::Greater
 3555        {
 3556            pending_selection.start = current_selection.start;
 3557        }
 3558        if pending_selection
 3559            .end
 3560            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3561            == Ordering::Less
 3562        {
 3563            pending_selection.end = current_selection.end;
 3564            pending_selection.reversed = true;
 3565        }
 3566
 3567        let mut pending_mode = self.selections.pending_mode().unwrap();
 3568        match &mut pending_mode {
 3569            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3570            _ => {}
 3571        }
 3572
 3573        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3574            SelectionEffects::scroll(Autoscroll::fit())
 3575        } else {
 3576            SelectionEffects::no_scroll()
 3577        };
 3578
 3579        self.change_selections(effects, window, cx, |s| {
 3580            s.set_pending(pending_selection.clone(), pending_mode);
 3581            s.set_is_extending(true);
 3582        });
 3583    }
 3584
 3585    fn begin_selection(
 3586        &mut self,
 3587        position: DisplayPoint,
 3588        add: bool,
 3589        click_count: usize,
 3590        window: &mut Window,
 3591        cx: &mut Context<Self>,
 3592    ) {
 3593        if !self.focus_handle.is_focused(window) {
 3594            self.last_focused_descendant = None;
 3595            window.focus(&self.focus_handle);
 3596        }
 3597
 3598        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3599        let buffer = display_map.buffer_snapshot();
 3600        let position = display_map.clip_point(position, Bias::Left);
 3601
 3602        let start;
 3603        let end;
 3604        let mode;
 3605        let mut auto_scroll;
 3606        match click_count {
 3607            1 => {
 3608                start = buffer.anchor_before(position.to_point(&display_map));
 3609                end = start;
 3610                mode = SelectMode::Character;
 3611                auto_scroll = true;
 3612            }
 3613            2 => {
 3614                let position = display_map
 3615                    .clip_point(position, Bias::Left)
 3616                    .to_offset(&display_map, Bias::Left);
 3617                let (range, _) = buffer.surrounding_word(position, None);
 3618                start = buffer.anchor_before(range.start);
 3619                end = buffer.anchor_before(range.end);
 3620                mode = SelectMode::Word(start..end);
 3621                auto_scroll = true;
 3622            }
 3623            3 => {
 3624                let position = display_map
 3625                    .clip_point(position, Bias::Left)
 3626                    .to_point(&display_map);
 3627                let line_start = display_map.prev_line_boundary(position).0;
 3628                let next_line_start = buffer.clip_point(
 3629                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3630                    Bias::Left,
 3631                );
 3632                start = buffer.anchor_before(line_start);
 3633                end = buffer.anchor_before(next_line_start);
 3634                mode = SelectMode::Line(start..end);
 3635                auto_scroll = true;
 3636            }
 3637            _ => {
 3638                start = buffer.anchor_before(0);
 3639                end = buffer.anchor_before(buffer.len());
 3640                mode = SelectMode::All;
 3641                auto_scroll = false;
 3642            }
 3643        }
 3644        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3645
 3646        let point_to_delete: Option<usize> = {
 3647            let selected_points: Vec<Selection<Point>> =
 3648                self.selections.disjoint_in_range(start..end, &display_map);
 3649
 3650            if !add || click_count > 1 {
 3651                None
 3652            } else if !selected_points.is_empty() {
 3653                Some(selected_points[0].id)
 3654            } else {
 3655                let clicked_point_already_selected =
 3656                    self.selections.disjoint_anchors().iter().find(|selection| {
 3657                        selection.start.to_point(buffer) == start.to_point(buffer)
 3658                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3659                    });
 3660
 3661                clicked_point_already_selected.map(|selection| selection.id)
 3662            }
 3663        };
 3664
 3665        let selections_count = self.selections.count();
 3666        let effects = if auto_scroll {
 3667            SelectionEffects::default()
 3668        } else {
 3669            SelectionEffects::no_scroll()
 3670        };
 3671
 3672        self.change_selections(effects, window, cx, |s| {
 3673            if let Some(point_to_delete) = point_to_delete {
 3674                s.delete(point_to_delete);
 3675
 3676                if selections_count == 1 {
 3677                    s.set_pending_anchor_range(start..end, mode);
 3678                }
 3679            } else {
 3680                if !add {
 3681                    s.clear_disjoint();
 3682                }
 3683
 3684                s.set_pending_anchor_range(start..end, mode);
 3685            }
 3686        });
 3687    }
 3688
 3689    fn begin_columnar_selection(
 3690        &mut self,
 3691        position: DisplayPoint,
 3692        goal_column: u32,
 3693        reset: bool,
 3694        mode: ColumnarMode,
 3695        window: &mut Window,
 3696        cx: &mut Context<Self>,
 3697    ) {
 3698        if !self.focus_handle.is_focused(window) {
 3699            self.last_focused_descendant = None;
 3700            window.focus(&self.focus_handle);
 3701        }
 3702
 3703        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3704
 3705        if reset {
 3706            let pointer_position = display_map
 3707                .buffer_snapshot()
 3708                .anchor_before(position.to_point(&display_map));
 3709
 3710            self.change_selections(
 3711                SelectionEffects::scroll(Autoscroll::newest()),
 3712                window,
 3713                cx,
 3714                |s| {
 3715                    s.clear_disjoint();
 3716                    s.set_pending_anchor_range(
 3717                        pointer_position..pointer_position,
 3718                        SelectMode::Character,
 3719                    );
 3720                },
 3721            );
 3722        };
 3723
 3724        let tail = self.selections.newest::<Point>(&display_map).tail();
 3725        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3726        self.columnar_selection_state = match mode {
 3727            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3728                selection_tail: selection_anchor,
 3729                display_point: if reset {
 3730                    if position.column() != goal_column {
 3731                        Some(DisplayPoint::new(position.row(), goal_column))
 3732                    } else {
 3733                        None
 3734                    }
 3735                } else {
 3736                    None
 3737                },
 3738            }),
 3739            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3740                selection_tail: selection_anchor,
 3741            }),
 3742        };
 3743
 3744        if !reset {
 3745            self.select_columns(position, goal_column, &display_map, window, cx);
 3746        }
 3747    }
 3748
 3749    fn update_selection(
 3750        &mut self,
 3751        position: DisplayPoint,
 3752        goal_column: u32,
 3753        scroll_delta: gpui::Point<f32>,
 3754        window: &mut Window,
 3755        cx: &mut Context<Self>,
 3756    ) {
 3757        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3758
 3759        if self.columnar_selection_state.is_some() {
 3760            self.select_columns(position, goal_column, &display_map, window, cx);
 3761        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3762            let buffer = display_map.buffer_snapshot();
 3763            let head;
 3764            let tail;
 3765            let mode = self.selections.pending_mode().unwrap();
 3766            match &mode {
 3767                SelectMode::Character => {
 3768                    head = position.to_point(&display_map);
 3769                    tail = pending.tail().to_point(buffer);
 3770                }
 3771                SelectMode::Word(original_range) => {
 3772                    let offset = display_map
 3773                        .clip_point(position, Bias::Left)
 3774                        .to_offset(&display_map, Bias::Left);
 3775                    let original_range = original_range.to_offset(buffer);
 3776
 3777                    let head_offset = if buffer.is_inside_word(offset, None)
 3778                        || original_range.contains(&offset)
 3779                    {
 3780                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3781                        if word_range.start < original_range.start {
 3782                            word_range.start
 3783                        } else {
 3784                            word_range.end
 3785                        }
 3786                    } else {
 3787                        offset
 3788                    };
 3789
 3790                    head = head_offset.to_point(buffer);
 3791                    if head_offset <= original_range.start {
 3792                        tail = original_range.end.to_point(buffer);
 3793                    } else {
 3794                        tail = original_range.start.to_point(buffer);
 3795                    }
 3796                }
 3797                SelectMode::Line(original_range) => {
 3798                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3799
 3800                    let position = display_map
 3801                        .clip_point(position, Bias::Left)
 3802                        .to_point(&display_map);
 3803                    let line_start = display_map.prev_line_boundary(position).0;
 3804                    let next_line_start = buffer.clip_point(
 3805                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3806                        Bias::Left,
 3807                    );
 3808
 3809                    if line_start < original_range.start {
 3810                        head = line_start
 3811                    } else {
 3812                        head = next_line_start
 3813                    }
 3814
 3815                    if head <= original_range.start {
 3816                        tail = original_range.end;
 3817                    } else {
 3818                        tail = original_range.start;
 3819                    }
 3820                }
 3821                SelectMode::All => {
 3822                    return;
 3823                }
 3824            };
 3825
 3826            if head < tail {
 3827                pending.start = buffer.anchor_before(head);
 3828                pending.end = buffer.anchor_before(tail);
 3829                pending.reversed = true;
 3830            } else {
 3831                pending.start = buffer.anchor_before(tail);
 3832                pending.end = buffer.anchor_before(head);
 3833                pending.reversed = false;
 3834            }
 3835
 3836            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3837                s.set_pending(pending.clone(), mode);
 3838            });
 3839        } else {
 3840            log::error!("update_selection dispatched with no pending selection");
 3841            return;
 3842        }
 3843
 3844        self.apply_scroll_delta(scroll_delta, window, cx);
 3845        cx.notify();
 3846    }
 3847
 3848    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3849        self.columnar_selection_state.take();
 3850        if let Some(pending_mode) = self.selections.pending_mode() {
 3851            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3852            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3853                s.select(selections);
 3854                s.clear_pending();
 3855                if s.is_extending() {
 3856                    s.set_is_extending(false);
 3857                } else {
 3858                    s.set_select_mode(pending_mode);
 3859                }
 3860            });
 3861        }
 3862    }
 3863
 3864    fn select_columns(
 3865        &mut self,
 3866        head: DisplayPoint,
 3867        goal_column: u32,
 3868        display_map: &DisplaySnapshot,
 3869        window: &mut Window,
 3870        cx: &mut Context<Self>,
 3871    ) {
 3872        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3873            return;
 3874        };
 3875
 3876        let tail = match columnar_state {
 3877            ColumnarSelectionState::FromMouse {
 3878                selection_tail,
 3879                display_point,
 3880            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3881            ColumnarSelectionState::FromSelection { selection_tail } => {
 3882                selection_tail.to_display_point(display_map)
 3883            }
 3884        };
 3885
 3886        let start_row = cmp::min(tail.row(), head.row());
 3887        let end_row = cmp::max(tail.row(), head.row());
 3888        let start_column = cmp::min(tail.column(), goal_column);
 3889        let end_column = cmp::max(tail.column(), goal_column);
 3890        let reversed = start_column < tail.column();
 3891
 3892        let selection_ranges = (start_row.0..=end_row.0)
 3893            .map(DisplayRow)
 3894            .filter_map(|row| {
 3895                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3896                    || start_column <= display_map.line_len(row))
 3897                    && !display_map.is_block_line(row)
 3898                {
 3899                    let start = display_map
 3900                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3901                        .to_point(display_map);
 3902                    let end = display_map
 3903                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3904                        .to_point(display_map);
 3905                    if reversed {
 3906                        Some(end..start)
 3907                    } else {
 3908                        Some(start..end)
 3909                    }
 3910                } else {
 3911                    None
 3912                }
 3913            })
 3914            .collect::<Vec<_>>();
 3915        if selection_ranges.is_empty() {
 3916            return;
 3917        }
 3918
 3919        let ranges = match columnar_state {
 3920            ColumnarSelectionState::FromMouse { .. } => {
 3921                let mut non_empty_ranges = selection_ranges
 3922                    .iter()
 3923                    .filter(|selection_range| selection_range.start != selection_range.end)
 3924                    .peekable();
 3925                if non_empty_ranges.peek().is_some() {
 3926                    non_empty_ranges.cloned().collect()
 3927                } else {
 3928                    selection_ranges
 3929                }
 3930            }
 3931            _ => selection_ranges,
 3932        };
 3933
 3934        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3935            s.select_ranges(ranges);
 3936        });
 3937        cx.notify();
 3938    }
 3939
 3940    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3941        self.selections
 3942            .all_adjusted(snapshot)
 3943            .iter()
 3944            .any(|selection| !selection.is_empty())
 3945    }
 3946
 3947    pub fn has_pending_nonempty_selection(&self) -> bool {
 3948        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3949            Some(Selection { start, end, .. }) => start != end,
 3950            None => false,
 3951        };
 3952
 3953        pending_nonempty_selection
 3954            || (self.columnar_selection_state.is_some()
 3955                && self.selections.disjoint_anchors().len() > 1)
 3956    }
 3957
 3958    pub fn has_pending_selection(&self) -> bool {
 3959        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3960    }
 3961
 3962    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3963        self.selection_mark_mode = false;
 3964        self.selection_drag_state = SelectionDragState::None;
 3965
 3966        if self.clear_expanded_diff_hunks(cx) {
 3967            cx.notify();
 3968            return;
 3969        }
 3970        if self.dismiss_menus_and_popups(true, window, cx) {
 3971            return;
 3972        }
 3973
 3974        if self.mode.is_full()
 3975            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3976        {
 3977            return;
 3978        }
 3979
 3980        cx.propagate();
 3981    }
 3982
 3983    pub fn dismiss_menus_and_popups(
 3984        &mut self,
 3985        is_user_requested: bool,
 3986        window: &mut Window,
 3987        cx: &mut Context<Self>,
 3988    ) -> bool {
 3989        if self.take_rename(false, window, cx).is_some() {
 3990            return true;
 3991        }
 3992
 3993        if self.hide_blame_popover(true, cx) {
 3994            return true;
 3995        }
 3996
 3997        if hide_hover(self, cx) {
 3998            return true;
 3999        }
 4000
 4001        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4002            return true;
 4003        }
 4004
 4005        if self.hide_context_menu(window, cx).is_some() {
 4006            return true;
 4007        }
 4008
 4009        if self.mouse_context_menu.take().is_some() {
 4010            return true;
 4011        }
 4012
 4013        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4014            return true;
 4015        }
 4016
 4017        if self.snippet_stack.pop().is_some() {
 4018            return true;
 4019        }
 4020
 4021        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4022            self.dismiss_diagnostics(cx);
 4023            return true;
 4024        }
 4025
 4026        false
 4027    }
 4028
 4029    fn linked_editing_ranges_for(
 4030        &self,
 4031        selection: Range<text::Anchor>,
 4032        cx: &App,
 4033    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4034        if self.linked_edit_ranges.is_empty() {
 4035            return None;
 4036        }
 4037        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4038            selection.end.buffer_id.and_then(|end_buffer_id| {
 4039                if selection.start.buffer_id != Some(end_buffer_id) {
 4040                    return None;
 4041                }
 4042                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4043                let snapshot = buffer.read(cx).snapshot();
 4044                self.linked_edit_ranges
 4045                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4046                    .map(|ranges| (ranges, snapshot, buffer))
 4047            })?;
 4048        use text::ToOffset as TO;
 4049        // find offset from the start of current range to current cursor position
 4050        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4051
 4052        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4053        let start_difference = start_offset - start_byte_offset;
 4054        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4055        let end_difference = end_offset - start_byte_offset;
 4056        // Current range has associated linked ranges.
 4057        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4058        for range in linked_ranges.iter() {
 4059            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4060            let end_offset = start_offset + end_difference;
 4061            let start_offset = start_offset + start_difference;
 4062            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4063                continue;
 4064            }
 4065            if self.selections.disjoint_anchor_ranges().any(|s| {
 4066                if s.start.buffer_id != selection.start.buffer_id
 4067                    || s.end.buffer_id != selection.end.buffer_id
 4068                {
 4069                    return false;
 4070                }
 4071                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4072                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4073            }) {
 4074                continue;
 4075            }
 4076            let start = buffer_snapshot.anchor_after(start_offset);
 4077            let end = buffer_snapshot.anchor_after(end_offset);
 4078            linked_edits
 4079                .entry(buffer.clone())
 4080                .or_default()
 4081                .push(start..end);
 4082        }
 4083        Some(linked_edits)
 4084    }
 4085
 4086    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4087        let text: Arc<str> = text.into();
 4088
 4089        if self.read_only(cx) {
 4090            return;
 4091        }
 4092
 4093        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4094
 4095        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4096        let mut bracket_inserted = false;
 4097        let mut edits = Vec::new();
 4098        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4099        let mut new_selections = Vec::with_capacity(selections.len());
 4100        let mut new_autoclose_regions = Vec::new();
 4101        let snapshot = self.buffer.read(cx).read(cx);
 4102        let mut clear_linked_edit_ranges = false;
 4103
 4104        for (selection, autoclose_region) in
 4105            self.selections_with_autoclose_regions(selections, &snapshot)
 4106        {
 4107            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4108                // Determine if the inserted text matches the opening or closing
 4109                // bracket of any of this language's bracket pairs.
 4110                let mut bracket_pair = None;
 4111                let mut is_bracket_pair_start = false;
 4112                let mut is_bracket_pair_end = false;
 4113                if !text.is_empty() {
 4114                    let mut bracket_pair_matching_end = None;
 4115                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4116                    //  and they are removing the character that triggered IME popup.
 4117                    for (pair, enabled) in scope.brackets() {
 4118                        if !pair.close && !pair.surround {
 4119                            continue;
 4120                        }
 4121
 4122                        if enabled && pair.start.ends_with(text.as_ref()) {
 4123                            let prefix_len = pair.start.len() - text.len();
 4124                            let preceding_text_matches_prefix = prefix_len == 0
 4125                                || (selection.start.column >= (prefix_len as u32)
 4126                                    && snapshot.contains_str_at(
 4127                                        Point::new(
 4128                                            selection.start.row,
 4129                                            selection.start.column - (prefix_len as u32),
 4130                                        ),
 4131                                        &pair.start[..prefix_len],
 4132                                    ));
 4133                            if preceding_text_matches_prefix {
 4134                                bracket_pair = Some(pair.clone());
 4135                                is_bracket_pair_start = true;
 4136                                break;
 4137                            }
 4138                        }
 4139                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4140                        {
 4141                            // take first bracket pair matching end, but don't break in case a later bracket
 4142                            // pair matches start
 4143                            bracket_pair_matching_end = Some(pair.clone());
 4144                        }
 4145                    }
 4146                    if let Some(end) = bracket_pair_matching_end
 4147                        && bracket_pair.is_none()
 4148                    {
 4149                        bracket_pair = Some(end);
 4150                        is_bracket_pair_end = true;
 4151                    }
 4152                }
 4153
 4154                if let Some(bracket_pair) = bracket_pair {
 4155                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4156                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4157                    let auto_surround =
 4158                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4159                    if selection.is_empty() {
 4160                        if is_bracket_pair_start {
 4161                            // If the inserted text is a suffix of an opening bracket and the
 4162                            // selection is preceded by the rest of the opening bracket, then
 4163                            // insert the closing bracket.
 4164                            let following_text_allows_autoclose = snapshot
 4165                                .chars_at(selection.start)
 4166                                .next()
 4167                                .is_none_or(|c| scope.should_autoclose_before(c));
 4168
 4169                            let preceding_text_allows_autoclose = selection.start.column == 0
 4170                                || snapshot
 4171                                    .reversed_chars_at(selection.start)
 4172                                    .next()
 4173                                    .is_none_or(|c| {
 4174                                        bracket_pair.start != bracket_pair.end
 4175                                            || !snapshot
 4176                                                .char_classifier_at(selection.start)
 4177                                                .is_word(c)
 4178                                    });
 4179
 4180                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4181                                && bracket_pair.start.len() == 1
 4182                            {
 4183                                let target = bracket_pair.start.chars().next().unwrap();
 4184                                let current_line_count = snapshot
 4185                                    .reversed_chars_at(selection.start)
 4186                                    .take_while(|&c| c != '\n')
 4187                                    .filter(|&c| c == target)
 4188                                    .count();
 4189                                current_line_count % 2 == 1
 4190                            } else {
 4191                                false
 4192                            };
 4193
 4194                            if autoclose
 4195                                && bracket_pair.close
 4196                                && following_text_allows_autoclose
 4197                                && preceding_text_allows_autoclose
 4198                                && !is_closing_quote
 4199                            {
 4200                                let anchor = snapshot.anchor_before(selection.end);
 4201                                new_selections.push((selection.map(|_| anchor), text.len()));
 4202                                new_autoclose_regions.push((
 4203                                    anchor,
 4204                                    text.len(),
 4205                                    selection.id,
 4206                                    bracket_pair.clone(),
 4207                                ));
 4208                                edits.push((
 4209                                    selection.range(),
 4210                                    format!("{}{}", text, bracket_pair.end).into(),
 4211                                ));
 4212                                bracket_inserted = true;
 4213                                continue;
 4214                            }
 4215                        }
 4216
 4217                        if let Some(region) = autoclose_region {
 4218                            // If the selection is followed by an auto-inserted closing bracket,
 4219                            // then don't insert that closing bracket again; just move the selection
 4220                            // past the closing bracket.
 4221                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4222                                && text.as_ref() == region.pair.end.as_str()
 4223                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4224                            if should_skip {
 4225                                let anchor = snapshot.anchor_after(selection.end);
 4226                                new_selections
 4227                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4228                                continue;
 4229                            }
 4230                        }
 4231
 4232                        let always_treat_brackets_as_autoclosed = snapshot
 4233                            .language_settings_at(selection.start, cx)
 4234                            .always_treat_brackets_as_autoclosed;
 4235                        if always_treat_brackets_as_autoclosed
 4236                            && is_bracket_pair_end
 4237                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4238                        {
 4239                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4240                            // and the inserted text is a closing bracket and the selection is followed
 4241                            // by the closing bracket then move the selection past the closing bracket.
 4242                            let anchor = snapshot.anchor_after(selection.end);
 4243                            new_selections.push((selection.map(|_| anchor), text.len()));
 4244                            continue;
 4245                        }
 4246                    }
 4247                    // If an opening bracket is 1 character long and is typed while
 4248                    // text is selected, then surround that text with the bracket pair.
 4249                    else if auto_surround
 4250                        && bracket_pair.surround
 4251                        && is_bracket_pair_start
 4252                        && bracket_pair.start.chars().count() == 1
 4253                    {
 4254                        edits.push((selection.start..selection.start, text.clone()));
 4255                        edits.push((
 4256                            selection.end..selection.end,
 4257                            bracket_pair.end.as_str().into(),
 4258                        ));
 4259                        bracket_inserted = true;
 4260                        new_selections.push((
 4261                            Selection {
 4262                                id: selection.id,
 4263                                start: snapshot.anchor_after(selection.start),
 4264                                end: snapshot.anchor_before(selection.end),
 4265                                reversed: selection.reversed,
 4266                                goal: selection.goal,
 4267                            },
 4268                            0,
 4269                        ));
 4270                        continue;
 4271                    }
 4272                }
 4273            }
 4274
 4275            if self.auto_replace_emoji_shortcode
 4276                && selection.is_empty()
 4277                && text.as_ref().ends_with(':')
 4278                && let Some(possible_emoji_short_code) =
 4279                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4280                && !possible_emoji_short_code.is_empty()
 4281                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4282            {
 4283                let emoji_shortcode_start = Point::new(
 4284                    selection.start.row,
 4285                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4286                );
 4287
 4288                // Remove shortcode from buffer
 4289                edits.push((
 4290                    emoji_shortcode_start..selection.start,
 4291                    "".to_string().into(),
 4292                ));
 4293                new_selections.push((
 4294                    Selection {
 4295                        id: selection.id,
 4296                        start: snapshot.anchor_after(emoji_shortcode_start),
 4297                        end: snapshot.anchor_before(selection.start),
 4298                        reversed: selection.reversed,
 4299                        goal: selection.goal,
 4300                    },
 4301                    0,
 4302                ));
 4303
 4304                // Insert emoji
 4305                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4306                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4307                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4308
 4309                continue;
 4310            }
 4311
 4312            // If not handling any auto-close operation, then just replace the selected
 4313            // text with the given input and move the selection to the end of the
 4314            // newly inserted text.
 4315            let anchor = snapshot.anchor_after(selection.end);
 4316            if !self.linked_edit_ranges.is_empty() {
 4317                let start_anchor = snapshot.anchor_before(selection.start);
 4318
 4319                let is_word_char = text.chars().next().is_none_or(|char| {
 4320                    let classifier = snapshot
 4321                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4322                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4323                    classifier.is_word(char)
 4324                });
 4325
 4326                if is_word_char {
 4327                    if let Some(ranges) = self
 4328                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4329                    {
 4330                        for (buffer, edits) in ranges {
 4331                            linked_edits
 4332                                .entry(buffer.clone())
 4333                                .or_default()
 4334                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4335                        }
 4336                    }
 4337                } else {
 4338                    clear_linked_edit_ranges = true;
 4339                }
 4340            }
 4341
 4342            new_selections.push((selection.map(|_| anchor), 0));
 4343            edits.push((selection.start..selection.end, text.clone()));
 4344        }
 4345
 4346        drop(snapshot);
 4347
 4348        self.transact(window, cx, |this, window, cx| {
 4349            if clear_linked_edit_ranges {
 4350                this.linked_edit_ranges.clear();
 4351            }
 4352            let initial_buffer_versions =
 4353                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4354
 4355            this.buffer.update(cx, |buffer, cx| {
 4356                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4357            });
 4358            for (buffer, edits) in linked_edits {
 4359                buffer.update(cx, |buffer, cx| {
 4360                    let snapshot = buffer.snapshot();
 4361                    let edits = edits
 4362                        .into_iter()
 4363                        .map(|(range, text)| {
 4364                            use text::ToPoint as TP;
 4365                            let end_point = TP::to_point(&range.end, &snapshot);
 4366                            let start_point = TP::to_point(&range.start, &snapshot);
 4367                            (start_point..end_point, text)
 4368                        })
 4369                        .sorted_by_key(|(range, _)| range.start);
 4370                    buffer.edit(edits, None, cx);
 4371                })
 4372            }
 4373            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4374            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4375            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4376            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4377                .zip(new_selection_deltas)
 4378                .map(|(selection, delta)| Selection {
 4379                    id: selection.id,
 4380                    start: selection.start + delta,
 4381                    end: selection.end + delta,
 4382                    reversed: selection.reversed,
 4383                    goal: SelectionGoal::None,
 4384                })
 4385                .collect::<Vec<_>>();
 4386
 4387            let mut i = 0;
 4388            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4389                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4390                let start = map.buffer_snapshot().anchor_before(position);
 4391                let end = map.buffer_snapshot().anchor_after(position);
 4392                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4393                    match existing_state
 4394                        .range
 4395                        .start
 4396                        .cmp(&start, map.buffer_snapshot())
 4397                    {
 4398                        Ordering::Less => i += 1,
 4399                        Ordering::Greater => break,
 4400                        Ordering::Equal => {
 4401                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4402                                Ordering::Less => i += 1,
 4403                                Ordering::Equal => break,
 4404                                Ordering::Greater => break,
 4405                            }
 4406                        }
 4407                    }
 4408                }
 4409                this.autoclose_regions.insert(
 4410                    i,
 4411                    AutocloseRegion {
 4412                        selection_id,
 4413                        range: start..end,
 4414                        pair,
 4415                    },
 4416                );
 4417            }
 4418
 4419            let had_active_edit_prediction = this.has_active_edit_prediction();
 4420            this.change_selections(
 4421                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4422                window,
 4423                cx,
 4424                |s| s.select(new_selections),
 4425            );
 4426
 4427            if !bracket_inserted
 4428                && let Some(on_type_format_task) =
 4429                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4430            {
 4431                on_type_format_task.detach_and_log_err(cx);
 4432            }
 4433
 4434            let editor_settings = EditorSettings::get_global(cx);
 4435            if bracket_inserted
 4436                && (editor_settings.auto_signature_help
 4437                    || editor_settings.show_signature_help_after_edits)
 4438            {
 4439                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4440            }
 4441
 4442            let trigger_in_words =
 4443                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4444            if this.hard_wrap.is_some() {
 4445                let latest: Range<Point> = this.selections.newest(&map).range();
 4446                if latest.is_empty()
 4447                    && this
 4448                        .buffer()
 4449                        .read(cx)
 4450                        .snapshot(cx)
 4451                        .line_len(MultiBufferRow(latest.start.row))
 4452                        == latest.start.column
 4453                {
 4454                    this.rewrap_impl(
 4455                        RewrapOptions {
 4456                            override_language_settings: true,
 4457                            preserve_existing_whitespace: true,
 4458                        },
 4459                        cx,
 4460                    )
 4461                }
 4462            }
 4463            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4464            refresh_linked_ranges(this, window, cx);
 4465            this.refresh_edit_prediction(true, false, window, cx);
 4466            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4467        });
 4468    }
 4469
 4470    fn find_possible_emoji_shortcode_at_position(
 4471        snapshot: &MultiBufferSnapshot,
 4472        position: Point,
 4473    ) -> Option<String> {
 4474        let mut chars = Vec::new();
 4475        let mut found_colon = false;
 4476        for char in snapshot.reversed_chars_at(position).take(100) {
 4477            // Found a possible emoji shortcode in the middle of the buffer
 4478            if found_colon {
 4479                if char.is_whitespace() {
 4480                    chars.reverse();
 4481                    return Some(chars.iter().collect());
 4482                }
 4483                // If the previous character is not a whitespace, we are in the middle of a word
 4484                // and we only want to complete the shortcode if the word is made up of other emojis
 4485                let mut containing_word = String::new();
 4486                for ch in snapshot
 4487                    .reversed_chars_at(position)
 4488                    .skip(chars.len() + 1)
 4489                    .take(100)
 4490                {
 4491                    if ch.is_whitespace() {
 4492                        break;
 4493                    }
 4494                    containing_word.push(ch);
 4495                }
 4496                let containing_word = containing_word.chars().rev().collect::<String>();
 4497                if util::word_consists_of_emojis(containing_word.as_str()) {
 4498                    chars.reverse();
 4499                    return Some(chars.iter().collect());
 4500                }
 4501            }
 4502
 4503            if char.is_whitespace() || !char.is_ascii() {
 4504                return None;
 4505            }
 4506            if char == ':' {
 4507                found_colon = true;
 4508            } else {
 4509                chars.push(char);
 4510            }
 4511        }
 4512        // Found a possible emoji shortcode at the beginning of the buffer
 4513        chars.reverse();
 4514        Some(chars.iter().collect())
 4515    }
 4516
 4517    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4518        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4519        self.transact(window, cx, |this, window, cx| {
 4520            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4521                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4522                let multi_buffer = this.buffer.read(cx);
 4523                let buffer = multi_buffer.snapshot(cx);
 4524                selections
 4525                    .iter()
 4526                    .map(|selection| {
 4527                        let start_point = selection.start.to_point(&buffer);
 4528                        let mut existing_indent =
 4529                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4530                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4531                        let start = selection.start;
 4532                        let end = selection.end;
 4533                        let selection_is_empty = start == end;
 4534                        let language_scope = buffer.language_scope_at(start);
 4535                        let (
 4536                            comment_delimiter,
 4537                            doc_delimiter,
 4538                            insert_extra_newline,
 4539                            indent_on_newline,
 4540                            indent_on_extra_newline,
 4541                        ) = if let Some(language) = &language_scope {
 4542                            let mut insert_extra_newline =
 4543                                insert_extra_newline_brackets(&buffer, start..end, language)
 4544                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4545
 4546                            // Comment extension on newline is allowed only for cursor selections
 4547                            let comment_delimiter = maybe!({
 4548                                if !selection_is_empty {
 4549                                    return None;
 4550                                }
 4551
 4552                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4553                                    return None;
 4554                                }
 4555
 4556                                let delimiters = language.line_comment_prefixes();
 4557                                let max_len_of_delimiter =
 4558                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4559                                let (snapshot, range) =
 4560                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4561
 4562                                let num_of_whitespaces = snapshot
 4563                                    .chars_for_range(range.clone())
 4564                                    .take_while(|c| c.is_whitespace())
 4565                                    .count();
 4566                                let comment_candidate = snapshot
 4567                                    .chars_for_range(range.clone())
 4568                                    .skip(num_of_whitespaces)
 4569                                    .take(max_len_of_delimiter)
 4570                                    .collect::<String>();
 4571                                let (delimiter, trimmed_len) = delimiters
 4572                                    .iter()
 4573                                    .filter_map(|delimiter| {
 4574                                        let prefix = delimiter.trim_end();
 4575                                        if comment_candidate.starts_with(prefix) {
 4576                                            Some((delimiter, prefix.len()))
 4577                                        } else {
 4578                                            None
 4579                                        }
 4580                                    })
 4581                                    .max_by_key(|(_, len)| *len)?;
 4582
 4583                                if let Some(BlockCommentConfig {
 4584                                    start: block_start, ..
 4585                                }) = language.block_comment()
 4586                                {
 4587                                    let block_start_trimmed = block_start.trim_end();
 4588                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4589                                        let line_content = snapshot
 4590                                            .chars_for_range(range)
 4591                                            .skip(num_of_whitespaces)
 4592                                            .take(block_start_trimmed.len())
 4593                                            .collect::<String>();
 4594
 4595                                        if line_content.starts_with(block_start_trimmed) {
 4596                                            return None;
 4597                                        }
 4598                                    }
 4599                                }
 4600
 4601                                let cursor_is_placed_after_comment_marker =
 4602                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4603                                if cursor_is_placed_after_comment_marker {
 4604                                    Some(delimiter.clone())
 4605                                } else {
 4606                                    None
 4607                                }
 4608                            });
 4609
 4610                            let mut indent_on_newline = IndentSize::spaces(0);
 4611                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4612
 4613                            let doc_delimiter = maybe!({
 4614                                if !selection_is_empty {
 4615                                    return None;
 4616                                }
 4617
 4618                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4619                                    return None;
 4620                                }
 4621
 4622                                let BlockCommentConfig {
 4623                                    start: start_tag,
 4624                                    end: end_tag,
 4625                                    prefix: delimiter,
 4626                                    tab_size: len,
 4627                                } = language.documentation_comment()?;
 4628                                let is_within_block_comment = buffer
 4629                                    .language_scope_at(start_point)
 4630                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4631                                if !is_within_block_comment {
 4632                                    return None;
 4633                                }
 4634
 4635                                let (snapshot, range) =
 4636                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4637
 4638                                let num_of_whitespaces = snapshot
 4639                                    .chars_for_range(range.clone())
 4640                                    .take_while(|c| c.is_whitespace())
 4641                                    .count();
 4642
 4643                                // 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.
 4644                                let column = start_point.column;
 4645                                let cursor_is_after_start_tag = {
 4646                                    let start_tag_len = start_tag.len();
 4647                                    let start_tag_line = snapshot
 4648                                        .chars_for_range(range.clone())
 4649                                        .skip(num_of_whitespaces)
 4650                                        .take(start_tag_len)
 4651                                        .collect::<String>();
 4652                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4653                                        num_of_whitespaces + start_tag_len <= column as usize
 4654                                    } else {
 4655                                        false
 4656                                    }
 4657                                };
 4658
 4659                                let cursor_is_after_delimiter = {
 4660                                    let delimiter_trim = delimiter.trim_end();
 4661                                    let delimiter_line = snapshot
 4662                                        .chars_for_range(range.clone())
 4663                                        .skip(num_of_whitespaces)
 4664                                        .take(delimiter_trim.len())
 4665                                        .collect::<String>();
 4666                                    if delimiter_line.starts_with(delimiter_trim) {
 4667                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4668                                    } else {
 4669                                        false
 4670                                    }
 4671                                };
 4672
 4673                                let cursor_is_before_end_tag_if_exists = {
 4674                                    let mut char_position = 0u32;
 4675                                    let mut end_tag_offset = None;
 4676
 4677                                    'outer: for chunk in snapshot.text_for_range(range) {
 4678                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4679                                            let chars_before_match =
 4680                                                chunk[..byte_pos].chars().count() as u32;
 4681                                            end_tag_offset =
 4682                                                Some(char_position + chars_before_match);
 4683                                            break 'outer;
 4684                                        }
 4685                                        char_position += chunk.chars().count() as u32;
 4686                                    }
 4687
 4688                                    if let Some(end_tag_offset) = end_tag_offset {
 4689                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4690                                        if cursor_is_after_start_tag {
 4691                                            if cursor_is_before_end_tag {
 4692                                                insert_extra_newline = true;
 4693                                            }
 4694                                            let cursor_is_at_start_of_end_tag =
 4695                                                column == end_tag_offset;
 4696                                            if cursor_is_at_start_of_end_tag {
 4697                                                indent_on_extra_newline.len = *len;
 4698                                            }
 4699                                        }
 4700                                        cursor_is_before_end_tag
 4701                                    } else {
 4702                                        true
 4703                                    }
 4704                                };
 4705
 4706                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4707                                    && cursor_is_before_end_tag_if_exists
 4708                                {
 4709                                    if cursor_is_after_start_tag {
 4710                                        indent_on_newline.len = *len;
 4711                                    }
 4712                                    Some(delimiter.clone())
 4713                                } else {
 4714                                    None
 4715                                }
 4716                            });
 4717
 4718                            (
 4719                                comment_delimiter,
 4720                                doc_delimiter,
 4721                                insert_extra_newline,
 4722                                indent_on_newline,
 4723                                indent_on_extra_newline,
 4724                            )
 4725                        } else {
 4726                            (
 4727                                None,
 4728                                None,
 4729                                false,
 4730                                IndentSize::default(),
 4731                                IndentSize::default(),
 4732                            )
 4733                        };
 4734
 4735                        let prevent_auto_indent = doc_delimiter.is_some();
 4736                        let delimiter = comment_delimiter.or(doc_delimiter);
 4737
 4738                        let capacity_for_delimiter =
 4739                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4740                        let mut new_text = String::with_capacity(
 4741                            1 + capacity_for_delimiter
 4742                                + existing_indent.len as usize
 4743                                + indent_on_newline.len as usize
 4744                                + indent_on_extra_newline.len as usize,
 4745                        );
 4746                        new_text.push('\n');
 4747                        new_text.extend(existing_indent.chars());
 4748                        new_text.extend(indent_on_newline.chars());
 4749
 4750                        if let Some(delimiter) = &delimiter {
 4751                            new_text.push_str(delimiter);
 4752                        }
 4753
 4754                        if insert_extra_newline {
 4755                            new_text.push('\n');
 4756                            new_text.extend(existing_indent.chars());
 4757                            new_text.extend(indent_on_extra_newline.chars());
 4758                        }
 4759
 4760                        let anchor = buffer.anchor_after(end);
 4761                        let new_selection = selection.map(|_| anchor);
 4762                        (
 4763                            ((start..end, new_text), prevent_auto_indent),
 4764                            (insert_extra_newline, new_selection),
 4765                        )
 4766                    })
 4767                    .unzip()
 4768            };
 4769
 4770            let mut auto_indent_edits = Vec::new();
 4771            let mut edits = Vec::new();
 4772            for (edit, prevent_auto_indent) in edits_with_flags {
 4773                if prevent_auto_indent {
 4774                    edits.push(edit);
 4775                } else {
 4776                    auto_indent_edits.push(edit);
 4777                }
 4778            }
 4779            if !edits.is_empty() {
 4780                this.edit(edits, cx);
 4781            }
 4782            if !auto_indent_edits.is_empty() {
 4783                this.edit_with_autoindent(auto_indent_edits, cx);
 4784            }
 4785
 4786            let buffer = this.buffer.read(cx).snapshot(cx);
 4787            let new_selections = selection_info
 4788                .into_iter()
 4789                .map(|(extra_newline_inserted, new_selection)| {
 4790                    let mut cursor = new_selection.end.to_point(&buffer);
 4791                    if extra_newline_inserted {
 4792                        cursor.row -= 1;
 4793                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4794                    }
 4795                    new_selection.map(|_| cursor)
 4796                })
 4797                .collect();
 4798
 4799            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4800            this.refresh_edit_prediction(true, false, window, cx);
 4801        });
 4802    }
 4803
 4804    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4805        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4806
 4807        let buffer = self.buffer.read(cx);
 4808        let snapshot = buffer.snapshot(cx);
 4809
 4810        let mut edits = Vec::new();
 4811        let mut rows = Vec::new();
 4812
 4813        for (rows_inserted, selection) in self
 4814            .selections
 4815            .all_adjusted(&self.display_snapshot(cx))
 4816            .into_iter()
 4817            .enumerate()
 4818        {
 4819            let cursor = selection.head();
 4820            let row = cursor.row;
 4821
 4822            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4823
 4824            let newline = "\n".to_string();
 4825            edits.push((start_of_line..start_of_line, newline));
 4826
 4827            rows.push(row + rows_inserted as u32);
 4828        }
 4829
 4830        self.transact(window, cx, |editor, window, cx| {
 4831            editor.edit(edits, cx);
 4832
 4833            editor.change_selections(Default::default(), window, cx, |s| {
 4834                let mut index = 0;
 4835                s.move_cursors_with(|map, _, _| {
 4836                    let row = rows[index];
 4837                    index += 1;
 4838
 4839                    let point = Point::new(row, 0);
 4840                    let boundary = map.next_line_boundary(point).1;
 4841                    let clipped = map.clip_point(boundary, Bias::Left);
 4842
 4843                    (clipped, SelectionGoal::None)
 4844                });
 4845            });
 4846
 4847            let mut indent_edits = Vec::new();
 4848            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4849            for row in rows {
 4850                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4851                for (row, indent) in indents {
 4852                    if indent.len == 0 {
 4853                        continue;
 4854                    }
 4855
 4856                    let text = match indent.kind {
 4857                        IndentKind::Space => " ".repeat(indent.len as usize),
 4858                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4859                    };
 4860                    let point = Point::new(row.0, 0);
 4861                    indent_edits.push((point..point, text));
 4862                }
 4863            }
 4864            editor.edit(indent_edits, cx);
 4865        });
 4866    }
 4867
 4868    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4869        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4870
 4871        let buffer = self.buffer.read(cx);
 4872        let snapshot = buffer.snapshot(cx);
 4873
 4874        let mut edits = Vec::new();
 4875        let mut rows = Vec::new();
 4876        let mut rows_inserted = 0;
 4877
 4878        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4879            let cursor = selection.head();
 4880            let row = cursor.row;
 4881
 4882            let point = Point::new(row + 1, 0);
 4883            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4884
 4885            let newline = "\n".to_string();
 4886            edits.push((start_of_line..start_of_line, newline));
 4887
 4888            rows_inserted += 1;
 4889            rows.push(row + rows_inserted);
 4890        }
 4891
 4892        self.transact(window, cx, |editor, window, cx| {
 4893            editor.edit(edits, cx);
 4894
 4895            editor.change_selections(Default::default(), window, cx, |s| {
 4896                let mut index = 0;
 4897                s.move_cursors_with(|map, _, _| {
 4898                    let row = rows[index];
 4899                    index += 1;
 4900
 4901                    let point = Point::new(row, 0);
 4902                    let boundary = map.next_line_boundary(point).1;
 4903                    let clipped = map.clip_point(boundary, Bias::Left);
 4904
 4905                    (clipped, SelectionGoal::None)
 4906                });
 4907            });
 4908
 4909            let mut indent_edits = Vec::new();
 4910            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4911            for row in rows {
 4912                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4913                for (row, indent) in indents {
 4914                    if indent.len == 0 {
 4915                        continue;
 4916                    }
 4917
 4918                    let text = match indent.kind {
 4919                        IndentKind::Space => " ".repeat(indent.len as usize),
 4920                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4921                    };
 4922                    let point = Point::new(row.0, 0);
 4923                    indent_edits.push((point..point, text));
 4924                }
 4925            }
 4926            editor.edit(indent_edits, cx);
 4927        });
 4928    }
 4929
 4930    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4931        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4932            original_indent_columns: Vec::new(),
 4933        });
 4934        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4935    }
 4936
 4937    fn insert_with_autoindent_mode(
 4938        &mut self,
 4939        text: &str,
 4940        autoindent_mode: Option<AutoindentMode>,
 4941        window: &mut Window,
 4942        cx: &mut Context<Self>,
 4943    ) {
 4944        if self.read_only(cx) {
 4945            return;
 4946        }
 4947
 4948        let text: Arc<str> = text.into();
 4949        self.transact(window, cx, |this, window, cx| {
 4950            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4951            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4952                let anchors = {
 4953                    let snapshot = buffer.read(cx);
 4954                    old_selections
 4955                        .iter()
 4956                        .map(|s| {
 4957                            let anchor = snapshot.anchor_after(s.head());
 4958                            s.map(|_| anchor)
 4959                        })
 4960                        .collect::<Vec<_>>()
 4961                };
 4962                buffer.edit(
 4963                    old_selections
 4964                        .iter()
 4965                        .map(|s| (s.start..s.end, text.clone())),
 4966                    autoindent_mode,
 4967                    cx,
 4968                );
 4969                anchors
 4970            });
 4971
 4972            this.change_selections(Default::default(), window, cx, |s| {
 4973                s.select_anchors(selection_anchors);
 4974            });
 4975
 4976            cx.notify();
 4977        });
 4978    }
 4979
 4980    fn trigger_completion_on_input(
 4981        &mut self,
 4982        text: &str,
 4983        trigger_in_words: bool,
 4984        window: &mut Window,
 4985        cx: &mut Context<Self>,
 4986    ) {
 4987        let completions_source = self
 4988            .context_menu
 4989            .borrow()
 4990            .as_ref()
 4991            .and_then(|menu| match menu {
 4992                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4993                CodeContextMenu::CodeActions(_) => None,
 4994            });
 4995
 4996        match completions_source {
 4997            Some(CompletionsMenuSource::Words { .. }) => {
 4998                self.open_or_update_completions_menu(
 4999                    Some(CompletionsMenuSource::Words {
 5000                        ignore_threshold: false,
 5001                    }),
 5002                    None,
 5003                    window,
 5004                    cx,
 5005                );
 5006            }
 5007            Some(CompletionsMenuSource::Normal)
 5008            | Some(CompletionsMenuSource::SnippetChoices)
 5009            | None
 5010                if self.is_completion_trigger(
 5011                    text,
 5012                    trigger_in_words,
 5013                    completions_source.is_some(),
 5014                    cx,
 5015                ) =>
 5016            {
 5017                self.show_completions(
 5018                    &ShowCompletions {
 5019                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 5020                    },
 5021                    window,
 5022                    cx,
 5023                )
 5024            }
 5025            _ => {
 5026                self.hide_context_menu(window, cx);
 5027            }
 5028        }
 5029    }
 5030
 5031    fn is_completion_trigger(
 5032        &self,
 5033        text: &str,
 5034        trigger_in_words: bool,
 5035        menu_is_open: bool,
 5036        cx: &mut Context<Self>,
 5037    ) -> bool {
 5038        let position = self.selections.newest_anchor().head();
 5039        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5040            return false;
 5041        };
 5042
 5043        if let Some(completion_provider) = &self.completion_provider {
 5044            completion_provider.is_completion_trigger(
 5045                &buffer,
 5046                position.text_anchor,
 5047                text,
 5048                trigger_in_words,
 5049                menu_is_open,
 5050                cx,
 5051            )
 5052        } else {
 5053            false
 5054        }
 5055    }
 5056
 5057    /// If any empty selections is touching the start of its innermost containing autoclose
 5058    /// region, expand it to select the brackets.
 5059    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5060        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5061        let buffer = self.buffer.read(cx).read(cx);
 5062        let new_selections = self
 5063            .selections_with_autoclose_regions(selections, &buffer)
 5064            .map(|(mut selection, region)| {
 5065                if !selection.is_empty() {
 5066                    return selection;
 5067                }
 5068
 5069                if let Some(region) = region {
 5070                    let mut range = region.range.to_offset(&buffer);
 5071                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5072                        range.start -= region.pair.start.len();
 5073                        if buffer.contains_str_at(range.start, &region.pair.start)
 5074                            && buffer.contains_str_at(range.end, &region.pair.end)
 5075                        {
 5076                            range.end += region.pair.end.len();
 5077                            selection.start = range.start;
 5078                            selection.end = range.end;
 5079
 5080                            return selection;
 5081                        }
 5082                    }
 5083                }
 5084
 5085                let always_treat_brackets_as_autoclosed = buffer
 5086                    .language_settings_at(selection.start, cx)
 5087                    .always_treat_brackets_as_autoclosed;
 5088
 5089                if !always_treat_brackets_as_autoclosed {
 5090                    return selection;
 5091                }
 5092
 5093                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5094                    for (pair, enabled) in scope.brackets() {
 5095                        if !enabled || !pair.close {
 5096                            continue;
 5097                        }
 5098
 5099                        if buffer.contains_str_at(selection.start, &pair.end) {
 5100                            let pair_start_len = pair.start.len();
 5101                            if buffer.contains_str_at(
 5102                                selection.start.saturating_sub(pair_start_len),
 5103                                &pair.start,
 5104                            ) {
 5105                                selection.start -= pair_start_len;
 5106                                selection.end += pair.end.len();
 5107
 5108                                return selection;
 5109                            }
 5110                        }
 5111                    }
 5112                }
 5113
 5114                selection
 5115            })
 5116            .collect();
 5117
 5118        drop(buffer);
 5119        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5120            selections.select(new_selections)
 5121        });
 5122    }
 5123
 5124    /// Iterate the given selections, and for each one, find the smallest surrounding
 5125    /// autoclose region. This uses the ordering of the selections and the autoclose
 5126    /// regions to avoid repeated comparisons.
 5127    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5128        &'a self,
 5129        selections: impl IntoIterator<Item = Selection<D>>,
 5130        buffer: &'a MultiBufferSnapshot,
 5131    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5132        let mut i = 0;
 5133        let mut regions = self.autoclose_regions.as_slice();
 5134        selections.into_iter().map(move |selection| {
 5135            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5136
 5137            let mut enclosing = None;
 5138            while let Some(pair_state) = regions.get(i) {
 5139                if pair_state.range.end.to_offset(buffer) < range.start {
 5140                    regions = &regions[i + 1..];
 5141                    i = 0;
 5142                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5143                    break;
 5144                } else {
 5145                    if pair_state.selection_id == selection.id {
 5146                        enclosing = Some(pair_state);
 5147                    }
 5148                    i += 1;
 5149                }
 5150            }
 5151
 5152            (selection, enclosing)
 5153        })
 5154    }
 5155
 5156    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5157    fn invalidate_autoclose_regions(
 5158        &mut self,
 5159        mut selections: &[Selection<Anchor>],
 5160        buffer: &MultiBufferSnapshot,
 5161    ) {
 5162        self.autoclose_regions.retain(|state| {
 5163            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5164                return false;
 5165            }
 5166
 5167            let mut i = 0;
 5168            while let Some(selection) = selections.get(i) {
 5169                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5170                    selections = &selections[1..];
 5171                    continue;
 5172                }
 5173                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5174                    break;
 5175                }
 5176                if selection.id == state.selection_id {
 5177                    return true;
 5178                } else {
 5179                    i += 1;
 5180                }
 5181            }
 5182            false
 5183        });
 5184    }
 5185
 5186    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5187        let offset = position.to_offset(buffer);
 5188        let (word_range, kind) =
 5189            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5190        if offset > word_range.start && kind == Some(CharKind::Word) {
 5191            Some(
 5192                buffer
 5193                    .text_for_range(word_range.start..offset)
 5194                    .collect::<String>(),
 5195            )
 5196        } else {
 5197            None
 5198        }
 5199    }
 5200
 5201    pub fn toggle_inline_values(
 5202        &mut self,
 5203        _: &ToggleInlineValues,
 5204        _: &mut Window,
 5205        cx: &mut Context<Self>,
 5206    ) {
 5207        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5208
 5209        self.refresh_inline_values(cx);
 5210    }
 5211
 5212    pub fn toggle_inlay_hints(
 5213        &mut self,
 5214        _: &ToggleInlayHints,
 5215        _: &mut Window,
 5216        cx: &mut Context<Self>,
 5217    ) {
 5218        self.refresh_inlay_hints(
 5219            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5220            cx,
 5221        );
 5222    }
 5223
 5224    pub fn inlay_hints_enabled(&self) -> bool {
 5225        self.inlay_hint_cache.enabled
 5226    }
 5227
 5228    pub fn inline_values_enabled(&self) -> bool {
 5229        self.inline_value_cache.enabled
 5230    }
 5231
 5232    #[cfg(any(test, feature = "test-support"))]
 5233    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5234        self.display_map
 5235            .read(cx)
 5236            .current_inlays()
 5237            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5238            .cloned()
 5239            .collect()
 5240    }
 5241
 5242    #[cfg(any(test, feature = "test-support"))]
 5243    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5244        self.display_map
 5245            .read(cx)
 5246            .current_inlays()
 5247            .cloned()
 5248            .collect()
 5249    }
 5250
 5251    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5252        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5253            return;
 5254        }
 5255
 5256        let reason_description = reason.description();
 5257        let ignore_debounce = matches!(
 5258            reason,
 5259            InlayHintRefreshReason::SettingsChange(_)
 5260                | InlayHintRefreshReason::Toggle(_)
 5261                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5262                | InlayHintRefreshReason::ModifiersChanged(_)
 5263        );
 5264        let (invalidate_cache, required_languages) = match reason {
 5265            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5266                match self.inlay_hint_cache.modifiers_override(enabled) {
 5267                    Some(enabled) => {
 5268                        if enabled {
 5269                            (InvalidationStrategy::RefreshRequested, None)
 5270                        } else {
 5271                            self.clear_inlay_hints(cx);
 5272                            return;
 5273                        }
 5274                    }
 5275                    None => return,
 5276                }
 5277            }
 5278            InlayHintRefreshReason::Toggle(enabled) => {
 5279                if self.inlay_hint_cache.toggle(enabled) {
 5280                    if enabled {
 5281                        (InvalidationStrategy::RefreshRequested, None)
 5282                    } else {
 5283                        self.clear_inlay_hints(cx);
 5284                        return;
 5285                    }
 5286                } else {
 5287                    return;
 5288                }
 5289            }
 5290            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5291                match self.inlay_hint_cache.update_settings(
 5292                    &self.buffer,
 5293                    new_settings,
 5294                    self.visible_inlay_hints(cx).cloned().collect::<Vec<_>>(),
 5295                    cx,
 5296                ) {
 5297                    ControlFlow::Break(Some(InlaySplice {
 5298                        to_remove,
 5299                        to_insert,
 5300                    })) => {
 5301                        self.splice_inlays(&to_remove, to_insert, cx);
 5302                        return;
 5303                    }
 5304                    ControlFlow::Break(None) => return,
 5305                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5306                }
 5307            }
 5308            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5309                if let Some(InlaySplice {
 5310                    to_remove,
 5311                    to_insert,
 5312                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5313                {
 5314                    self.splice_inlays(&to_remove, to_insert, cx);
 5315                }
 5316                self.display_map.update(cx, |display_map, cx| {
 5317                    display_map.remove_inlays_for_excerpts(&excerpts_removed, cx)
 5318                });
 5319                return;
 5320            }
 5321            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5322            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5323                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5324            }
 5325            InlayHintRefreshReason::RefreshRequested => {
 5326                (InvalidationStrategy::RefreshRequested, None)
 5327            }
 5328        };
 5329
 5330        let mut visible_excerpts = self.visible_excerpts(required_languages.as_ref(), cx);
 5331        visible_excerpts.retain(|_, (buffer, _, _)| {
 5332            self.registered_buffers
 5333                .contains_key(&buffer.read(cx).remote_id())
 5334        });
 5335
 5336        if let Some(InlaySplice {
 5337            to_remove,
 5338            to_insert,
 5339        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5340            reason_description,
 5341            visible_excerpts,
 5342            invalidate_cache,
 5343            ignore_debounce,
 5344            cx,
 5345        ) {
 5346            self.splice_inlays(&to_remove, to_insert, cx);
 5347        }
 5348    }
 5349
 5350    pub fn clear_inlay_hints(&self, cx: &mut Context<Editor>) {
 5351        self.splice_inlays(
 5352            &self
 5353                .visible_inlay_hints(cx)
 5354                .map(|inlay| inlay.id)
 5355                .collect::<Vec<_>>(),
 5356            Vec::new(),
 5357            cx,
 5358        );
 5359    }
 5360
 5361    fn visible_inlay_hints<'a>(
 5362        &'a self,
 5363        cx: &'a Context<Editor>,
 5364    ) -> impl Iterator<Item = &'a Inlay> {
 5365        self.display_map
 5366            .read(cx)
 5367            .current_inlays()
 5368            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5369    }
 5370
 5371    pub fn visible_excerpts(
 5372        &self,
 5373        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5374        cx: &mut Context<Editor>,
 5375    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5376        let Some(project) = self.project() else {
 5377            return HashMap::default();
 5378        };
 5379        let project = project.read(cx);
 5380        let multi_buffer = self.buffer().read(cx);
 5381        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5382        let multi_buffer_visible_start = self
 5383            .scroll_manager
 5384            .anchor()
 5385            .anchor
 5386            .to_point(&multi_buffer_snapshot);
 5387        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5388            multi_buffer_visible_start
 5389                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5390            Bias::Left,
 5391        );
 5392        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5393        multi_buffer_snapshot
 5394            .range_to_buffer_ranges(multi_buffer_visible_range)
 5395            .into_iter()
 5396            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5397            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5398                let buffer_file = project::File::from_dyn(buffer.file())?;
 5399                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5400                let worktree_entry = buffer_worktree
 5401                    .read(cx)
 5402                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5403                if worktree_entry.is_ignored {
 5404                    return None;
 5405                }
 5406
 5407                let language = buffer.language()?;
 5408                if let Some(restrict_to_languages) = restrict_to_languages
 5409                    && !restrict_to_languages.contains(language)
 5410                {
 5411                    return None;
 5412                }
 5413                Some((
 5414                    excerpt_id,
 5415                    (
 5416                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5417                        buffer.version().clone(),
 5418                        excerpt_visible_range,
 5419                    ),
 5420                ))
 5421            })
 5422            .collect()
 5423    }
 5424
 5425    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5426        TextLayoutDetails {
 5427            text_system: window.text_system().clone(),
 5428            editor_style: self.style.clone().unwrap(),
 5429            rem_size: window.rem_size(),
 5430            scroll_anchor: self.scroll_manager.anchor(),
 5431            visible_rows: self.visible_line_count(),
 5432            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5433        }
 5434    }
 5435
 5436    pub fn splice_inlays(
 5437        &self,
 5438        to_remove: &[InlayId],
 5439        to_insert: Vec<Inlay>,
 5440        cx: &mut Context<Self>,
 5441    ) {
 5442        self.display_map.update(cx, |display_map, cx| {
 5443            display_map.splice_inlays(to_remove, to_insert, cx)
 5444        });
 5445        cx.notify();
 5446    }
 5447
 5448    fn trigger_on_type_formatting(
 5449        &self,
 5450        input: String,
 5451        window: &mut Window,
 5452        cx: &mut Context<Self>,
 5453    ) -> Option<Task<Result<()>>> {
 5454        if input.len() != 1 {
 5455            return None;
 5456        }
 5457
 5458        let project = self.project()?;
 5459        let position = self.selections.newest_anchor().head();
 5460        let (buffer, buffer_position) = self
 5461            .buffer
 5462            .read(cx)
 5463            .text_anchor_for_position(position, cx)?;
 5464
 5465        let settings = language_settings::language_settings(
 5466            buffer
 5467                .read(cx)
 5468                .language_at(buffer_position)
 5469                .map(|l| l.name()),
 5470            buffer.read(cx).file(),
 5471            cx,
 5472        );
 5473        if !settings.use_on_type_format {
 5474            return None;
 5475        }
 5476
 5477        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5478        // hence we do LSP request & edit on host side only — add formats to host's history.
 5479        let push_to_lsp_host_history = true;
 5480        // If this is not the host, append its history with new edits.
 5481        let push_to_client_history = project.read(cx).is_via_collab();
 5482
 5483        let on_type_formatting = project.update(cx, |project, cx| {
 5484            project.on_type_format(
 5485                buffer.clone(),
 5486                buffer_position,
 5487                input,
 5488                push_to_lsp_host_history,
 5489                cx,
 5490            )
 5491        });
 5492        Some(cx.spawn_in(window, async move |editor, cx| {
 5493            if let Some(transaction) = on_type_formatting.await? {
 5494                if push_to_client_history {
 5495                    buffer
 5496                        .update(cx, |buffer, _| {
 5497                            buffer.push_transaction(transaction, Instant::now());
 5498                            buffer.finalize_last_transaction();
 5499                        })
 5500                        .ok();
 5501                }
 5502                editor.update(cx, |editor, cx| {
 5503                    editor.refresh_document_highlights(cx);
 5504                })?;
 5505            }
 5506            Ok(())
 5507        }))
 5508    }
 5509
 5510    pub fn show_word_completions(
 5511        &mut self,
 5512        _: &ShowWordCompletions,
 5513        window: &mut Window,
 5514        cx: &mut Context<Self>,
 5515    ) {
 5516        self.open_or_update_completions_menu(
 5517            Some(CompletionsMenuSource::Words {
 5518                ignore_threshold: true,
 5519            }),
 5520            None,
 5521            window,
 5522            cx,
 5523        );
 5524    }
 5525
 5526    pub fn show_completions(
 5527        &mut self,
 5528        options: &ShowCompletions,
 5529        window: &mut Window,
 5530        cx: &mut Context<Self>,
 5531    ) {
 5532        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5533    }
 5534
 5535    fn open_or_update_completions_menu(
 5536        &mut self,
 5537        requested_source: Option<CompletionsMenuSource>,
 5538        trigger: Option<&str>,
 5539        window: &mut Window,
 5540        cx: &mut Context<Self>,
 5541    ) {
 5542        if self.pending_rename.is_some() {
 5543            return;
 5544        }
 5545
 5546        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5547
 5548        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5549        // inserted and selected. To handle that case, the start of the selection is used so that
 5550        // the menu starts with all choices.
 5551        let position = self
 5552            .selections
 5553            .newest_anchor()
 5554            .start
 5555            .bias_right(&multibuffer_snapshot);
 5556        if position.diff_base_anchor.is_some() {
 5557            return;
 5558        }
 5559        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5560        let Some(buffer) = buffer_position
 5561            .buffer_id
 5562            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5563        else {
 5564            return;
 5565        };
 5566        let buffer_snapshot = buffer.read(cx).snapshot();
 5567
 5568        let query: Option<Arc<String>> =
 5569            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5570                .map(|query| query.into());
 5571
 5572        drop(multibuffer_snapshot);
 5573
 5574        // Hide the current completions menu when query is empty. Without this, cached
 5575        // completions from before the trigger char may be reused (#32774).
 5576        if query.is_none() {
 5577            let menu_is_open = matches!(
 5578                self.context_menu.borrow().as_ref(),
 5579                Some(CodeContextMenu::Completions(_))
 5580            );
 5581            if menu_is_open {
 5582                self.hide_context_menu(window, cx);
 5583            }
 5584        }
 5585
 5586        let mut ignore_word_threshold = false;
 5587        let provider = match requested_source {
 5588            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5589            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5590                ignore_word_threshold = ignore_threshold;
 5591                None
 5592            }
 5593            Some(CompletionsMenuSource::SnippetChoices) => {
 5594                log::error!("bug: SnippetChoices requested_source is not handled");
 5595                None
 5596            }
 5597        };
 5598
 5599        let sort_completions = provider
 5600            .as_ref()
 5601            .is_some_and(|provider| provider.sort_completions());
 5602
 5603        let filter_completions = provider
 5604            .as_ref()
 5605            .is_none_or(|provider| provider.filter_completions());
 5606
 5607        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5608            if filter_completions {
 5609                menu.filter(query.clone(), provider.clone(), window, cx);
 5610            }
 5611            // When `is_incomplete` is false, no need to re-query completions when the current query
 5612            // is a suffix of the initial query.
 5613            if !menu.is_incomplete {
 5614                // If the new query is a suffix of the old query (typing more characters) and
 5615                // the previous result was complete, the existing completions can be filtered.
 5616                //
 5617                // Note that this is always true for snippet completions.
 5618                let query_matches = match (&menu.initial_query, &query) {
 5619                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5620                    (None, _) => true,
 5621                    _ => false,
 5622                };
 5623                if query_matches {
 5624                    let position_matches = if menu.initial_position == position {
 5625                        true
 5626                    } else {
 5627                        let snapshot = self.buffer.read(cx).read(cx);
 5628                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5629                    };
 5630                    if position_matches {
 5631                        return;
 5632                    }
 5633                }
 5634            }
 5635        };
 5636
 5637        let trigger_kind = match trigger {
 5638            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5639                CompletionTriggerKind::TRIGGER_CHARACTER
 5640            }
 5641            _ => CompletionTriggerKind::INVOKED,
 5642        };
 5643        let completion_context = CompletionContext {
 5644            trigger_character: trigger.and_then(|trigger| {
 5645                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5646                    Some(String::from(trigger))
 5647                } else {
 5648                    None
 5649                }
 5650            }),
 5651            trigger_kind,
 5652        };
 5653
 5654        let Anchor {
 5655            excerpt_id: buffer_excerpt_id,
 5656            text_anchor: buffer_position,
 5657            ..
 5658        } = buffer_position;
 5659
 5660        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5661            buffer_snapshot.surrounding_word(buffer_position, None)
 5662        {
 5663            let word_to_exclude = buffer_snapshot
 5664                .text_for_range(word_range.clone())
 5665                .collect::<String>();
 5666            (
 5667                buffer_snapshot.anchor_before(word_range.start)
 5668                    ..buffer_snapshot.anchor_after(buffer_position),
 5669                Some(word_to_exclude),
 5670            )
 5671        } else {
 5672            (buffer_position..buffer_position, None)
 5673        };
 5674
 5675        let language = buffer_snapshot
 5676            .language_at(buffer_position)
 5677            .map(|language| language.name());
 5678
 5679        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5680            .completions
 5681            .clone();
 5682
 5683        let show_completion_documentation = buffer_snapshot
 5684            .settings_at(buffer_position, cx)
 5685            .show_completion_documentation;
 5686
 5687        // The document can be large, so stay in reasonable bounds when searching for words,
 5688        // otherwise completion pop-up might be slow to appear.
 5689        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5690        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5691        let min_word_search = buffer_snapshot.clip_point(
 5692            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5693            Bias::Left,
 5694        );
 5695        let max_word_search = buffer_snapshot.clip_point(
 5696            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5697            Bias::Right,
 5698        );
 5699        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5700            ..buffer_snapshot.point_to_offset(max_word_search);
 5701
 5702        let skip_digits = query
 5703            .as_ref()
 5704            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5705
 5706        let omit_word_completions = !self.word_completions_enabled
 5707            || (!ignore_word_threshold
 5708                && match &query {
 5709                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5710                    None => completion_settings.words_min_length != 0,
 5711                });
 5712
 5713        let (mut words, provider_responses) = match &provider {
 5714            Some(provider) => {
 5715                let provider_responses = provider.completions(
 5716                    buffer_excerpt_id,
 5717                    &buffer,
 5718                    buffer_position,
 5719                    completion_context,
 5720                    window,
 5721                    cx,
 5722                );
 5723
 5724                let words = match (omit_word_completions, completion_settings.words) {
 5725                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5726                        Task::ready(BTreeMap::default())
 5727                    }
 5728                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5729                        .background_spawn(async move {
 5730                            buffer_snapshot.words_in_range(WordsQuery {
 5731                                fuzzy_contents: None,
 5732                                range: word_search_range,
 5733                                skip_digits,
 5734                            })
 5735                        }),
 5736                };
 5737
 5738                (words, provider_responses)
 5739            }
 5740            None => {
 5741                let words = if omit_word_completions {
 5742                    Task::ready(BTreeMap::default())
 5743                } else {
 5744                    cx.background_spawn(async move {
 5745                        buffer_snapshot.words_in_range(WordsQuery {
 5746                            fuzzy_contents: None,
 5747                            range: word_search_range,
 5748                            skip_digits,
 5749                        })
 5750                    })
 5751                };
 5752                (words, Task::ready(Ok(Vec::new())))
 5753            }
 5754        };
 5755
 5756        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5757
 5758        let id = post_inc(&mut self.next_completion_id);
 5759        let task = cx.spawn_in(window, async move |editor, cx| {
 5760            let Ok(()) = editor.update(cx, |this, _| {
 5761                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5762            }) else {
 5763                return;
 5764            };
 5765
 5766            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5767            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5768            let mut completions = Vec::new();
 5769            let mut is_incomplete = false;
 5770            let mut display_options: Option<CompletionDisplayOptions> = None;
 5771            if let Some(provider_responses) = provider_responses.await.log_err()
 5772                && !provider_responses.is_empty()
 5773            {
 5774                for response in provider_responses {
 5775                    completions.extend(response.completions);
 5776                    is_incomplete = is_incomplete || response.is_incomplete;
 5777                    match display_options.as_mut() {
 5778                        None => {
 5779                            display_options = Some(response.display_options);
 5780                        }
 5781                        Some(options) => options.merge(&response.display_options),
 5782                    }
 5783                }
 5784                if completion_settings.words == WordsCompletionMode::Fallback {
 5785                    words = Task::ready(BTreeMap::default());
 5786                }
 5787            }
 5788            let display_options = display_options.unwrap_or_default();
 5789
 5790            let mut words = words.await;
 5791            if let Some(word_to_exclude) = &word_to_exclude {
 5792                words.remove(word_to_exclude);
 5793            }
 5794            for lsp_completion in &completions {
 5795                words.remove(&lsp_completion.new_text);
 5796            }
 5797            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5798                replace_range: word_replace_range.clone(),
 5799                new_text: word.clone(),
 5800                label: CodeLabel::plain(word, None),
 5801                icon_path: None,
 5802                documentation: None,
 5803                source: CompletionSource::BufferWord {
 5804                    word_range,
 5805                    resolved: false,
 5806                },
 5807                insert_text_mode: Some(InsertTextMode::AS_IS),
 5808                confirm: None,
 5809            }));
 5810
 5811            let menu = if completions.is_empty() {
 5812                None
 5813            } else {
 5814                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5815                    let languages = editor
 5816                        .workspace
 5817                        .as_ref()
 5818                        .and_then(|(workspace, _)| workspace.upgrade())
 5819                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5820                    let menu = CompletionsMenu::new(
 5821                        id,
 5822                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5823                        sort_completions,
 5824                        show_completion_documentation,
 5825                        position,
 5826                        query.clone(),
 5827                        is_incomplete,
 5828                        buffer.clone(),
 5829                        completions.into(),
 5830                        display_options,
 5831                        snippet_sort_order,
 5832                        languages,
 5833                        language,
 5834                        cx,
 5835                    );
 5836
 5837                    let query = if filter_completions { query } else { None };
 5838                    let matches_task = if let Some(query) = query {
 5839                        menu.do_async_filtering(query, cx)
 5840                    } else {
 5841                        Task::ready(menu.unfiltered_matches())
 5842                    };
 5843                    (menu, matches_task)
 5844                }) else {
 5845                    return;
 5846                };
 5847
 5848                let matches = matches_task.await;
 5849
 5850                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5851                    // Newer menu already set, so exit.
 5852                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5853                        editor.context_menu.borrow().as_ref()
 5854                        && prev_menu.id > id
 5855                    {
 5856                        return;
 5857                    };
 5858
 5859                    // Only valid to take prev_menu because it the new menu is immediately set
 5860                    // below, or the menu is hidden.
 5861                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5862                        editor.context_menu.borrow_mut().take()
 5863                    {
 5864                        let position_matches =
 5865                            if prev_menu.initial_position == menu.initial_position {
 5866                                true
 5867                            } else {
 5868                                let snapshot = editor.buffer.read(cx).read(cx);
 5869                                prev_menu.initial_position.to_offset(&snapshot)
 5870                                    == menu.initial_position.to_offset(&snapshot)
 5871                            };
 5872                        if position_matches {
 5873                            // Preserve markdown cache before `set_filter_results` because it will
 5874                            // try to populate the documentation cache.
 5875                            menu.preserve_markdown_cache(prev_menu);
 5876                        }
 5877                    };
 5878
 5879                    menu.set_filter_results(matches, provider, window, cx);
 5880                }) else {
 5881                    return;
 5882                };
 5883
 5884                menu.visible().then_some(menu)
 5885            };
 5886
 5887            editor
 5888                .update_in(cx, |editor, window, cx| {
 5889                    if editor.focus_handle.is_focused(window)
 5890                        && let Some(menu) = menu
 5891                    {
 5892                        *editor.context_menu.borrow_mut() =
 5893                            Some(CodeContextMenu::Completions(menu));
 5894
 5895                        crate::hover_popover::hide_hover(editor, cx);
 5896                        if editor.show_edit_predictions_in_menu() {
 5897                            editor.update_visible_edit_prediction(window, cx);
 5898                        } else {
 5899                            editor.discard_edit_prediction(false, cx);
 5900                        }
 5901
 5902                        cx.notify();
 5903                        return;
 5904                    }
 5905
 5906                    if editor.completion_tasks.len() <= 1 {
 5907                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5908                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5909                        // If it was already hidden and we don't show edit predictions in the menu,
 5910                        // we should also show the edit prediction when available.
 5911                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5912                            editor.update_visible_edit_prediction(window, cx);
 5913                        }
 5914                    }
 5915                })
 5916                .ok();
 5917        });
 5918
 5919        self.completion_tasks.push((id, task));
 5920    }
 5921
 5922    #[cfg(feature = "test-support")]
 5923    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5924        let menu = self.context_menu.borrow();
 5925        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5926            let completions = menu.completions.borrow();
 5927            Some(completions.to_vec())
 5928        } else {
 5929            None
 5930        }
 5931    }
 5932
 5933    pub fn with_completions_menu_matching_id<R>(
 5934        &self,
 5935        id: CompletionId,
 5936        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5937    ) -> R {
 5938        let mut context_menu = self.context_menu.borrow_mut();
 5939        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5940            return f(None);
 5941        };
 5942        if completions_menu.id != id {
 5943            return f(None);
 5944        }
 5945        f(Some(completions_menu))
 5946    }
 5947
 5948    pub fn confirm_completion(
 5949        &mut self,
 5950        action: &ConfirmCompletion,
 5951        window: &mut Window,
 5952        cx: &mut Context<Self>,
 5953    ) -> Option<Task<Result<()>>> {
 5954        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5955        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5956    }
 5957
 5958    pub fn confirm_completion_insert(
 5959        &mut self,
 5960        _: &ConfirmCompletionInsert,
 5961        window: &mut Window,
 5962        cx: &mut Context<Self>,
 5963    ) -> Option<Task<Result<()>>> {
 5964        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5965        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5966    }
 5967
 5968    pub fn confirm_completion_replace(
 5969        &mut self,
 5970        _: &ConfirmCompletionReplace,
 5971        window: &mut Window,
 5972        cx: &mut Context<Self>,
 5973    ) -> Option<Task<Result<()>>> {
 5974        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5975        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5976    }
 5977
 5978    pub fn compose_completion(
 5979        &mut self,
 5980        action: &ComposeCompletion,
 5981        window: &mut Window,
 5982        cx: &mut Context<Self>,
 5983    ) -> Option<Task<Result<()>>> {
 5984        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5985        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5986    }
 5987
 5988    fn do_completion(
 5989        &mut self,
 5990        item_ix: Option<usize>,
 5991        intent: CompletionIntent,
 5992        window: &mut Window,
 5993        cx: &mut Context<Editor>,
 5994    ) -> Option<Task<Result<()>>> {
 5995        use language::ToOffset as _;
 5996
 5997        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5998        else {
 5999            return None;
 6000        };
 6001
 6002        let candidate_id = {
 6003            let entries = completions_menu.entries.borrow();
 6004            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6005            if self.show_edit_predictions_in_menu() {
 6006                self.discard_edit_prediction(true, cx);
 6007            }
 6008            mat.candidate_id
 6009        };
 6010
 6011        let completion = completions_menu
 6012            .completions
 6013            .borrow()
 6014            .get(candidate_id)?
 6015            .clone();
 6016        cx.stop_propagation();
 6017
 6018        let buffer_handle = completions_menu.buffer.clone();
 6019
 6020        let CompletionEdit {
 6021            new_text,
 6022            snippet,
 6023            replace_range,
 6024        } = process_completion_for_edit(
 6025            &completion,
 6026            intent,
 6027            &buffer_handle,
 6028            &completions_menu.initial_position.text_anchor,
 6029            cx,
 6030        );
 6031
 6032        let buffer = buffer_handle.read(cx);
 6033        let snapshot = self.buffer.read(cx).snapshot(cx);
 6034        let newest_anchor = self.selections.newest_anchor();
 6035        let replace_range_multibuffer = {
 6036            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6037            excerpt.map_range_from_buffer(replace_range.clone())
 6038        };
 6039        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6040            return None;
 6041        }
 6042
 6043        let old_text = buffer
 6044            .text_for_range(replace_range.clone())
 6045            .collect::<String>();
 6046        let lookbehind = newest_anchor
 6047            .start
 6048            .text_anchor
 6049            .to_offset(buffer)
 6050            .saturating_sub(replace_range.start);
 6051        let lookahead = replace_range
 6052            .end
 6053            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6054        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6055        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6056
 6057        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 6058        let mut ranges = Vec::new();
 6059        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6060
 6061        for selection in &selections {
 6062            let range = if selection.id == newest_anchor.id {
 6063                replace_range_multibuffer.clone()
 6064            } else {
 6065                let mut range = selection.range();
 6066
 6067                // if prefix is present, don't duplicate it
 6068                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6069                    range.start = range.start.saturating_sub(lookbehind);
 6070
 6071                    // if suffix is also present, mimic the newest cursor and replace it
 6072                    if selection.id != newest_anchor.id
 6073                        && snapshot.contains_str_at(range.end, suffix)
 6074                    {
 6075                        range.end += lookahead;
 6076                    }
 6077                }
 6078                range
 6079            };
 6080
 6081            ranges.push(range.clone());
 6082
 6083            if !self.linked_edit_ranges.is_empty() {
 6084                let start_anchor = snapshot.anchor_before(range.start);
 6085                let end_anchor = snapshot.anchor_after(range.end);
 6086                if let Some(ranges) = self
 6087                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6088                {
 6089                    for (buffer, edits) in ranges {
 6090                        linked_edits
 6091                            .entry(buffer.clone())
 6092                            .or_default()
 6093                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6094                    }
 6095                }
 6096            }
 6097        }
 6098
 6099        let common_prefix_len = old_text
 6100            .chars()
 6101            .zip(new_text.chars())
 6102            .take_while(|(a, b)| a == b)
 6103            .map(|(a, _)| a.len_utf8())
 6104            .sum::<usize>();
 6105
 6106        cx.emit(EditorEvent::InputHandled {
 6107            utf16_range_to_replace: None,
 6108            text: new_text[common_prefix_len..].into(),
 6109        });
 6110
 6111        self.transact(window, cx, |editor, window, cx| {
 6112            if let Some(mut snippet) = snippet {
 6113                snippet.text = new_text.to_string();
 6114                editor
 6115                    .insert_snippet(&ranges, snippet, window, cx)
 6116                    .log_err();
 6117            } else {
 6118                editor.buffer.update(cx, |multi_buffer, cx| {
 6119                    let auto_indent = match completion.insert_text_mode {
 6120                        Some(InsertTextMode::AS_IS) => None,
 6121                        _ => editor.autoindent_mode.clone(),
 6122                    };
 6123                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6124                    multi_buffer.edit(edits, auto_indent, cx);
 6125                });
 6126            }
 6127            for (buffer, edits) in linked_edits {
 6128                buffer.update(cx, |buffer, cx| {
 6129                    let snapshot = buffer.snapshot();
 6130                    let edits = edits
 6131                        .into_iter()
 6132                        .map(|(range, text)| {
 6133                            use text::ToPoint as TP;
 6134                            let end_point = TP::to_point(&range.end, &snapshot);
 6135                            let start_point = TP::to_point(&range.start, &snapshot);
 6136                            (start_point..end_point, text)
 6137                        })
 6138                        .sorted_by_key(|(range, _)| range.start);
 6139                    buffer.edit(edits, None, cx);
 6140                })
 6141            }
 6142
 6143            editor.refresh_edit_prediction(true, false, window, cx);
 6144        });
 6145        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6146
 6147        let show_new_completions_on_confirm = completion
 6148            .confirm
 6149            .as_ref()
 6150            .is_some_and(|confirm| confirm(intent, window, cx));
 6151        if show_new_completions_on_confirm {
 6152            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6153        }
 6154
 6155        let provider = self.completion_provider.as_ref()?;
 6156        drop(completion);
 6157        let apply_edits = provider.apply_additional_edits_for_completion(
 6158            buffer_handle,
 6159            completions_menu.completions.clone(),
 6160            candidate_id,
 6161            true,
 6162            cx,
 6163        );
 6164
 6165        let editor_settings = EditorSettings::get_global(cx);
 6166        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6167            // After the code completion is finished, users often want to know what signatures are needed.
 6168            // so we should automatically call signature_help
 6169            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6170        }
 6171
 6172        Some(cx.foreground_executor().spawn(async move {
 6173            apply_edits.await?;
 6174            Ok(())
 6175        }))
 6176    }
 6177
 6178    pub fn toggle_code_actions(
 6179        &mut self,
 6180        action: &ToggleCodeActions,
 6181        window: &mut Window,
 6182        cx: &mut Context<Self>,
 6183    ) {
 6184        let quick_launch = action.quick_launch;
 6185        let mut context_menu = self.context_menu.borrow_mut();
 6186        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6187            if code_actions.deployed_from == action.deployed_from {
 6188                // Toggle if we're selecting the same one
 6189                *context_menu = None;
 6190                cx.notify();
 6191                return;
 6192            } else {
 6193                // Otherwise, clear it and start a new one
 6194                *context_menu = None;
 6195                cx.notify();
 6196            }
 6197        }
 6198        drop(context_menu);
 6199        let snapshot = self.snapshot(window, cx);
 6200        let deployed_from = action.deployed_from.clone();
 6201        let action = action.clone();
 6202        self.completion_tasks.clear();
 6203        self.discard_edit_prediction(false, cx);
 6204
 6205        let multibuffer_point = match &action.deployed_from {
 6206            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6207                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6208            }
 6209            _ => self
 6210                .selections
 6211                .newest::<Point>(&snapshot.display_snapshot)
 6212                .head(),
 6213        };
 6214        let Some((buffer, buffer_row)) = snapshot
 6215            .buffer_snapshot()
 6216            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6217            .and_then(|(buffer_snapshot, range)| {
 6218                self.buffer()
 6219                    .read(cx)
 6220                    .buffer(buffer_snapshot.remote_id())
 6221                    .map(|buffer| (buffer, range.start.row))
 6222            })
 6223        else {
 6224            return;
 6225        };
 6226        let buffer_id = buffer.read(cx).remote_id();
 6227        let tasks = self
 6228            .tasks
 6229            .get(&(buffer_id, buffer_row))
 6230            .map(|t| Arc::new(t.to_owned()));
 6231
 6232        if !self.focus_handle.is_focused(window) {
 6233            return;
 6234        }
 6235        let project = self.project.clone();
 6236
 6237        let code_actions_task = match deployed_from {
 6238            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6239            _ => self.code_actions(buffer_row, window, cx),
 6240        };
 6241
 6242        let runnable_task = match deployed_from {
 6243            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6244            _ => {
 6245                let mut task_context_task = Task::ready(None);
 6246                if let Some(tasks) = &tasks
 6247                    && let Some(project) = project
 6248                {
 6249                    task_context_task =
 6250                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6251                }
 6252
 6253                cx.spawn_in(window, {
 6254                    let buffer = buffer.clone();
 6255                    async move |editor, cx| {
 6256                        let task_context = task_context_task.await;
 6257
 6258                        let resolved_tasks =
 6259                            tasks
 6260                                .zip(task_context.clone())
 6261                                .map(|(tasks, task_context)| ResolvedTasks {
 6262                                    templates: tasks.resolve(&task_context).collect(),
 6263                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6264                                        multibuffer_point.row,
 6265                                        tasks.column,
 6266                                    )),
 6267                                });
 6268                        let debug_scenarios = editor
 6269                            .update(cx, |editor, cx| {
 6270                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6271                            })?
 6272                            .await;
 6273                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6274                    }
 6275                })
 6276            }
 6277        };
 6278
 6279        cx.spawn_in(window, async move |editor, cx| {
 6280            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6281            let code_actions = code_actions_task.await;
 6282            let spawn_straight_away = quick_launch
 6283                && resolved_tasks
 6284                    .as_ref()
 6285                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6286                && code_actions
 6287                    .as_ref()
 6288                    .is_none_or(|actions| actions.is_empty())
 6289                && debug_scenarios.is_empty();
 6290
 6291            editor.update_in(cx, |editor, window, cx| {
 6292                crate::hover_popover::hide_hover(editor, cx);
 6293                let actions = CodeActionContents::new(
 6294                    resolved_tasks,
 6295                    code_actions,
 6296                    debug_scenarios,
 6297                    task_context.unwrap_or_default(),
 6298                );
 6299
 6300                // Don't show the menu if there are no actions available
 6301                if actions.is_empty() {
 6302                    cx.notify();
 6303                    return Task::ready(Ok(()));
 6304                }
 6305
 6306                *editor.context_menu.borrow_mut() =
 6307                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6308                        buffer,
 6309                        actions,
 6310                        selected_item: Default::default(),
 6311                        scroll_handle: UniformListScrollHandle::default(),
 6312                        deployed_from,
 6313                    }));
 6314                cx.notify();
 6315                if spawn_straight_away
 6316                    && let Some(task) = editor.confirm_code_action(
 6317                        &ConfirmCodeAction { item_ix: Some(0) },
 6318                        window,
 6319                        cx,
 6320                    )
 6321                {
 6322                    return task;
 6323                }
 6324
 6325                Task::ready(Ok(()))
 6326            })
 6327        })
 6328        .detach_and_log_err(cx);
 6329    }
 6330
 6331    fn debug_scenarios(
 6332        &mut self,
 6333        resolved_tasks: &Option<ResolvedTasks>,
 6334        buffer: &Entity<Buffer>,
 6335        cx: &mut App,
 6336    ) -> Task<Vec<task::DebugScenario>> {
 6337        maybe!({
 6338            let project = self.project()?;
 6339            let dap_store = project.read(cx).dap_store();
 6340            let mut scenarios = vec![];
 6341            let resolved_tasks = resolved_tasks.as_ref()?;
 6342            let buffer = buffer.read(cx);
 6343            let language = buffer.language()?;
 6344            let file = buffer.file();
 6345            let debug_adapter = language_settings(language.name().into(), file, cx)
 6346                .debuggers
 6347                .first()
 6348                .map(SharedString::from)
 6349                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6350
 6351            dap_store.update(cx, |dap_store, cx| {
 6352                for (_, task) in &resolved_tasks.templates {
 6353                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6354                        task.original_task().clone(),
 6355                        debug_adapter.clone().into(),
 6356                        task.display_label().to_owned().into(),
 6357                        cx,
 6358                    );
 6359                    scenarios.push(maybe_scenario);
 6360                }
 6361            });
 6362            Some(cx.background_spawn(async move {
 6363                futures::future::join_all(scenarios)
 6364                    .await
 6365                    .into_iter()
 6366                    .flatten()
 6367                    .collect::<Vec<_>>()
 6368            }))
 6369        })
 6370        .unwrap_or_else(|| Task::ready(vec![]))
 6371    }
 6372
 6373    fn code_actions(
 6374        &mut self,
 6375        buffer_row: u32,
 6376        window: &mut Window,
 6377        cx: &mut Context<Self>,
 6378    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6379        let mut task = self.code_actions_task.take();
 6380        cx.spawn_in(window, async move |editor, cx| {
 6381            while let Some(prev_task) = task {
 6382                prev_task.await.log_err();
 6383                task = editor
 6384                    .update(cx, |this, _| this.code_actions_task.take())
 6385                    .ok()?;
 6386            }
 6387
 6388            editor
 6389                .update(cx, |editor, cx| {
 6390                    editor
 6391                        .available_code_actions
 6392                        .clone()
 6393                        .and_then(|(location, code_actions)| {
 6394                            let snapshot = location.buffer.read(cx).snapshot();
 6395                            let point_range = location.range.to_point(&snapshot);
 6396                            let point_range = point_range.start.row..=point_range.end.row;
 6397                            if point_range.contains(&buffer_row) {
 6398                                Some(code_actions)
 6399                            } else {
 6400                                None
 6401                            }
 6402                        })
 6403                })
 6404                .ok()
 6405                .flatten()
 6406        })
 6407    }
 6408
 6409    pub fn confirm_code_action(
 6410        &mut self,
 6411        action: &ConfirmCodeAction,
 6412        window: &mut Window,
 6413        cx: &mut Context<Self>,
 6414    ) -> Option<Task<Result<()>>> {
 6415        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6416
 6417        let actions_menu =
 6418            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6419                menu
 6420            } else {
 6421                return None;
 6422            };
 6423
 6424        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6425        let action = actions_menu.actions.get(action_ix)?;
 6426        let title = action.label();
 6427        let buffer = actions_menu.buffer;
 6428        let workspace = self.workspace()?;
 6429
 6430        match action {
 6431            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6432                workspace.update(cx, |workspace, cx| {
 6433                    workspace.schedule_resolved_task(
 6434                        task_source_kind,
 6435                        resolved_task,
 6436                        false,
 6437                        window,
 6438                        cx,
 6439                    );
 6440
 6441                    Some(Task::ready(Ok(())))
 6442                })
 6443            }
 6444            CodeActionsItem::CodeAction {
 6445                excerpt_id,
 6446                action,
 6447                provider,
 6448            } => {
 6449                let apply_code_action =
 6450                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6451                let workspace = workspace.downgrade();
 6452                Some(cx.spawn_in(window, async move |editor, cx| {
 6453                    let project_transaction = apply_code_action.await?;
 6454                    Self::open_project_transaction(
 6455                        &editor,
 6456                        workspace,
 6457                        project_transaction,
 6458                        title,
 6459                        cx,
 6460                    )
 6461                    .await
 6462                }))
 6463            }
 6464            CodeActionsItem::DebugScenario(scenario) => {
 6465                let context = actions_menu.actions.context;
 6466
 6467                workspace.update(cx, |workspace, cx| {
 6468                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6469                    workspace.start_debug_session(
 6470                        scenario,
 6471                        context,
 6472                        Some(buffer),
 6473                        None,
 6474                        window,
 6475                        cx,
 6476                    );
 6477                });
 6478                Some(Task::ready(Ok(())))
 6479            }
 6480        }
 6481    }
 6482
 6483    pub async fn open_project_transaction(
 6484        editor: &WeakEntity<Editor>,
 6485        workspace: WeakEntity<Workspace>,
 6486        transaction: ProjectTransaction,
 6487        title: String,
 6488        cx: &mut AsyncWindowContext,
 6489    ) -> Result<()> {
 6490        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6491        cx.update(|_, cx| {
 6492            entries.sort_unstable_by_key(|(buffer, _)| {
 6493                buffer.read(cx).file().map(|f| f.path().clone())
 6494            });
 6495        })?;
 6496        if entries.is_empty() {
 6497            return Ok(());
 6498        }
 6499
 6500        // If the project transaction's edits are all contained within this editor, then
 6501        // avoid opening a new editor to display them.
 6502
 6503        if let [(buffer, transaction)] = &*entries {
 6504            let excerpt = editor.update(cx, |editor, cx| {
 6505                editor
 6506                    .buffer()
 6507                    .read(cx)
 6508                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6509            })?;
 6510            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6511                && excerpted_buffer == *buffer
 6512            {
 6513                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6514                    let excerpt_range = excerpt_range.to_offset(buffer);
 6515                    buffer
 6516                        .edited_ranges_for_transaction::<usize>(transaction)
 6517                        .all(|range| {
 6518                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6519                        })
 6520                })?;
 6521
 6522                if all_edits_within_excerpt {
 6523                    return Ok(());
 6524                }
 6525            }
 6526        }
 6527
 6528        let mut ranges_to_highlight = Vec::new();
 6529        let excerpt_buffer = cx.new(|cx| {
 6530            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6531            for (buffer_handle, transaction) in &entries {
 6532                let edited_ranges = buffer_handle
 6533                    .read(cx)
 6534                    .edited_ranges_for_transaction::<Point>(transaction)
 6535                    .collect::<Vec<_>>();
 6536                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6537                    PathKey::for_buffer(buffer_handle, cx),
 6538                    buffer_handle.clone(),
 6539                    edited_ranges,
 6540                    multibuffer_context_lines(cx),
 6541                    cx,
 6542                );
 6543
 6544                ranges_to_highlight.extend(ranges);
 6545            }
 6546            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6547            multibuffer
 6548        })?;
 6549
 6550        workspace.update_in(cx, |workspace, window, cx| {
 6551            let project = workspace.project().clone();
 6552            let editor =
 6553                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6554            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6555            editor.update(cx, |editor, cx| {
 6556                editor.highlight_background::<Self>(
 6557                    &ranges_to_highlight,
 6558                    |theme| theme.colors().editor_highlighted_line_background,
 6559                    cx,
 6560                );
 6561            });
 6562        })?;
 6563
 6564        Ok(())
 6565    }
 6566
 6567    pub fn clear_code_action_providers(&mut self) {
 6568        self.code_action_providers.clear();
 6569        self.available_code_actions.take();
 6570    }
 6571
 6572    pub fn add_code_action_provider(
 6573        &mut self,
 6574        provider: Rc<dyn CodeActionProvider>,
 6575        window: &mut Window,
 6576        cx: &mut Context<Self>,
 6577    ) {
 6578        if self
 6579            .code_action_providers
 6580            .iter()
 6581            .any(|existing_provider| existing_provider.id() == provider.id())
 6582        {
 6583            return;
 6584        }
 6585
 6586        self.code_action_providers.push(provider);
 6587        self.refresh_code_actions(window, cx);
 6588    }
 6589
 6590    pub fn remove_code_action_provider(
 6591        &mut self,
 6592        id: Arc<str>,
 6593        window: &mut Window,
 6594        cx: &mut Context<Self>,
 6595    ) {
 6596        self.code_action_providers
 6597            .retain(|provider| provider.id() != id);
 6598        self.refresh_code_actions(window, cx);
 6599    }
 6600
 6601    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6602        !self.code_action_providers.is_empty()
 6603            && EditorSettings::get_global(cx).toolbar.code_actions
 6604    }
 6605
 6606    pub fn has_available_code_actions(&self) -> bool {
 6607        self.available_code_actions
 6608            .as_ref()
 6609            .is_some_and(|(_, actions)| !actions.is_empty())
 6610    }
 6611
 6612    fn render_inline_code_actions(
 6613        &self,
 6614        icon_size: ui::IconSize,
 6615        display_row: DisplayRow,
 6616        is_active: bool,
 6617        cx: &mut Context<Self>,
 6618    ) -> AnyElement {
 6619        let show_tooltip = !self.context_menu_visible();
 6620        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6621            .icon_size(icon_size)
 6622            .shape(ui::IconButtonShape::Square)
 6623            .icon_color(ui::Color::Hidden)
 6624            .toggle_state(is_active)
 6625            .when(show_tooltip, |this| {
 6626                this.tooltip({
 6627                    let focus_handle = self.focus_handle.clone();
 6628                    move |window, cx| {
 6629                        Tooltip::for_action_in(
 6630                            "Toggle Code Actions",
 6631                            &ToggleCodeActions {
 6632                                deployed_from: None,
 6633                                quick_launch: false,
 6634                            },
 6635                            &focus_handle,
 6636                            window,
 6637                            cx,
 6638                        )
 6639                    }
 6640                })
 6641            })
 6642            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6643                window.focus(&editor.focus_handle(cx));
 6644                editor.toggle_code_actions(
 6645                    &crate::actions::ToggleCodeActions {
 6646                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6647                            display_row,
 6648                        )),
 6649                        quick_launch: false,
 6650                    },
 6651                    window,
 6652                    cx,
 6653                );
 6654            }))
 6655            .into_any_element()
 6656    }
 6657
 6658    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6659        &self.context_menu
 6660    }
 6661
 6662    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6663        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6664            cx.background_executor()
 6665                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6666                .await;
 6667
 6668            let (start_buffer, start, _, end, newest_selection) = this
 6669                .update(cx, |this, cx| {
 6670                    let newest_selection = this.selections.newest_anchor().clone();
 6671                    if newest_selection.head().diff_base_anchor.is_some() {
 6672                        return None;
 6673                    }
 6674                    let display_snapshot = this.display_snapshot(cx);
 6675                    let newest_selection_adjusted =
 6676                        this.selections.newest_adjusted(&display_snapshot);
 6677                    let buffer = this.buffer.read(cx);
 6678
 6679                    let (start_buffer, start) =
 6680                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6681                    let (end_buffer, end) =
 6682                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6683
 6684                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6685                })?
 6686                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6687                .context(
 6688                    "Expected selection to lie in a single buffer when refreshing code actions",
 6689                )?;
 6690            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6691                let providers = this.code_action_providers.clone();
 6692                let tasks = this
 6693                    .code_action_providers
 6694                    .iter()
 6695                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6696                    .collect::<Vec<_>>();
 6697                (providers, tasks)
 6698            })?;
 6699
 6700            let mut actions = Vec::new();
 6701            for (provider, provider_actions) in
 6702                providers.into_iter().zip(future::join_all(tasks).await)
 6703            {
 6704                if let Some(provider_actions) = provider_actions.log_err() {
 6705                    actions.extend(provider_actions.into_iter().map(|action| {
 6706                        AvailableCodeAction {
 6707                            excerpt_id: newest_selection.start.excerpt_id,
 6708                            action,
 6709                            provider: provider.clone(),
 6710                        }
 6711                    }));
 6712                }
 6713            }
 6714
 6715            this.update(cx, |this, cx| {
 6716                this.available_code_actions = if actions.is_empty() {
 6717                    None
 6718                } else {
 6719                    Some((
 6720                        Location {
 6721                            buffer: start_buffer,
 6722                            range: start..end,
 6723                        },
 6724                        actions.into(),
 6725                    ))
 6726                };
 6727                cx.notify();
 6728            })
 6729        }));
 6730    }
 6731
 6732    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6733        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6734            self.show_git_blame_inline = false;
 6735
 6736            self.show_git_blame_inline_delay_task =
 6737                Some(cx.spawn_in(window, async move |this, cx| {
 6738                    cx.background_executor().timer(delay).await;
 6739
 6740                    this.update(cx, |this, cx| {
 6741                        this.show_git_blame_inline = true;
 6742                        cx.notify();
 6743                    })
 6744                    .log_err();
 6745                }));
 6746        }
 6747    }
 6748
 6749    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6750        let snapshot = self.snapshot(window, cx);
 6751        let cursor = self
 6752            .selections
 6753            .newest::<Point>(&snapshot.display_snapshot)
 6754            .head();
 6755        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6756        else {
 6757            return;
 6758        };
 6759
 6760        let Some(blame) = self.blame.as_ref() else {
 6761            return;
 6762        };
 6763
 6764        let row_info = RowInfo {
 6765            buffer_id: Some(buffer.remote_id()),
 6766            buffer_row: Some(point.row),
 6767            ..Default::default()
 6768        };
 6769        let Some((buffer, blame_entry)) = blame
 6770            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6771            .flatten()
 6772        else {
 6773            return;
 6774        };
 6775
 6776        let anchor = self.selections.newest_anchor().head();
 6777        let position = self.to_pixel_point(anchor, &snapshot, window);
 6778        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6779            self.show_blame_popover(
 6780                buffer,
 6781                &blame_entry,
 6782                position + last_bounds.origin,
 6783                true,
 6784                cx,
 6785            );
 6786        };
 6787    }
 6788
 6789    fn show_blame_popover(
 6790        &mut self,
 6791        buffer: BufferId,
 6792        blame_entry: &BlameEntry,
 6793        position: gpui::Point<Pixels>,
 6794        ignore_timeout: bool,
 6795        cx: &mut Context<Self>,
 6796    ) {
 6797        if let Some(state) = &mut self.inline_blame_popover {
 6798            state.hide_task.take();
 6799        } else {
 6800            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6801            let blame_entry = blame_entry.clone();
 6802            let show_task = cx.spawn(async move |editor, cx| {
 6803                if !ignore_timeout {
 6804                    cx.background_executor()
 6805                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6806                        .await;
 6807                }
 6808                editor
 6809                    .update(cx, |editor, cx| {
 6810                        editor.inline_blame_popover_show_task.take();
 6811                        let Some(blame) = editor.blame.as_ref() else {
 6812                            return;
 6813                        };
 6814                        let blame = blame.read(cx);
 6815                        let details = blame.details_for_entry(buffer, &blame_entry);
 6816                        let markdown = cx.new(|cx| {
 6817                            Markdown::new(
 6818                                details
 6819                                    .as_ref()
 6820                                    .map(|message| message.message.clone())
 6821                                    .unwrap_or_default(),
 6822                                None,
 6823                                None,
 6824                                cx,
 6825                            )
 6826                        });
 6827                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6828                            position,
 6829                            hide_task: None,
 6830                            popover_bounds: None,
 6831                            popover_state: InlineBlamePopoverState {
 6832                                scroll_handle: ScrollHandle::new(),
 6833                                commit_message: details,
 6834                                markdown,
 6835                            },
 6836                            keyboard_grace: ignore_timeout,
 6837                        });
 6838                        cx.notify();
 6839                    })
 6840                    .ok();
 6841            });
 6842            self.inline_blame_popover_show_task = Some(show_task);
 6843        }
 6844    }
 6845
 6846    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6847        self.inline_blame_popover_show_task.take();
 6848        if let Some(state) = &mut self.inline_blame_popover {
 6849            let hide_task = cx.spawn(async move |editor, cx| {
 6850                if !ignore_timeout {
 6851                    cx.background_executor()
 6852                        .timer(std::time::Duration::from_millis(100))
 6853                        .await;
 6854                }
 6855                editor
 6856                    .update(cx, |editor, cx| {
 6857                        editor.inline_blame_popover.take();
 6858                        cx.notify();
 6859                    })
 6860                    .ok();
 6861            });
 6862            state.hide_task = Some(hide_task);
 6863            true
 6864        } else {
 6865            false
 6866        }
 6867    }
 6868
 6869    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6870        if self.pending_rename.is_some() {
 6871            return None;
 6872        }
 6873
 6874        let provider = self.semantics_provider.clone()?;
 6875        let buffer = self.buffer.read(cx);
 6876        let newest_selection = self.selections.newest_anchor().clone();
 6877        let cursor_position = newest_selection.head();
 6878        let (cursor_buffer, cursor_buffer_position) =
 6879            buffer.text_anchor_for_position(cursor_position, cx)?;
 6880        let (tail_buffer, tail_buffer_position) =
 6881            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6882        if cursor_buffer != tail_buffer {
 6883            return None;
 6884        }
 6885
 6886        let snapshot = cursor_buffer.read(cx).snapshot();
 6887        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6888        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6889        if start_word_range != end_word_range {
 6890            self.document_highlights_task.take();
 6891            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6892            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6893            return None;
 6894        }
 6895
 6896        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6897        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6898            cx.background_executor()
 6899                .timer(Duration::from_millis(debounce))
 6900                .await;
 6901
 6902            let highlights = if let Some(highlights) = cx
 6903                .update(|cx| {
 6904                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6905                })
 6906                .ok()
 6907                .flatten()
 6908            {
 6909                highlights.await.log_err()
 6910            } else {
 6911                None
 6912            };
 6913
 6914            if let Some(highlights) = highlights {
 6915                this.update(cx, |this, cx| {
 6916                    if this.pending_rename.is_some() {
 6917                        return;
 6918                    }
 6919
 6920                    let buffer = this.buffer.read(cx);
 6921                    if buffer
 6922                        .text_anchor_for_position(cursor_position, cx)
 6923                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6924                    {
 6925                        return;
 6926                    }
 6927
 6928                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6929                    let mut write_ranges = Vec::new();
 6930                    let mut read_ranges = Vec::new();
 6931                    for highlight in highlights {
 6932                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6933                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6934                        {
 6935                            let start = highlight
 6936                                .range
 6937                                .start
 6938                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6939                            let end = highlight
 6940                                .range
 6941                                .end
 6942                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6943                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6944                                continue;
 6945                            }
 6946
 6947                            let range =
 6948                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6949                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6950                                write_ranges.push(range);
 6951                            } else {
 6952                                read_ranges.push(range);
 6953                            }
 6954                        }
 6955                    }
 6956
 6957                    this.highlight_background::<DocumentHighlightRead>(
 6958                        &read_ranges,
 6959                        |theme| theme.colors().editor_document_highlight_read_background,
 6960                        cx,
 6961                    );
 6962                    this.highlight_background::<DocumentHighlightWrite>(
 6963                        &write_ranges,
 6964                        |theme| theme.colors().editor_document_highlight_write_background,
 6965                        cx,
 6966                    );
 6967                    cx.notify();
 6968                })
 6969                .log_err();
 6970            }
 6971        }));
 6972        None
 6973    }
 6974
 6975    fn prepare_highlight_query_from_selection(
 6976        &mut self,
 6977        cx: &mut Context<Editor>,
 6978    ) -> Option<(String, Range<Anchor>)> {
 6979        if matches!(self.mode, EditorMode::SingleLine) {
 6980            return None;
 6981        }
 6982        if !EditorSettings::get_global(cx).selection_highlight {
 6983            return None;
 6984        }
 6985        if self.selections.count() != 1 || self.selections.line_mode() {
 6986            return None;
 6987        }
 6988        let selection = self.selections.newest_anchor();
 6989        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6990        let selection_point_range = selection.start.to_point(&multi_buffer_snapshot)
 6991            ..selection.end.to_point(&multi_buffer_snapshot);
 6992        // If the selection spans multiple rows OR it is empty
 6993        if selection_point_range.start.row != selection_point_range.end.row
 6994            || selection_point_range.start.column == selection_point_range.end.column
 6995        {
 6996            return None;
 6997        }
 6998
 6999        let query = multi_buffer_snapshot
 7000            .text_for_range(selection.range())
 7001            .collect::<String>();
 7002        if query.trim().is_empty() {
 7003            return None;
 7004        }
 7005        Some((query, selection.range()))
 7006    }
 7007
 7008    fn update_selection_occurrence_highlights(
 7009        &mut self,
 7010        query_text: String,
 7011        query_range: Range<Anchor>,
 7012        multi_buffer_range_to_query: Range<Point>,
 7013        use_debounce: bool,
 7014        window: &mut Window,
 7015        cx: &mut Context<Editor>,
 7016    ) -> Task<()> {
 7017        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7018        cx.spawn_in(window, async move |editor, cx| {
 7019            if use_debounce {
 7020                cx.background_executor()
 7021                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7022                    .await;
 7023            }
 7024            let match_task = cx.background_spawn(async move {
 7025                let buffer_ranges = multi_buffer_snapshot
 7026                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7027                    .into_iter()
 7028                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7029                let mut match_ranges = Vec::new();
 7030                let Ok(regex) = project::search::SearchQuery::text(
 7031                    query_text.clone(),
 7032                    false,
 7033                    false,
 7034                    false,
 7035                    Default::default(),
 7036                    Default::default(),
 7037                    false,
 7038                    None,
 7039                ) else {
 7040                    return Vec::default();
 7041                };
 7042                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7043                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7044                    match_ranges.extend(
 7045                        regex
 7046                            .search(buffer_snapshot, Some(search_range.clone()))
 7047                            .await
 7048                            .into_iter()
 7049                            .filter_map(|match_range| {
 7050                                let match_start = buffer_snapshot
 7051                                    .anchor_after(search_range.start + match_range.start);
 7052                                let match_end = buffer_snapshot
 7053                                    .anchor_before(search_range.start + match_range.end);
 7054                                let match_anchor_range = Anchor::range_in_buffer(
 7055                                    excerpt_id,
 7056                                    buffer_snapshot.remote_id(),
 7057                                    match_start..match_end,
 7058                                );
 7059                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7060                            }),
 7061                    );
 7062                }
 7063                match_ranges
 7064            });
 7065            let match_ranges = match_task.await;
 7066            editor
 7067                .update_in(cx, |editor, _, cx| {
 7068                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7069                    if !match_ranges.is_empty() {
 7070                        editor.highlight_background::<SelectedTextHighlight>(
 7071                            &match_ranges,
 7072                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7073                            cx,
 7074                        )
 7075                    }
 7076                })
 7077                .log_err();
 7078        })
 7079    }
 7080
 7081    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7082        struct NewlineFold;
 7083        let type_id = std::any::TypeId::of::<NewlineFold>();
 7084        if !self.mode.is_single_line() {
 7085            return;
 7086        }
 7087        let snapshot = self.snapshot(window, cx);
 7088        if snapshot.buffer_snapshot().max_point().row == 0 {
 7089            return;
 7090        }
 7091        let task = cx.background_spawn(async move {
 7092            let new_newlines = snapshot
 7093                .buffer_chars_at(0)
 7094                .filter_map(|(c, i)| {
 7095                    if c == '\n' {
 7096                        Some(
 7097                            snapshot.buffer_snapshot().anchor_after(i)
 7098                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7099                        )
 7100                    } else {
 7101                        None
 7102                    }
 7103                })
 7104                .collect::<Vec<_>>();
 7105            let existing_newlines = snapshot
 7106                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7107                .filter_map(|fold| {
 7108                    if fold.placeholder.type_tag == Some(type_id) {
 7109                        Some(fold.range.start..fold.range.end)
 7110                    } else {
 7111                        None
 7112                    }
 7113                })
 7114                .collect::<Vec<_>>();
 7115
 7116            (new_newlines, existing_newlines)
 7117        });
 7118        self.folding_newlines = cx.spawn(async move |this, cx| {
 7119            let (new_newlines, existing_newlines) = task.await;
 7120            if new_newlines == existing_newlines {
 7121                return;
 7122            }
 7123            let placeholder = FoldPlaceholder {
 7124                render: Arc::new(move |_, _, cx| {
 7125                    div()
 7126                        .bg(cx.theme().status().hint_background)
 7127                        .border_b_1()
 7128                        .size_full()
 7129                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7130                        .border_color(cx.theme().status().hint)
 7131                        .child("\\n")
 7132                        .into_any()
 7133                }),
 7134                constrain_width: false,
 7135                merge_adjacent: false,
 7136                type_tag: Some(type_id),
 7137            };
 7138            let creases = new_newlines
 7139                .into_iter()
 7140                .map(|range| Crease::simple(range, placeholder.clone()))
 7141                .collect();
 7142            this.update(cx, |this, cx| {
 7143                this.display_map.update(cx, |display_map, cx| {
 7144                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7145                    display_map.fold(creases, cx);
 7146                });
 7147            })
 7148            .ok();
 7149        });
 7150    }
 7151
 7152    fn refresh_selected_text_highlights(
 7153        &mut self,
 7154        on_buffer_edit: bool,
 7155        window: &mut Window,
 7156        cx: &mut Context<Editor>,
 7157    ) {
 7158        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7159        else {
 7160            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7161            self.quick_selection_highlight_task.take();
 7162            self.debounced_selection_highlight_task.take();
 7163            return;
 7164        };
 7165        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7166        if on_buffer_edit
 7167            || self
 7168                .quick_selection_highlight_task
 7169                .as_ref()
 7170                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7171        {
 7172            let multi_buffer_visible_start = self
 7173                .scroll_manager
 7174                .anchor()
 7175                .anchor
 7176                .to_point(&multi_buffer_snapshot);
 7177            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7178                multi_buffer_visible_start
 7179                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7180                Bias::Left,
 7181            );
 7182            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7183            self.quick_selection_highlight_task = Some((
 7184                query_range.clone(),
 7185                self.update_selection_occurrence_highlights(
 7186                    query_text.clone(),
 7187                    query_range.clone(),
 7188                    multi_buffer_visible_range,
 7189                    false,
 7190                    window,
 7191                    cx,
 7192                ),
 7193            ));
 7194        }
 7195        if on_buffer_edit
 7196            || self
 7197                .debounced_selection_highlight_task
 7198                .as_ref()
 7199                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7200        {
 7201            let multi_buffer_start = multi_buffer_snapshot
 7202                .anchor_before(0)
 7203                .to_point(&multi_buffer_snapshot);
 7204            let multi_buffer_end = multi_buffer_snapshot
 7205                .anchor_after(multi_buffer_snapshot.len())
 7206                .to_point(&multi_buffer_snapshot);
 7207            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7208            self.debounced_selection_highlight_task = Some((
 7209                query_range.clone(),
 7210                self.update_selection_occurrence_highlights(
 7211                    query_text,
 7212                    query_range,
 7213                    multi_buffer_full_range,
 7214                    true,
 7215                    window,
 7216                    cx,
 7217                ),
 7218            ));
 7219        }
 7220    }
 7221
 7222    pub fn refresh_edit_prediction(
 7223        &mut self,
 7224        debounce: bool,
 7225        user_requested: bool,
 7226        window: &mut Window,
 7227        cx: &mut Context<Self>,
 7228    ) -> Option<()> {
 7229        if DisableAiSettings::get_global(cx).disable_ai {
 7230            return None;
 7231        }
 7232
 7233        let provider = self.edit_prediction_provider()?;
 7234        let cursor = self.selections.newest_anchor().head();
 7235        let (buffer, cursor_buffer_position) =
 7236            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7237
 7238        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7239            self.discard_edit_prediction(false, cx);
 7240            return None;
 7241        }
 7242
 7243        self.update_visible_edit_prediction(window, cx);
 7244
 7245        if !user_requested
 7246            && (!self.should_show_edit_predictions()
 7247                || !self.is_focused(window)
 7248                || buffer.read(cx).is_empty())
 7249        {
 7250            self.discard_edit_prediction(false, cx);
 7251            return None;
 7252        }
 7253
 7254        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7255        Some(())
 7256    }
 7257
 7258    fn show_edit_predictions_in_menu(&self) -> bool {
 7259        match self.edit_prediction_settings {
 7260            EditPredictionSettings::Disabled => false,
 7261            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7262        }
 7263    }
 7264
 7265    pub fn edit_predictions_enabled(&self) -> bool {
 7266        match self.edit_prediction_settings {
 7267            EditPredictionSettings::Disabled => false,
 7268            EditPredictionSettings::Enabled { .. } => true,
 7269        }
 7270    }
 7271
 7272    fn edit_prediction_requires_modifier(&self) -> bool {
 7273        match self.edit_prediction_settings {
 7274            EditPredictionSettings::Disabled => false,
 7275            EditPredictionSettings::Enabled {
 7276                preview_requires_modifier,
 7277                ..
 7278            } => preview_requires_modifier,
 7279        }
 7280    }
 7281
 7282    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7283        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7284            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7285            self.discard_edit_prediction(false, cx);
 7286        } else {
 7287            let selection = self.selections.newest_anchor();
 7288            let cursor = selection.head();
 7289
 7290            if let Some((buffer, cursor_buffer_position)) =
 7291                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7292            {
 7293                self.edit_prediction_settings =
 7294                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7295            }
 7296        }
 7297    }
 7298
 7299    fn edit_prediction_settings_at_position(
 7300        &self,
 7301        buffer: &Entity<Buffer>,
 7302        buffer_position: language::Anchor,
 7303        cx: &App,
 7304    ) -> EditPredictionSettings {
 7305        if !self.mode.is_full()
 7306            || !self.show_edit_predictions_override.unwrap_or(true)
 7307            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7308        {
 7309            return EditPredictionSettings::Disabled;
 7310        }
 7311
 7312        let buffer = buffer.read(cx);
 7313
 7314        let file = buffer.file();
 7315
 7316        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7317            return EditPredictionSettings::Disabled;
 7318        };
 7319
 7320        let by_provider = matches!(
 7321            self.menu_edit_predictions_policy,
 7322            MenuEditPredictionsPolicy::ByProvider
 7323        );
 7324
 7325        let show_in_menu = by_provider
 7326            && self
 7327                .edit_prediction_provider
 7328                .as_ref()
 7329                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7330
 7331        let preview_requires_modifier =
 7332            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7333
 7334        EditPredictionSettings::Enabled {
 7335            show_in_menu,
 7336            preview_requires_modifier,
 7337        }
 7338    }
 7339
 7340    fn should_show_edit_predictions(&self) -> bool {
 7341        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7342    }
 7343
 7344    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7345        matches!(
 7346            self.edit_prediction_preview,
 7347            EditPredictionPreview::Active { .. }
 7348        )
 7349    }
 7350
 7351    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7352        let cursor = self.selections.newest_anchor().head();
 7353        if let Some((buffer, cursor_position)) =
 7354            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7355        {
 7356            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7357        } else {
 7358            false
 7359        }
 7360    }
 7361
 7362    pub fn supports_minimap(&self, cx: &App) -> bool {
 7363        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7364    }
 7365
 7366    fn edit_predictions_enabled_in_buffer(
 7367        &self,
 7368        buffer: &Entity<Buffer>,
 7369        buffer_position: language::Anchor,
 7370        cx: &App,
 7371    ) -> bool {
 7372        maybe!({
 7373            if self.read_only(cx) {
 7374                return Some(false);
 7375            }
 7376            let provider = self.edit_prediction_provider()?;
 7377            if !provider.is_enabled(buffer, buffer_position, cx) {
 7378                return Some(false);
 7379            }
 7380            let buffer = buffer.read(cx);
 7381            let Some(file) = buffer.file() else {
 7382                return Some(true);
 7383            };
 7384            let settings = all_language_settings(Some(file), cx);
 7385            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7386        })
 7387        .unwrap_or(false)
 7388    }
 7389
 7390    fn cycle_edit_prediction(
 7391        &mut self,
 7392        direction: Direction,
 7393        window: &mut Window,
 7394        cx: &mut Context<Self>,
 7395    ) -> Option<()> {
 7396        let provider = self.edit_prediction_provider()?;
 7397        let cursor = self.selections.newest_anchor().head();
 7398        let (buffer, cursor_buffer_position) =
 7399            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7400        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7401            return None;
 7402        }
 7403
 7404        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7405        self.update_visible_edit_prediction(window, cx);
 7406
 7407        Some(())
 7408    }
 7409
 7410    pub fn show_edit_prediction(
 7411        &mut self,
 7412        _: &ShowEditPrediction,
 7413        window: &mut Window,
 7414        cx: &mut Context<Self>,
 7415    ) {
 7416        if !self.has_active_edit_prediction() {
 7417            self.refresh_edit_prediction(false, true, window, cx);
 7418            return;
 7419        }
 7420
 7421        self.update_visible_edit_prediction(window, cx);
 7422    }
 7423
 7424    pub fn display_cursor_names(
 7425        &mut self,
 7426        _: &DisplayCursorNames,
 7427        window: &mut Window,
 7428        cx: &mut Context<Self>,
 7429    ) {
 7430        self.show_cursor_names(window, cx);
 7431    }
 7432
 7433    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7434        self.show_cursor_names = true;
 7435        cx.notify();
 7436        cx.spawn_in(window, async move |this, cx| {
 7437            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7438            this.update(cx, |this, cx| {
 7439                this.show_cursor_names = false;
 7440                cx.notify()
 7441            })
 7442            .ok()
 7443        })
 7444        .detach();
 7445    }
 7446
 7447    pub fn next_edit_prediction(
 7448        &mut self,
 7449        _: &NextEditPrediction,
 7450        window: &mut Window,
 7451        cx: &mut Context<Self>,
 7452    ) {
 7453        if self.has_active_edit_prediction() {
 7454            self.cycle_edit_prediction(Direction::Next, window, cx);
 7455        } else {
 7456            let is_copilot_disabled = self
 7457                .refresh_edit_prediction(false, true, window, cx)
 7458                .is_none();
 7459            if is_copilot_disabled {
 7460                cx.propagate();
 7461            }
 7462        }
 7463    }
 7464
 7465    pub fn previous_edit_prediction(
 7466        &mut self,
 7467        _: &PreviousEditPrediction,
 7468        window: &mut Window,
 7469        cx: &mut Context<Self>,
 7470    ) {
 7471        if self.has_active_edit_prediction() {
 7472            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7473        } else {
 7474            let is_copilot_disabled = self
 7475                .refresh_edit_prediction(false, true, window, cx)
 7476                .is_none();
 7477            if is_copilot_disabled {
 7478                cx.propagate();
 7479            }
 7480        }
 7481    }
 7482
 7483    pub fn accept_edit_prediction(
 7484        &mut self,
 7485        _: &AcceptEditPrediction,
 7486        window: &mut Window,
 7487        cx: &mut Context<Self>,
 7488    ) {
 7489        if self.show_edit_predictions_in_menu() {
 7490            self.hide_context_menu(window, cx);
 7491        }
 7492
 7493        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7494            return;
 7495        };
 7496
 7497        match &active_edit_prediction.completion {
 7498            EditPrediction::MoveWithin { target, .. } => {
 7499                let target = *target;
 7500
 7501                if let Some(position_map) = &self.last_position_map {
 7502                    if position_map
 7503                        .visible_row_range
 7504                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7505                        || !self.edit_prediction_requires_modifier()
 7506                    {
 7507                        self.unfold_ranges(&[target..target], true, false, cx);
 7508                        // Note that this is also done in vim's handler of the Tab action.
 7509                        self.change_selections(
 7510                            SelectionEffects::scroll(Autoscroll::newest()),
 7511                            window,
 7512                            cx,
 7513                            |selections| {
 7514                                selections.select_anchor_ranges([target..target]);
 7515                            },
 7516                        );
 7517                        self.clear_row_highlights::<EditPredictionPreview>();
 7518
 7519                        self.edit_prediction_preview
 7520                            .set_previous_scroll_position(None);
 7521                    } else {
 7522                        self.edit_prediction_preview
 7523                            .set_previous_scroll_position(Some(
 7524                                position_map.snapshot.scroll_anchor,
 7525                            ));
 7526
 7527                        self.highlight_rows::<EditPredictionPreview>(
 7528                            target..target,
 7529                            cx.theme().colors().editor_highlighted_line_background,
 7530                            RowHighlightOptions {
 7531                                autoscroll: true,
 7532                                ..Default::default()
 7533                            },
 7534                            cx,
 7535                        );
 7536                        self.request_autoscroll(Autoscroll::fit(), cx);
 7537                    }
 7538                }
 7539            }
 7540            EditPrediction::MoveOutside { snapshot, target } => {
 7541                if let Some(workspace) = self.workspace() {
 7542                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7543                        .detach_and_log_err(cx);
 7544                }
 7545            }
 7546            EditPrediction::Edit { edits, .. } => {
 7547                self.report_edit_prediction_event(
 7548                    active_edit_prediction.completion_id.clone(),
 7549                    true,
 7550                    cx,
 7551                );
 7552
 7553                if let Some(provider) = self.edit_prediction_provider() {
 7554                    provider.accept(cx);
 7555                }
 7556
 7557                // Store the transaction ID and selections before applying the edit
 7558                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7559
 7560                let snapshot = self.buffer.read(cx).snapshot(cx);
 7561                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7562
 7563                self.buffer.update(cx, |buffer, cx| {
 7564                    buffer.edit(edits.iter().cloned(), None, cx)
 7565                });
 7566
 7567                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7568                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7569                });
 7570
 7571                let selections = self.selections.disjoint_anchors_arc();
 7572                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7573                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7574                    if has_new_transaction {
 7575                        self.selection_history
 7576                            .insert_transaction(transaction_id_now, selections);
 7577                    }
 7578                }
 7579
 7580                self.update_visible_edit_prediction(window, cx);
 7581                if self.active_edit_prediction.is_none() {
 7582                    self.refresh_edit_prediction(true, true, window, cx);
 7583                }
 7584
 7585                cx.notify();
 7586            }
 7587        }
 7588
 7589        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7590    }
 7591
 7592    pub fn accept_partial_edit_prediction(
 7593        &mut self,
 7594        _: &AcceptPartialEditPrediction,
 7595        window: &mut Window,
 7596        cx: &mut Context<Self>,
 7597    ) {
 7598        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7599            return;
 7600        };
 7601        if self.selections.count() != 1 {
 7602            return;
 7603        }
 7604
 7605        match &active_edit_prediction.completion {
 7606            EditPrediction::MoveWithin { target, .. } => {
 7607                let target = *target;
 7608                self.change_selections(
 7609                    SelectionEffects::scroll(Autoscroll::newest()),
 7610                    window,
 7611                    cx,
 7612                    |selections| {
 7613                        selections.select_anchor_ranges([target..target]);
 7614                    },
 7615                );
 7616            }
 7617            EditPrediction::MoveOutside { snapshot, target } => {
 7618                if let Some(workspace) = self.workspace() {
 7619                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7620                        .detach_and_log_err(cx);
 7621                }
 7622            }
 7623            EditPrediction::Edit { edits, .. } => {
 7624                self.report_edit_prediction_event(
 7625                    active_edit_prediction.completion_id.clone(),
 7626                    true,
 7627                    cx,
 7628                );
 7629
 7630                // Find an insertion that starts at the cursor position.
 7631                let snapshot = self.buffer.read(cx).snapshot(cx);
 7632                let cursor_offset = self
 7633                    .selections
 7634                    .newest::<usize>(&self.display_snapshot(cx))
 7635                    .head();
 7636                let insertion = edits.iter().find_map(|(range, text)| {
 7637                    let range = range.to_offset(&snapshot);
 7638                    if range.is_empty() && range.start == cursor_offset {
 7639                        Some(text)
 7640                    } else {
 7641                        None
 7642                    }
 7643                });
 7644
 7645                if let Some(text) = insertion {
 7646                    let mut partial_completion = text
 7647                        .chars()
 7648                        .by_ref()
 7649                        .take_while(|c| c.is_alphabetic())
 7650                        .collect::<String>();
 7651                    if partial_completion.is_empty() {
 7652                        partial_completion = text
 7653                            .chars()
 7654                            .by_ref()
 7655                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7656                            .collect::<String>();
 7657                    }
 7658
 7659                    cx.emit(EditorEvent::InputHandled {
 7660                        utf16_range_to_replace: None,
 7661                        text: partial_completion.clone().into(),
 7662                    });
 7663
 7664                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7665
 7666                    self.refresh_edit_prediction(true, true, window, cx);
 7667                    cx.notify();
 7668                } else {
 7669                    self.accept_edit_prediction(&Default::default(), window, cx);
 7670                }
 7671            }
 7672        }
 7673    }
 7674
 7675    fn discard_edit_prediction(
 7676        &mut self,
 7677        should_report_edit_prediction_event: bool,
 7678        cx: &mut Context<Self>,
 7679    ) -> bool {
 7680        if should_report_edit_prediction_event {
 7681            let completion_id = self
 7682                .active_edit_prediction
 7683                .as_ref()
 7684                .and_then(|active_completion| active_completion.completion_id.clone());
 7685
 7686            self.report_edit_prediction_event(completion_id, false, cx);
 7687        }
 7688
 7689        if let Some(provider) = self.edit_prediction_provider() {
 7690            provider.discard(cx);
 7691        }
 7692
 7693        self.take_active_edit_prediction(cx)
 7694    }
 7695
 7696    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7697        let Some(provider) = self.edit_prediction_provider() else {
 7698            return;
 7699        };
 7700
 7701        let Some((_, buffer, _)) = self
 7702            .buffer
 7703            .read(cx)
 7704            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7705        else {
 7706            return;
 7707        };
 7708
 7709        let extension = buffer
 7710            .read(cx)
 7711            .file()
 7712            .and_then(|file| Some(file.path().extension()?.to_string()));
 7713
 7714        let event_type = match accepted {
 7715            true => "Edit Prediction Accepted",
 7716            false => "Edit Prediction Discarded",
 7717        };
 7718        telemetry::event!(
 7719            event_type,
 7720            provider = provider.name(),
 7721            prediction_id = id,
 7722            suggestion_accepted = accepted,
 7723            file_extension = extension,
 7724        );
 7725    }
 7726
 7727    fn open_editor_at_anchor(
 7728        snapshot: &language::BufferSnapshot,
 7729        target: language::Anchor,
 7730        workspace: &Entity<Workspace>,
 7731        window: &mut Window,
 7732        cx: &mut App,
 7733    ) -> Task<Result<()>> {
 7734        workspace.update(cx, |workspace, cx| {
 7735            let path = snapshot.file().map(|file| file.full_path(cx));
 7736            let Some(path) =
 7737                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7738            else {
 7739                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7740            };
 7741            let target = text::ToPoint::to_point(&target, snapshot);
 7742            let item = workspace.open_path(path, None, true, window, cx);
 7743            window.spawn(cx, async move |cx| {
 7744                let Some(editor) = item.await?.downcast::<Editor>() else {
 7745                    return Ok(());
 7746                };
 7747                editor
 7748                    .update_in(cx, |editor, window, cx| {
 7749                        editor.go_to_singleton_buffer_point(target, window, cx);
 7750                    })
 7751                    .ok();
 7752                anyhow::Ok(())
 7753            })
 7754        })
 7755    }
 7756
 7757    pub fn has_active_edit_prediction(&self) -> bool {
 7758        self.active_edit_prediction.is_some()
 7759    }
 7760
 7761    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7762        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7763            return false;
 7764        };
 7765
 7766        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7767        self.clear_highlights::<EditPredictionHighlight>(cx);
 7768        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7769        true
 7770    }
 7771
 7772    /// Returns true when we're displaying the edit prediction popover below the cursor
 7773    /// like we are not previewing and the LSP autocomplete menu is visible
 7774    /// or we are in `when_holding_modifier` mode.
 7775    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7776        if self.edit_prediction_preview_is_active()
 7777            || !self.show_edit_predictions_in_menu()
 7778            || !self.edit_predictions_enabled()
 7779        {
 7780            return false;
 7781        }
 7782
 7783        if self.has_visible_completions_menu() {
 7784            return true;
 7785        }
 7786
 7787        has_completion && self.edit_prediction_requires_modifier()
 7788    }
 7789
 7790    fn handle_modifiers_changed(
 7791        &mut self,
 7792        modifiers: Modifiers,
 7793        position_map: &PositionMap,
 7794        window: &mut Window,
 7795        cx: &mut Context<Self>,
 7796    ) {
 7797        if self.show_edit_predictions_in_menu() {
 7798            self.update_edit_prediction_preview(&modifiers, window, cx);
 7799        }
 7800
 7801        self.update_selection_mode(&modifiers, position_map, window, cx);
 7802
 7803        let mouse_position = window.mouse_position();
 7804        if !position_map.text_hitbox.is_hovered(window) {
 7805            return;
 7806        }
 7807
 7808        self.update_hovered_link(
 7809            position_map.point_for_position(mouse_position),
 7810            &position_map.snapshot,
 7811            modifiers,
 7812            window,
 7813            cx,
 7814        )
 7815    }
 7816
 7817    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7818        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7819        if invert {
 7820            match multi_cursor_setting {
 7821                MultiCursorModifier::Alt => modifiers.alt,
 7822                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7823            }
 7824        } else {
 7825            match multi_cursor_setting {
 7826                MultiCursorModifier::Alt => modifiers.secondary(),
 7827                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7828            }
 7829        }
 7830    }
 7831
 7832    fn columnar_selection_mode(
 7833        modifiers: &Modifiers,
 7834        cx: &mut Context<Self>,
 7835    ) -> Option<ColumnarMode> {
 7836        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7837            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7838                Some(ColumnarMode::FromMouse)
 7839            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7840                Some(ColumnarMode::FromSelection)
 7841            } else {
 7842                None
 7843            }
 7844        } else {
 7845            None
 7846        }
 7847    }
 7848
 7849    fn update_selection_mode(
 7850        &mut self,
 7851        modifiers: &Modifiers,
 7852        position_map: &PositionMap,
 7853        window: &mut Window,
 7854        cx: &mut Context<Self>,
 7855    ) {
 7856        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7857            return;
 7858        };
 7859        if self.selections.pending_anchor().is_none() {
 7860            return;
 7861        }
 7862
 7863        let mouse_position = window.mouse_position();
 7864        let point_for_position = position_map.point_for_position(mouse_position);
 7865        let position = point_for_position.previous_valid;
 7866
 7867        self.select(
 7868            SelectPhase::BeginColumnar {
 7869                position,
 7870                reset: false,
 7871                mode,
 7872                goal_column: point_for_position.exact_unclipped.column(),
 7873            },
 7874            window,
 7875            cx,
 7876        );
 7877    }
 7878
 7879    fn update_edit_prediction_preview(
 7880        &mut self,
 7881        modifiers: &Modifiers,
 7882        window: &mut Window,
 7883        cx: &mut Context<Self>,
 7884    ) {
 7885        let mut modifiers_held = false;
 7886        if let Some(accept_keystroke) = self
 7887            .accept_edit_prediction_keybind(false, window, cx)
 7888            .keystroke()
 7889        {
 7890            modifiers_held = modifiers_held
 7891                || (accept_keystroke.modifiers() == modifiers
 7892                    && accept_keystroke.modifiers().modified());
 7893        };
 7894        if let Some(accept_partial_keystroke) = self
 7895            .accept_edit_prediction_keybind(true, window, cx)
 7896            .keystroke()
 7897        {
 7898            modifiers_held = modifiers_held
 7899                || (accept_partial_keystroke.modifiers() == modifiers
 7900                    && accept_partial_keystroke.modifiers().modified());
 7901        }
 7902
 7903        if modifiers_held {
 7904            if matches!(
 7905                self.edit_prediction_preview,
 7906                EditPredictionPreview::Inactive { .. }
 7907            ) {
 7908                self.edit_prediction_preview = EditPredictionPreview::Active {
 7909                    previous_scroll_position: None,
 7910                    since: Instant::now(),
 7911                };
 7912
 7913                self.update_visible_edit_prediction(window, cx);
 7914                cx.notify();
 7915            }
 7916        } else if let EditPredictionPreview::Active {
 7917            previous_scroll_position,
 7918            since,
 7919        } = self.edit_prediction_preview
 7920        {
 7921            if let (Some(previous_scroll_position), Some(position_map)) =
 7922                (previous_scroll_position, self.last_position_map.as_ref())
 7923            {
 7924                self.set_scroll_position(
 7925                    previous_scroll_position
 7926                        .scroll_position(&position_map.snapshot.display_snapshot),
 7927                    window,
 7928                    cx,
 7929                );
 7930            }
 7931
 7932            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7933                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7934            };
 7935            self.clear_row_highlights::<EditPredictionPreview>();
 7936            self.update_visible_edit_prediction(window, cx);
 7937            cx.notify();
 7938        }
 7939    }
 7940
 7941    fn update_visible_edit_prediction(
 7942        &mut self,
 7943        _window: &mut Window,
 7944        cx: &mut Context<Self>,
 7945    ) -> Option<()> {
 7946        if DisableAiSettings::get_global(cx).disable_ai {
 7947            return None;
 7948        }
 7949
 7950        if self.ime_transaction.is_some() {
 7951            self.discard_edit_prediction(false, cx);
 7952            return None;
 7953        }
 7954
 7955        let selection = self.selections.newest_anchor();
 7956        let cursor = selection.head();
 7957        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7958        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7959        let excerpt_id = cursor.excerpt_id;
 7960
 7961        let show_in_menu = self.show_edit_predictions_in_menu();
 7962        let completions_menu_has_precedence = !show_in_menu
 7963            && (self.context_menu.borrow().is_some()
 7964                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7965
 7966        if completions_menu_has_precedence
 7967            || !offset_selection.is_empty()
 7968            || self
 7969                .active_edit_prediction
 7970                .as_ref()
 7971                .is_some_and(|completion| {
 7972                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7973                        return false;
 7974                    };
 7975                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7976                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7977                    !invalidation_range.contains(&offset_selection.head())
 7978                })
 7979        {
 7980            self.discard_edit_prediction(false, cx);
 7981            return None;
 7982        }
 7983
 7984        self.take_active_edit_prediction(cx);
 7985        let Some(provider) = self.edit_prediction_provider() else {
 7986            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7987            return None;
 7988        };
 7989
 7990        let (buffer, cursor_buffer_position) =
 7991            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7992
 7993        self.edit_prediction_settings =
 7994            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7995
 7996        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7997
 7998        if self.edit_prediction_indent_conflict {
 7999            let cursor_point = cursor.to_point(&multibuffer);
 8000
 8001            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 8002
 8003            if let Some((_, indent)) = indents.iter().next()
 8004                && indent.len == cursor_point.column
 8005            {
 8006                self.edit_prediction_indent_conflict = false;
 8007            }
 8008        }
 8009
 8010        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8011
 8012        let (completion_id, edits, edit_preview) = match edit_prediction {
 8013            edit_prediction::EditPrediction::Local {
 8014                id,
 8015                edits,
 8016                edit_preview,
 8017            } => (id, edits, edit_preview),
 8018            edit_prediction::EditPrediction::Jump {
 8019                id,
 8020                snapshot,
 8021                target,
 8022            } => {
 8023                self.stale_edit_prediction_in_menu = None;
 8024                self.active_edit_prediction = Some(EditPredictionState {
 8025                    inlay_ids: vec![],
 8026                    completion: EditPrediction::MoveOutside { snapshot, target },
 8027                    completion_id: id,
 8028                    invalidation_range: None,
 8029                });
 8030                cx.notify();
 8031                return Some(());
 8032            }
 8033        };
 8034
 8035        let edits = edits
 8036            .into_iter()
 8037            .flat_map(|(range, new_text)| {
 8038                Some((
 8039                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8040                    new_text,
 8041                ))
 8042            })
 8043            .collect::<Vec<_>>();
 8044        if edits.is_empty() {
 8045            return None;
 8046        }
 8047
 8048        let first_edit_start = edits.first().unwrap().0.start;
 8049        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8050        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8051
 8052        let last_edit_end = edits.last().unwrap().0.end;
 8053        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8054        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8055
 8056        let cursor_row = cursor.to_point(&multibuffer).row;
 8057
 8058        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8059
 8060        let mut inlay_ids = Vec::new();
 8061        let invalidation_row_range;
 8062        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8063            Some(cursor_row..edit_end_row)
 8064        } else if cursor_row > edit_end_row {
 8065            Some(edit_start_row..cursor_row)
 8066        } else {
 8067            None
 8068        };
 8069        let supports_jump = self
 8070            .edit_prediction_provider
 8071            .as_ref()
 8072            .map(|provider| provider.provider.supports_jump_to_edit())
 8073            .unwrap_or(true);
 8074
 8075        let is_move = supports_jump
 8076            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8077        let completion = if is_move {
 8078            invalidation_row_range =
 8079                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8080            let target = first_edit_start;
 8081            EditPrediction::MoveWithin { target, snapshot }
 8082        } else {
 8083            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8084                && !self.edit_predictions_hidden_for_vim_mode;
 8085
 8086            if show_completions_in_buffer {
 8087                if edits
 8088                    .iter()
 8089                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8090                {
 8091                    let mut inlays = Vec::new();
 8092                    for (range, new_text) in &edits {
 8093                        let inlay = Inlay::edit_prediction(
 8094                            post_inc(&mut self.next_inlay_id),
 8095                            range.start,
 8096                            new_text.as_str(),
 8097                        );
 8098                        inlay_ids.push(inlay.id);
 8099                        inlays.push(inlay);
 8100                    }
 8101
 8102                    self.splice_inlays(&[], inlays, cx);
 8103                } else {
 8104                    let background_color = cx.theme().status().deleted_background;
 8105                    self.highlight_text::<EditPredictionHighlight>(
 8106                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8107                        HighlightStyle {
 8108                            background_color: Some(background_color),
 8109                            ..Default::default()
 8110                        },
 8111                        cx,
 8112                    );
 8113                }
 8114            }
 8115
 8116            invalidation_row_range = edit_start_row..edit_end_row;
 8117
 8118            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8119                if provider.show_tab_accept_marker() {
 8120                    EditDisplayMode::TabAccept
 8121                } else {
 8122                    EditDisplayMode::Inline
 8123                }
 8124            } else {
 8125                EditDisplayMode::DiffPopover
 8126            };
 8127
 8128            EditPrediction::Edit {
 8129                edits,
 8130                edit_preview,
 8131                display_mode,
 8132                snapshot,
 8133            }
 8134        };
 8135
 8136        let invalidation_range = multibuffer
 8137            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8138            ..multibuffer.anchor_after(Point::new(
 8139                invalidation_row_range.end,
 8140                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8141            ));
 8142
 8143        self.stale_edit_prediction_in_menu = None;
 8144        self.active_edit_prediction = Some(EditPredictionState {
 8145            inlay_ids,
 8146            completion,
 8147            completion_id,
 8148            invalidation_range: Some(invalidation_range),
 8149        });
 8150
 8151        cx.notify();
 8152
 8153        Some(())
 8154    }
 8155
 8156    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8157        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8158    }
 8159
 8160    fn clear_tasks(&mut self) {
 8161        self.tasks.clear()
 8162    }
 8163
 8164    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8165        if self.tasks.insert(key, value).is_some() {
 8166            // This case should hopefully be rare, but just in case...
 8167            log::error!(
 8168                "multiple different run targets found on a single line, only the last target will be rendered"
 8169            )
 8170        }
 8171    }
 8172
 8173    /// Get all display points of breakpoints that will be rendered within editor
 8174    ///
 8175    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8176    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8177    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8178    fn active_breakpoints(
 8179        &self,
 8180        range: Range<DisplayRow>,
 8181        window: &mut Window,
 8182        cx: &mut Context<Self>,
 8183    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8184        let mut breakpoint_display_points = HashMap::default();
 8185
 8186        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8187            return breakpoint_display_points;
 8188        };
 8189
 8190        let snapshot = self.snapshot(window, cx);
 8191
 8192        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8193        let Some(project) = self.project() else {
 8194            return breakpoint_display_points;
 8195        };
 8196
 8197        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8198            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8199
 8200        for (buffer_snapshot, range, excerpt_id) in
 8201            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8202        {
 8203            let Some(buffer) = project
 8204                .read(cx)
 8205                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8206            else {
 8207                continue;
 8208            };
 8209            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8210                &buffer,
 8211                Some(
 8212                    buffer_snapshot.anchor_before(range.start)
 8213                        ..buffer_snapshot.anchor_after(range.end),
 8214                ),
 8215                buffer_snapshot,
 8216                cx,
 8217            );
 8218            for (breakpoint, state) in breakpoints {
 8219                let multi_buffer_anchor =
 8220                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8221                let position = multi_buffer_anchor
 8222                    .to_point(multi_buffer_snapshot)
 8223                    .to_display_point(&snapshot);
 8224
 8225                breakpoint_display_points.insert(
 8226                    position.row(),
 8227                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8228                );
 8229            }
 8230        }
 8231
 8232        breakpoint_display_points
 8233    }
 8234
 8235    fn breakpoint_context_menu(
 8236        &self,
 8237        anchor: Anchor,
 8238        window: &mut Window,
 8239        cx: &mut Context<Self>,
 8240    ) -> Entity<ui::ContextMenu> {
 8241        let weak_editor = cx.weak_entity();
 8242        let focus_handle = self.focus_handle(cx);
 8243
 8244        let row = self
 8245            .buffer
 8246            .read(cx)
 8247            .snapshot(cx)
 8248            .summary_for_anchor::<Point>(&anchor)
 8249            .row;
 8250
 8251        let breakpoint = self
 8252            .breakpoint_at_row(row, window, cx)
 8253            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8254
 8255        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8256            "Edit Log Breakpoint"
 8257        } else {
 8258            "Set Log Breakpoint"
 8259        };
 8260
 8261        let condition_breakpoint_msg = if breakpoint
 8262            .as_ref()
 8263            .is_some_and(|bp| bp.1.condition.is_some())
 8264        {
 8265            "Edit Condition Breakpoint"
 8266        } else {
 8267            "Set Condition Breakpoint"
 8268        };
 8269
 8270        let hit_condition_breakpoint_msg = if breakpoint
 8271            .as_ref()
 8272            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8273        {
 8274            "Edit Hit Condition Breakpoint"
 8275        } else {
 8276            "Set Hit Condition Breakpoint"
 8277        };
 8278
 8279        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8280            "Unset Breakpoint"
 8281        } else {
 8282            "Set Breakpoint"
 8283        };
 8284
 8285        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8286
 8287        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8288            BreakpointState::Enabled => Some("Disable"),
 8289            BreakpointState::Disabled => Some("Enable"),
 8290        });
 8291
 8292        let (anchor, breakpoint) =
 8293            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8294
 8295        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8296            menu.on_blur_subscription(Subscription::new(|| {}))
 8297                .context(focus_handle)
 8298                .when(run_to_cursor, |this| {
 8299                    let weak_editor = weak_editor.clone();
 8300                    this.entry("Run to cursor", None, move |window, cx| {
 8301                        weak_editor
 8302                            .update(cx, |editor, cx| {
 8303                                editor.change_selections(
 8304                                    SelectionEffects::no_scroll(),
 8305                                    window,
 8306                                    cx,
 8307                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8308                                );
 8309                            })
 8310                            .ok();
 8311
 8312                        window.dispatch_action(Box::new(RunToCursor), cx);
 8313                    })
 8314                    .separator()
 8315                })
 8316                .when_some(toggle_state_msg, |this, msg| {
 8317                    this.entry(msg, None, {
 8318                        let weak_editor = weak_editor.clone();
 8319                        let breakpoint = breakpoint.clone();
 8320                        move |_window, cx| {
 8321                            weak_editor
 8322                                .update(cx, |this, cx| {
 8323                                    this.edit_breakpoint_at_anchor(
 8324                                        anchor,
 8325                                        breakpoint.as_ref().clone(),
 8326                                        BreakpointEditAction::InvertState,
 8327                                        cx,
 8328                                    );
 8329                                })
 8330                                .log_err();
 8331                        }
 8332                    })
 8333                })
 8334                .entry(set_breakpoint_msg, None, {
 8335                    let weak_editor = weak_editor.clone();
 8336                    let breakpoint = breakpoint.clone();
 8337                    move |_window, cx| {
 8338                        weak_editor
 8339                            .update(cx, |this, cx| {
 8340                                this.edit_breakpoint_at_anchor(
 8341                                    anchor,
 8342                                    breakpoint.as_ref().clone(),
 8343                                    BreakpointEditAction::Toggle,
 8344                                    cx,
 8345                                );
 8346                            })
 8347                            .log_err();
 8348                    }
 8349                })
 8350                .entry(log_breakpoint_msg, None, {
 8351                    let breakpoint = breakpoint.clone();
 8352                    let weak_editor = weak_editor.clone();
 8353                    move |window, cx| {
 8354                        weak_editor
 8355                            .update(cx, |this, cx| {
 8356                                this.add_edit_breakpoint_block(
 8357                                    anchor,
 8358                                    breakpoint.as_ref(),
 8359                                    BreakpointPromptEditAction::Log,
 8360                                    window,
 8361                                    cx,
 8362                                );
 8363                            })
 8364                            .log_err();
 8365                    }
 8366                })
 8367                .entry(condition_breakpoint_msg, None, {
 8368                    let breakpoint = breakpoint.clone();
 8369                    let weak_editor = weak_editor.clone();
 8370                    move |window, cx| {
 8371                        weak_editor
 8372                            .update(cx, |this, cx| {
 8373                                this.add_edit_breakpoint_block(
 8374                                    anchor,
 8375                                    breakpoint.as_ref(),
 8376                                    BreakpointPromptEditAction::Condition,
 8377                                    window,
 8378                                    cx,
 8379                                );
 8380                            })
 8381                            .log_err();
 8382                    }
 8383                })
 8384                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8385                    weak_editor
 8386                        .update(cx, |this, cx| {
 8387                            this.add_edit_breakpoint_block(
 8388                                anchor,
 8389                                breakpoint.as_ref(),
 8390                                BreakpointPromptEditAction::HitCondition,
 8391                                window,
 8392                                cx,
 8393                            );
 8394                        })
 8395                        .log_err();
 8396                })
 8397        })
 8398    }
 8399
 8400    fn render_breakpoint(
 8401        &self,
 8402        position: Anchor,
 8403        row: DisplayRow,
 8404        breakpoint: &Breakpoint,
 8405        state: Option<BreakpointSessionState>,
 8406        cx: &mut Context<Self>,
 8407    ) -> IconButton {
 8408        let is_rejected = state.is_some_and(|s| !s.verified);
 8409        // Is it a breakpoint that shows up when hovering over gutter?
 8410        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8411            (false, false),
 8412            |PhantomBreakpointIndicator {
 8413                 is_active,
 8414                 display_row,
 8415                 collides_with_existing_breakpoint,
 8416             }| {
 8417                (
 8418                    is_active && display_row == row,
 8419                    collides_with_existing_breakpoint,
 8420                )
 8421            },
 8422        );
 8423
 8424        let (color, icon) = {
 8425            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8426                (false, false) => ui::IconName::DebugBreakpoint,
 8427                (true, false) => ui::IconName::DebugLogBreakpoint,
 8428                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8429                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8430            };
 8431
 8432            let color = if is_phantom {
 8433                Color::Hint
 8434            } else if is_rejected {
 8435                Color::Disabled
 8436            } else {
 8437                Color::Debugger
 8438            };
 8439
 8440            (color, icon)
 8441        };
 8442
 8443        let breakpoint = Arc::from(breakpoint.clone());
 8444
 8445        let alt_as_text = gpui::Keystroke {
 8446            modifiers: Modifiers::secondary_key(),
 8447            ..Default::default()
 8448        };
 8449        let primary_action_text = if breakpoint.is_disabled() {
 8450            "Enable breakpoint"
 8451        } else if is_phantom && !collides_with_existing {
 8452            "Set breakpoint"
 8453        } else {
 8454            "Unset breakpoint"
 8455        };
 8456        let focus_handle = self.focus_handle.clone();
 8457
 8458        let meta = if is_rejected {
 8459            SharedString::from("No executable code is associated with this line.")
 8460        } else if collides_with_existing && !breakpoint.is_disabled() {
 8461            SharedString::from(format!(
 8462                "{alt_as_text}-click to disable,\nright-click for more options."
 8463            ))
 8464        } else {
 8465            SharedString::from("Right-click for more options.")
 8466        };
 8467        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8468            .icon_size(IconSize::XSmall)
 8469            .size(ui::ButtonSize::None)
 8470            .when(is_rejected, |this| {
 8471                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8472            })
 8473            .icon_color(color)
 8474            .style(ButtonStyle::Transparent)
 8475            .on_click(cx.listener({
 8476                move |editor, event: &ClickEvent, window, cx| {
 8477                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8478                        BreakpointEditAction::InvertState
 8479                    } else {
 8480                        BreakpointEditAction::Toggle
 8481                    };
 8482
 8483                    window.focus(&editor.focus_handle(cx));
 8484                    editor.edit_breakpoint_at_anchor(
 8485                        position,
 8486                        breakpoint.as_ref().clone(),
 8487                        edit_action,
 8488                        cx,
 8489                    );
 8490                }
 8491            }))
 8492            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8493                editor.set_breakpoint_context_menu(
 8494                    row,
 8495                    Some(position),
 8496                    event.position(),
 8497                    window,
 8498                    cx,
 8499                );
 8500            }))
 8501            .tooltip(move |window, cx| {
 8502                Tooltip::with_meta_in(
 8503                    primary_action_text,
 8504                    Some(&ToggleBreakpoint),
 8505                    meta.clone(),
 8506                    &focus_handle,
 8507                    window,
 8508                    cx,
 8509                )
 8510            })
 8511    }
 8512
 8513    fn build_tasks_context(
 8514        project: &Entity<Project>,
 8515        buffer: &Entity<Buffer>,
 8516        buffer_row: u32,
 8517        tasks: &Arc<RunnableTasks>,
 8518        cx: &mut Context<Self>,
 8519    ) -> Task<Option<task::TaskContext>> {
 8520        let position = Point::new(buffer_row, tasks.column);
 8521        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8522        let location = Location {
 8523            buffer: buffer.clone(),
 8524            range: range_start..range_start,
 8525        };
 8526        // Fill in the environmental variables from the tree-sitter captures
 8527        let mut captured_task_variables = TaskVariables::default();
 8528        for (capture_name, value) in tasks.extra_variables.clone() {
 8529            captured_task_variables.insert(
 8530                task::VariableName::Custom(capture_name.into()),
 8531                value.clone(),
 8532            );
 8533        }
 8534        project.update(cx, |project, cx| {
 8535            project.task_store().update(cx, |task_store, cx| {
 8536                task_store.task_context_for_location(captured_task_variables, location, cx)
 8537            })
 8538        })
 8539    }
 8540
 8541    pub fn spawn_nearest_task(
 8542        &mut self,
 8543        action: &SpawnNearestTask,
 8544        window: &mut Window,
 8545        cx: &mut Context<Self>,
 8546    ) {
 8547        let Some((workspace, _)) = self.workspace.clone() else {
 8548            return;
 8549        };
 8550        let Some(project) = self.project.clone() else {
 8551            return;
 8552        };
 8553
 8554        // Try to find a closest, enclosing node using tree-sitter that has a task
 8555        let Some((buffer, buffer_row, tasks)) = self
 8556            .find_enclosing_node_task(cx)
 8557            // Or find the task that's closest in row-distance.
 8558            .or_else(|| self.find_closest_task(cx))
 8559        else {
 8560            return;
 8561        };
 8562
 8563        let reveal_strategy = action.reveal;
 8564        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8565        cx.spawn_in(window, async move |_, cx| {
 8566            let context = task_context.await?;
 8567            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8568
 8569            let resolved = &mut resolved_task.resolved;
 8570            resolved.reveal = reveal_strategy;
 8571
 8572            workspace
 8573                .update_in(cx, |workspace, window, cx| {
 8574                    workspace.schedule_resolved_task(
 8575                        task_source_kind,
 8576                        resolved_task,
 8577                        false,
 8578                        window,
 8579                        cx,
 8580                    );
 8581                })
 8582                .ok()
 8583        })
 8584        .detach();
 8585    }
 8586
 8587    fn find_closest_task(
 8588        &mut self,
 8589        cx: &mut Context<Self>,
 8590    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8591        let cursor_row = self
 8592            .selections
 8593            .newest_adjusted(&self.display_snapshot(cx))
 8594            .head()
 8595            .row;
 8596
 8597        let ((buffer_id, row), tasks) = self
 8598            .tasks
 8599            .iter()
 8600            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8601
 8602        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8603        let tasks = Arc::new(tasks.to_owned());
 8604        Some((buffer, *row, tasks))
 8605    }
 8606
 8607    fn find_enclosing_node_task(
 8608        &mut self,
 8609        cx: &mut Context<Self>,
 8610    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8611        let snapshot = self.buffer.read(cx).snapshot(cx);
 8612        let offset = self
 8613            .selections
 8614            .newest::<usize>(&self.display_snapshot(cx))
 8615            .head();
 8616        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8617        let buffer_id = excerpt.buffer().remote_id();
 8618
 8619        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8620        let mut cursor = layer.node().walk();
 8621
 8622        while cursor.goto_first_child_for_byte(offset).is_some() {
 8623            if cursor.node().end_byte() == offset {
 8624                cursor.goto_next_sibling();
 8625            }
 8626        }
 8627
 8628        // Ascend to the smallest ancestor that contains the range and has a task.
 8629        loop {
 8630            let node = cursor.node();
 8631            let node_range = node.byte_range();
 8632            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8633
 8634            // Check if this node contains our offset
 8635            if node_range.start <= offset && node_range.end >= offset {
 8636                // If it contains offset, check for task
 8637                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8638                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8639                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8640                }
 8641            }
 8642
 8643            if !cursor.goto_parent() {
 8644                break;
 8645            }
 8646        }
 8647        None
 8648    }
 8649
 8650    fn render_run_indicator(
 8651        &self,
 8652        _style: &EditorStyle,
 8653        is_active: bool,
 8654        row: DisplayRow,
 8655        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8656        cx: &mut Context<Self>,
 8657    ) -> IconButton {
 8658        let color = Color::Muted;
 8659        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8660
 8661        IconButton::new(
 8662            ("run_indicator", row.0 as usize),
 8663            ui::IconName::PlayOutlined,
 8664        )
 8665        .shape(ui::IconButtonShape::Square)
 8666        .icon_size(IconSize::XSmall)
 8667        .icon_color(color)
 8668        .toggle_state(is_active)
 8669        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8670            let quick_launch = match e {
 8671                ClickEvent::Keyboard(_) => true,
 8672                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8673            };
 8674
 8675            window.focus(&editor.focus_handle(cx));
 8676            editor.toggle_code_actions(
 8677                &ToggleCodeActions {
 8678                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8679                    quick_launch,
 8680                },
 8681                window,
 8682                cx,
 8683            );
 8684        }))
 8685        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8686            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8687        }))
 8688    }
 8689
 8690    pub fn context_menu_visible(&self) -> bool {
 8691        !self.edit_prediction_preview_is_active()
 8692            && self
 8693                .context_menu
 8694                .borrow()
 8695                .as_ref()
 8696                .is_some_and(|menu| menu.visible())
 8697    }
 8698
 8699    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8700        self.context_menu
 8701            .borrow()
 8702            .as_ref()
 8703            .map(|menu| menu.origin())
 8704    }
 8705
 8706    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8707        self.context_menu_options = Some(options);
 8708    }
 8709
 8710    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8711    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8712
 8713    fn render_edit_prediction_popover(
 8714        &mut self,
 8715        text_bounds: &Bounds<Pixels>,
 8716        content_origin: gpui::Point<Pixels>,
 8717        right_margin: Pixels,
 8718        editor_snapshot: &EditorSnapshot,
 8719        visible_row_range: Range<DisplayRow>,
 8720        scroll_top: ScrollOffset,
 8721        scroll_bottom: ScrollOffset,
 8722        line_layouts: &[LineWithInvisibles],
 8723        line_height: Pixels,
 8724        scroll_position: gpui::Point<ScrollOffset>,
 8725        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8726        newest_selection_head: Option<DisplayPoint>,
 8727        editor_width: Pixels,
 8728        style: &EditorStyle,
 8729        window: &mut Window,
 8730        cx: &mut App,
 8731    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8732        if self.mode().is_minimap() {
 8733            return None;
 8734        }
 8735        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8736
 8737        if self.edit_prediction_visible_in_cursor_popover(true) {
 8738            return None;
 8739        }
 8740
 8741        match &active_edit_prediction.completion {
 8742            EditPrediction::MoveWithin { target, .. } => {
 8743                let target_display_point = target.to_display_point(editor_snapshot);
 8744
 8745                if self.edit_prediction_requires_modifier() {
 8746                    if !self.edit_prediction_preview_is_active() {
 8747                        return None;
 8748                    }
 8749
 8750                    self.render_edit_prediction_modifier_jump_popover(
 8751                        text_bounds,
 8752                        content_origin,
 8753                        visible_row_range,
 8754                        line_layouts,
 8755                        line_height,
 8756                        scroll_pixel_position,
 8757                        newest_selection_head,
 8758                        target_display_point,
 8759                        window,
 8760                        cx,
 8761                    )
 8762                } else {
 8763                    self.render_edit_prediction_eager_jump_popover(
 8764                        text_bounds,
 8765                        content_origin,
 8766                        editor_snapshot,
 8767                        visible_row_range,
 8768                        scroll_top,
 8769                        scroll_bottom,
 8770                        line_height,
 8771                        scroll_pixel_position,
 8772                        target_display_point,
 8773                        editor_width,
 8774                        window,
 8775                        cx,
 8776                    )
 8777                }
 8778            }
 8779            EditPrediction::Edit {
 8780                display_mode: EditDisplayMode::Inline,
 8781                ..
 8782            } => None,
 8783            EditPrediction::Edit {
 8784                display_mode: EditDisplayMode::TabAccept,
 8785                edits,
 8786                ..
 8787            } => {
 8788                let range = &edits.first()?.0;
 8789                let target_display_point = range.end.to_display_point(editor_snapshot);
 8790
 8791                self.render_edit_prediction_end_of_line_popover(
 8792                    "Accept",
 8793                    editor_snapshot,
 8794                    visible_row_range,
 8795                    target_display_point,
 8796                    line_height,
 8797                    scroll_pixel_position,
 8798                    content_origin,
 8799                    editor_width,
 8800                    window,
 8801                    cx,
 8802                )
 8803            }
 8804            EditPrediction::Edit {
 8805                edits,
 8806                edit_preview,
 8807                display_mode: EditDisplayMode::DiffPopover,
 8808                snapshot,
 8809            } => self.render_edit_prediction_diff_popover(
 8810                text_bounds,
 8811                content_origin,
 8812                right_margin,
 8813                editor_snapshot,
 8814                visible_row_range,
 8815                line_layouts,
 8816                line_height,
 8817                scroll_position,
 8818                scroll_pixel_position,
 8819                newest_selection_head,
 8820                editor_width,
 8821                style,
 8822                edits,
 8823                edit_preview,
 8824                snapshot,
 8825                window,
 8826                cx,
 8827            ),
 8828            EditPrediction::MoveOutside { snapshot, .. } => {
 8829                let file_name = snapshot
 8830                    .file()
 8831                    .map(|file| file.file_name(cx))
 8832                    .unwrap_or("untitled");
 8833                let mut element = self
 8834                    .render_edit_prediction_line_popover(
 8835                        format!("Jump to {file_name}"),
 8836                        Some(IconName::ZedPredict),
 8837                        window,
 8838                        cx,
 8839                    )
 8840                    .into_any();
 8841
 8842                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8843                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8844                let origin_y = text_bounds.size.height - size.height - px(30.);
 8845                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8846                element.prepaint_at(origin, window, cx);
 8847
 8848                Some((element, origin))
 8849            }
 8850        }
 8851    }
 8852
 8853    fn render_edit_prediction_modifier_jump_popover(
 8854        &mut self,
 8855        text_bounds: &Bounds<Pixels>,
 8856        content_origin: gpui::Point<Pixels>,
 8857        visible_row_range: Range<DisplayRow>,
 8858        line_layouts: &[LineWithInvisibles],
 8859        line_height: Pixels,
 8860        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8861        newest_selection_head: Option<DisplayPoint>,
 8862        target_display_point: DisplayPoint,
 8863        window: &mut Window,
 8864        cx: &mut App,
 8865    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8866        let scrolled_content_origin =
 8867            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8868
 8869        const SCROLL_PADDING_Y: Pixels = px(12.);
 8870
 8871        if target_display_point.row() < visible_row_range.start {
 8872            return self.render_edit_prediction_scroll_popover(
 8873                |_| SCROLL_PADDING_Y,
 8874                IconName::ArrowUp,
 8875                visible_row_range,
 8876                line_layouts,
 8877                newest_selection_head,
 8878                scrolled_content_origin,
 8879                window,
 8880                cx,
 8881            );
 8882        } else if target_display_point.row() >= visible_row_range.end {
 8883            return self.render_edit_prediction_scroll_popover(
 8884                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8885                IconName::ArrowDown,
 8886                visible_row_range,
 8887                line_layouts,
 8888                newest_selection_head,
 8889                scrolled_content_origin,
 8890                window,
 8891                cx,
 8892            );
 8893        }
 8894
 8895        const POLE_WIDTH: Pixels = px(2.);
 8896
 8897        let line_layout =
 8898            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8899        let target_column = target_display_point.column() as usize;
 8900
 8901        let target_x = line_layout.x_for_index(target_column);
 8902        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8903            - scroll_pixel_position.y;
 8904
 8905        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8906
 8907        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8908        border_color.l += 0.001;
 8909
 8910        let mut element = v_flex()
 8911            .items_end()
 8912            .when(flag_on_right, |el| el.items_start())
 8913            .child(if flag_on_right {
 8914                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8915                    .rounded_bl(px(0.))
 8916                    .rounded_tl(px(0.))
 8917                    .border_l_2()
 8918                    .border_color(border_color)
 8919            } else {
 8920                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8921                    .rounded_br(px(0.))
 8922                    .rounded_tr(px(0.))
 8923                    .border_r_2()
 8924                    .border_color(border_color)
 8925            })
 8926            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8927            .into_any();
 8928
 8929        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8930
 8931        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8932            - point(
 8933                if flag_on_right {
 8934                    POLE_WIDTH
 8935                } else {
 8936                    size.width - POLE_WIDTH
 8937                },
 8938                size.height - line_height,
 8939            );
 8940
 8941        origin.x = origin.x.max(content_origin.x);
 8942
 8943        element.prepaint_at(origin, window, cx);
 8944
 8945        Some((element, origin))
 8946    }
 8947
 8948    fn render_edit_prediction_scroll_popover(
 8949        &mut self,
 8950        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8951        scroll_icon: IconName,
 8952        visible_row_range: Range<DisplayRow>,
 8953        line_layouts: &[LineWithInvisibles],
 8954        newest_selection_head: Option<DisplayPoint>,
 8955        scrolled_content_origin: gpui::Point<Pixels>,
 8956        window: &mut Window,
 8957        cx: &mut App,
 8958    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8959        let mut element = self
 8960            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8961            .into_any();
 8962
 8963        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8964
 8965        let cursor = newest_selection_head?;
 8966        let cursor_row_layout =
 8967            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8968        let cursor_column = cursor.column() as usize;
 8969
 8970        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8971
 8972        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8973
 8974        element.prepaint_at(origin, window, cx);
 8975        Some((element, origin))
 8976    }
 8977
 8978    fn render_edit_prediction_eager_jump_popover(
 8979        &mut self,
 8980        text_bounds: &Bounds<Pixels>,
 8981        content_origin: gpui::Point<Pixels>,
 8982        editor_snapshot: &EditorSnapshot,
 8983        visible_row_range: Range<DisplayRow>,
 8984        scroll_top: ScrollOffset,
 8985        scroll_bottom: ScrollOffset,
 8986        line_height: Pixels,
 8987        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8988        target_display_point: DisplayPoint,
 8989        editor_width: Pixels,
 8990        window: &mut Window,
 8991        cx: &mut App,
 8992    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8993        if target_display_point.row().as_f64() < scroll_top {
 8994            let mut element = self
 8995                .render_edit_prediction_line_popover(
 8996                    "Jump to Edit",
 8997                    Some(IconName::ArrowUp),
 8998                    window,
 8999                    cx,
 9000                )
 9001                .into_any();
 9002
 9003            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9004            let offset = point(
 9005                (text_bounds.size.width - size.width) / 2.,
 9006                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9007            );
 9008
 9009            let origin = text_bounds.origin + offset;
 9010            element.prepaint_at(origin, window, cx);
 9011            Some((element, origin))
 9012        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9013            let mut element = self
 9014                .render_edit_prediction_line_popover(
 9015                    "Jump to Edit",
 9016                    Some(IconName::ArrowDown),
 9017                    window,
 9018                    cx,
 9019                )
 9020                .into_any();
 9021
 9022            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9023            let offset = point(
 9024                (text_bounds.size.width - size.width) / 2.,
 9025                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9026            );
 9027
 9028            let origin = text_bounds.origin + offset;
 9029            element.prepaint_at(origin, window, cx);
 9030            Some((element, origin))
 9031        } else {
 9032            self.render_edit_prediction_end_of_line_popover(
 9033                "Jump to Edit",
 9034                editor_snapshot,
 9035                visible_row_range,
 9036                target_display_point,
 9037                line_height,
 9038                scroll_pixel_position,
 9039                content_origin,
 9040                editor_width,
 9041                window,
 9042                cx,
 9043            )
 9044        }
 9045    }
 9046
 9047    fn render_edit_prediction_end_of_line_popover(
 9048        self: &mut Editor,
 9049        label: &'static str,
 9050        editor_snapshot: &EditorSnapshot,
 9051        visible_row_range: Range<DisplayRow>,
 9052        target_display_point: DisplayPoint,
 9053        line_height: Pixels,
 9054        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9055        content_origin: gpui::Point<Pixels>,
 9056        editor_width: Pixels,
 9057        window: &mut Window,
 9058        cx: &mut App,
 9059    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9060        let target_line_end = DisplayPoint::new(
 9061            target_display_point.row(),
 9062            editor_snapshot.line_len(target_display_point.row()),
 9063        );
 9064
 9065        let mut element = self
 9066            .render_edit_prediction_line_popover(label, None, window, cx)
 9067            .into_any();
 9068
 9069        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9070
 9071        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9072
 9073        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9074        let mut origin = start_point
 9075            + line_origin
 9076            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9077        origin.x = origin.x.max(content_origin.x);
 9078
 9079        let max_x = content_origin.x + editor_width - size.width;
 9080
 9081        if origin.x > max_x {
 9082            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9083
 9084            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9085                origin.y += offset;
 9086                IconName::ArrowUp
 9087            } else {
 9088                origin.y -= offset;
 9089                IconName::ArrowDown
 9090            };
 9091
 9092            element = self
 9093                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9094                .into_any();
 9095
 9096            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9097
 9098            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9099        }
 9100
 9101        element.prepaint_at(origin, window, cx);
 9102        Some((element, origin))
 9103    }
 9104
 9105    fn render_edit_prediction_diff_popover(
 9106        self: &Editor,
 9107        text_bounds: &Bounds<Pixels>,
 9108        content_origin: gpui::Point<Pixels>,
 9109        right_margin: Pixels,
 9110        editor_snapshot: &EditorSnapshot,
 9111        visible_row_range: Range<DisplayRow>,
 9112        line_layouts: &[LineWithInvisibles],
 9113        line_height: Pixels,
 9114        scroll_position: gpui::Point<ScrollOffset>,
 9115        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9116        newest_selection_head: Option<DisplayPoint>,
 9117        editor_width: Pixels,
 9118        style: &EditorStyle,
 9119        edits: &Vec<(Range<Anchor>, String)>,
 9120        edit_preview: &Option<language::EditPreview>,
 9121        snapshot: &language::BufferSnapshot,
 9122        window: &mut Window,
 9123        cx: &mut App,
 9124    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9125        let edit_start = edits
 9126            .first()
 9127            .unwrap()
 9128            .0
 9129            .start
 9130            .to_display_point(editor_snapshot);
 9131        let edit_end = edits
 9132            .last()
 9133            .unwrap()
 9134            .0
 9135            .end
 9136            .to_display_point(editor_snapshot);
 9137
 9138        let is_visible = visible_row_range.contains(&edit_start.row())
 9139            || visible_row_range.contains(&edit_end.row());
 9140        if !is_visible {
 9141            return None;
 9142        }
 9143
 9144        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9145            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9146        } else {
 9147            // Fallback for providers without edit_preview
 9148            crate::edit_prediction_fallback_text(edits, cx)
 9149        };
 9150
 9151        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9152        let line_count = highlighted_edits.text.lines().count();
 9153
 9154        const BORDER_WIDTH: Pixels = px(1.);
 9155
 9156        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9157        let has_keybind = keybind.is_some();
 9158
 9159        let mut element = h_flex()
 9160            .items_start()
 9161            .child(
 9162                h_flex()
 9163                    .bg(cx.theme().colors().editor_background)
 9164                    .border(BORDER_WIDTH)
 9165                    .shadow_xs()
 9166                    .border_color(cx.theme().colors().border)
 9167                    .rounded_l_lg()
 9168                    .when(line_count > 1, |el| el.rounded_br_lg())
 9169                    .pr_1()
 9170                    .child(styled_text),
 9171            )
 9172            .child(
 9173                h_flex()
 9174                    .h(line_height + BORDER_WIDTH * 2.)
 9175                    .px_1p5()
 9176                    .gap_1()
 9177                    // Workaround: For some reason, there's a gap if we don't do this
 9178                    .ml(-BORDER_WIDTH)
 9179                    .shadow(vec![gpui::BoxShadow {
 9180                        color: gpui::black().opacity(0.05),
 9181                        offset: point(px(1.), px(1.)),
 9182                        blur_radius: px(2.),
 9183                        spread_radius: px(0.),
 9184                    }])
 9185                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9186                    .border(BORDER_WIDTH)
 9187                    .border_color(cx.theme().colors().border)
 9188                    .rounded_r_lg()
 9189                    .id("edit_prediction_diff_popover_keybind")
 9190                    .when(!has_keybind, |el| {
 9191                        let status_colors = cx.theme().status();
 9192
 9193                        el.bg(status_colors.error_background)
 9194                            .border_color(status_colors.error.opacity(0.6))
 9195                            .child(Icon::new(IconName::Info).color(Color::Error))
 9196                            .cursor_default()
 9197                            .hoverable_tooltip(move |_window, cx| {
 9198                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9199                            })
 9200                    })
 9201                    .children(keybind),
 9202            )
 9203            .into_any();
 9204
 9205        let longest_row =
 9206            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9207        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9208            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9209        } else {
 9210            layout_line(
 9211                longest_row,
 9212                editor_snapshot,
 9213                style,
 9214                editor_width,
 9215                |_| false,
 9216                window,
 9217                cx,
 9218            )
 9219            .width
 9220        };
 9221
 9222        let viewport_bounds =
 9223            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9224                right: -right_margin,
 9225                ..Default::default()
 9226            });
 9227
 9228        let x_after_longest = Pixels::from(
 9229            ScrollPixelOffset::from(
 9230                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9231            ) - scroll_pixel_position.x,
 9232        );
 9233
 9234        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9235
 9236        // Fully visible if it can be displayed within the window (allow overlapping other
 9237        // panes). However, this is only allowed if the popover starts within text_bounds.
 9238        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9239            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9240
 9241        let mut origin = if can_position_to_the_right {
 9242            point(
 9243                x_after_longest,
 9244                text_bounds.origin.y
 9245                    + Pixels::from(
 9246                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9247                            - scroll_pixel_position.y,
 9248                    ),
 9249            )
 9250        } else {
 9251            let cursor_row = newest_selection_head.map(|head| head.row());
 9252            let above_edit = edit_start
 9253                .row()
 9254                .0
 9255                .checked_sub(line_count as u32)
 9256                .map(DisplayRow);
 9257            let below_edit = Some(edit_end.row() + 1);
 9258            let above_cursor =
 9259                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9260            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9261
 9262            // Place the edit popover adjacent to the edit if there is a location
 9263            // available that is onscreen and does not obscure the cursor. Otherwise,
 9264            // place it adjacent to the cursor.
 9265            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9266                .into_iter()
 9267                .flatten()
 9268                .find(|&start_row| {
 9269                    let end_row = start_row + line_count as u32;
 9270                    visible_row_range.contains(&start_row)
 9271                        && visible_row_range.contains(&end_row)
 9272                        && cursor_row
 9273                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9274                })?;
 9275
 9276            content_origin
 9277                + point(
 9278                    Pixels::from(-scroll_pixel_position.x),
 9279                    Pixels::from(
 9280                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9281                    ),
 9282                )
 9283        };
 9284
 9285        origin.x -= BORDER_WIDTH;
 9286
 9287        window.defer_draw(element, origin, 1);
 9288
 9289        // Do not return an element, since it will already be drawn due to defer_draw.
 9290        None
 9291    }
 9292
 9293    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9294        px(30.)
 9295    }
 9296
 9297    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9298        if self.read_only(cx) {
 9299            cx.theme().players().read_only()
 9300        } else {
 9301            self.style.as_ref().unwrap().local_player
 9302        }
 9303    }
 9304
 9305    fn render_edit_prediction_accept_keybind(
 9306        &self,
 9307        window: &mut Window,
 9308        cx: &mut App,
 9309    ) -> Option<AnyElement> {
 9310        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9311        let accept_keystroke = accept_binding.keystroke()?;
 9312
 9313        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9314
 9315        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9316            Color::Accent
 9317        } else {
 9318            Color::Muted
 9319        };
 9320
 9321        h_flex()
 9322            .px_0p5()
 9323            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9324            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9325            .text_size(TextSize::XSmall.rems(cx))
 9326            .child(h_flex().children(ui::render_modifiers(
 9327                accept_keystroke.modifiers(),
 9328                PlatformStyle::platform(),
 9329                Some(modifiers_color),
 9330                Some(IconSize::XSmall.rems().into()),
 9331                true,
 9332            )))
 9333            .when(is_platform_style_mac, |parent| {
 9334                parent.child(accept_keystroke.key().to_string())
 9335            })
 9336            .when(!is_platform_style_mac, |parent| {
 9337                parent.child(
 9338                    Key::new(
 9339                        util::capitalize(accept_keystroke.key()),
 9340                        Some(Color::Default),
 9341                    )
 9342                    .size(Some(IconSize::XSmall.rems().into())),
 9343                )
 9344            })
 9345            .into_any()
 9346            .into()
 9347    }
 9348
 9349    fn render_edit_prediction_line_popover(
 9350        &self,
 9351        label: impl Into<SharedString>,
 9352        icon: Option<IconName>,
 9353        window: &mut Window,
 9354        cx: &mut App,
 9355    ) -> Stateful<Div> {
 9356        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9357
 9358        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9359        let has_keybind = keybind.is_some();
 9360
 9361        h_flex()
 9362            .id("ep-line-popover")
 9363            .py_0p5()
 9364            .pl_1()
 9365            .pr(padding_right)
 9366            .gap_1()
 9367            .rounded_md()
 9368            .border_1()
 9369            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9370            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9371            .shadow_xs()
 9372            .when(!has_keybind, |el| {
 9373                let status_colors = cx.theme().status();
 9374
 9375                el.bg(status_colors.error_background)
 9376                    .border_color(status_colors.error.opacity(0.6))
 9377                    .pl_2()
 9378                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9379                    .cursor_default()
 9380                    .hoverable_tooltip(move |_window, cx| {
 9381                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9382                    })
 9383            })
 9384            .children(keybind)
 9385            .child(
 9386                Label::new(label)
 9387                    .size(LabelSize::Small)
 9388                    .when(!has_keybind, |el| {
 9389                        el.color(cx.theme().status().error.into()).strikethrough()
 9390                    }),
 9391            )
 9392            .when(!has_keybind, |el| {
 9393                el.child(
 9394                    h_flex().ml_1().child(
 9395                        Icon::new(IconName::Info)
 9396                            .size(IconSize::Small)
 9397                            .color(cx.theme().status().error.into()),
 9398                    ),
 9399                )
 9400            })
 9401            .when_some(icon, |element, icon| {
 9402                element.child(
 9403                    div()
 9404                        .mt(px(1.5))
 9405                        .child(Icon::new(icon).size(IconSize::Small)),
 9406                )
 9407            })
 9408    }
 9409
 9410    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9411        let accent_color = cx.theme().colors().text_accent;
 9412        let editor_bg_color = cx.theme().colors().editor_background;
 9413        editor_bg_color.blend(accent_color.opacity(0.1))
 9414    }
 9415
 9416    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9417        let accent_color = cx.theme().colors().text_accent;
 9418        let editor_bg_color = cx.theme().colors().editor_background;
 9419        editor_bg_color.blend(accent_color.opacity(0.6))
 9420    }
 9421    fn get_prediction_provider_icon_name(
 9422        provider: &Option<RegisteredEditPredictionProvider>,
 9423    ) -> IconName {
 9424        match provider {
 9425            Some(provider) => match provider.provider.name() {
 9426                "copilot" => IconName::Copilot,
 9427                "supermaven" => IconName::Supermaven,
 9428                _ => IconName::ZedPredict,
 9429            },
 9430            None => IconName::ZedPredict,
 9431        }
 9432    }
 9433
 9434    fn render_edit_prediction_cursor_popover(
 9435        &self,
 9436        min_width: Pixels,
 9437        max_width: Pixels,
 9438        cursor_point: Point,
 9439        style: &EditorStyle,
 9440        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9441        _window: &Window,
 9442        cx: &mut Context<Editor>,
 9443    ) -> Option<AnyElement> {
 9444        let provider = self.edit_prediction_provider.as_ref()?;
 9445        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9446
 9447        let is_refreshing = provider.provider.is_refreshing(cx);
 9448
 9449        fn pending_completion_container(icon: IconName) -> Div {
 9450            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9451        }
 9452
 9453        let completion = match &self.active_edit_prediction {
 9454            Some(prediction) => {
 9455                if !self.has_visible_completions_menu() {
 9456                    const RADIUS: Pixels = px(6.);
 9457                    const BORDER_WIDTH: Pixels = px(1.);
 9458
 9459                    return Some(
 9460                        h_flex()
 9461                            .elevation_2(cx)
 9462                            .border(BORDER_WIDTH)
 9463                            .border_color(cx.theme().colors().border)
 9464                            .when(accept_keystroke.is_none(), |el| {
 9465                                el.border_color(cx.theme().status().error)
 9466                            })
 9467                            .rounded(RADIUS)
 9468                            .rounded_tl(px(0.))
 9469                            .overflow_hidden()
 9470                            .child(div().px_1p5().child(match &prediction.completion {
 9471                                EditPrediction::MoveWithin { target, snapshot } => {
 9472                                    use text::ToPoint as _;
 9473                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9474                                    {
 9475                                        Icon::new(IconName::ZedPredictDown)
 9476                                    } else {
 9477                                        Icon::new(IconName::ZedPredictUp)
 9478                                    }
 9479                                }
 9480                                EditPrediction::MoveOutside { .. } => {
 9481                                    // TODO [zeta2] custom icon for external jump?
 9482                                    Icon::new(provider_icon)
 9483                                }
 9484                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9485                            }))
 9486                            .child(
 9487                                h_flex()
 9488                                    .gap_1()
 9489                                    .py_1()
 9490                                    .px_2()
 9491                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9492                                    .border_l_1()
 9493                                    .border_color(cx.theme().colors().border)
 9494                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9495                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9496                                        el.child(
 9497                                            Label::new("Hold")
 9498                                                .size(LabelSize::Small)
 9499                                                .when(accept_keystroke.is_none(), |el| {
 9500                                                    el.strikethrough()
 9501                                                })
 9502                                                .line_height_style(LineHeightStyle::UiLabel),
 9503                                        )
 9504                                    })
 9505                                    .id("edit_prediction_cursor_popover_keybind")
 9506                                    .when(accept_keystroke.is_none(), |el| {
 9507                                        let status_colors = cx.theme().status();
 9508
 9509                                        el.bg(status_colors.error_background)
 9510                                            .border_color(status_colors.error.opacity(0.6))
 9511                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9512                                            .cursor_default()
 9513                                            .hoverable_tooltip(move |_window, cx| {
 9514                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9515                                                    .into()
 9516                                            })
 9517                                    })
 9518                                    .when_some(
 9519                                        accept_keystroke.as_ref(),
 9520                                        |el, accept_keystroke| {
 9521                                            el.child(h_flex().children(ui::render_modifiers(
 9522                                                accept_keystroke.modifiers(),
 9523                                                PlatformStyle::platform(),
 9524                                                Some(Color::Default),
 9525                                                Some(IconSize::XSmall.rems().into()),
 9526                                                false,
 9527                                            )))
 9528                                        },
 9529                                    ),
 9530                            )
 9531                            .into_any(),
 9532                    );
 9533                }
 9534
 9535                self.render_edit_prediction_cursor_popover_preview(
 9536                    prediction,
 9537                    cursor_point,
 9538                    style,
 9539                    cx,
 9540                )?
 9541            }
 9542
 9543            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9544                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9545                    stale_completion,
 9546                    cursor_point,
 9547                    style,
 9548                    cx,
 9549                )?,
 9550
 9551                None => pending_completion_container(provider_icon)
 9552                    .child(Label::new("...").size(LabelSize::Small)),
 9553            },
 9554
 9555            None => pending_completion_container(provider_icon)
 9556                .child(Label::new("...").size(LabelSize::Small)),
 9557        };
 9558
 9559        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9560            completion
 9561                .with_animation(
 9562                    "loading-completion",
 9563                    Animation::new(Duration::from_secs(2))
 9564                        .repeat()
 9565                        .with_easing(pulsating_between(0.4, 0.8)),
 9566                    |label, delta| label.opacity(delta),
 9567                )
 9568                .into_any_element()
 9569        } else {
 9570            completion.into_any_element()
 9571        };
 9572
 9573        let has_completion = self.active_edit_prediction.is_some();
 9574
 9575        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9576        Some(
 9577            h_flex()
 9578                .min_w(min_width)
 9579                .max_w(max_width)
 9580                .flex_1()
 9581                .elevation_2(cx)
 9582                .border_color(cx.theme().colors().border)
 9583                .child(
 9584                    div()
 9585                        .flex_1()
 9586                        .py_1()
 9587                        .px_2()
 9588                        .overflow_hidden()
 9589                        .child(completion),
 9590                )
 9591                .when_some(accept_keystroke, |el, accept_keystroke| {
 9592                    if !accept_keystroke.modifiers().modified() {
 9593                        return el;
 9594                    }
 9595
 9596                    el.child(
 9597                        h_flex()
 9598                            .h_full()
 9599                            .border_l_1()
 9600                            .rounded_r_lg()
 9601                            .border_color(cx.theme().colors().border)
 9602                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9603                            .gap_1()
 9604                            .py_1()
 9605                            .px_2()
 9606                            .child(
 9607                                h_flex()
 9608                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9609                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9610                                    .child(h_flex().children(ui::render_modifiers(
 9611                                        accept_keystroke.modifiers(),
 9612                                        PlatformStyle::platform(),
 9613                                        Some(if !has_completion {
 9614                                            Color::Muted
 9615                                        } else {
 9616                                            Color::Default
 9617                                        }),
 9618                                        None,
 9619                                        false,
 9620                                    ))),
 9621                            )
 9622                            .child(Label::new("Preview").into_any_element())
 9623                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9624                    )
 9625                })
 9626                .into_any(),
 9627        )
 9628    }
 9629
 9630    fn render_edit_prediction_cursor_popover_preview(
 9631        &self,
 9632        completion: &EditPredictionState,
 9633        cursor_point: Point,
 9634        style: &EditorStyle,
 9635        cx: &mut Context<Editor>,
 9636    ) -> Option<Div> {
 9637        use text::ToPoint as _;
 9638
 9639        fn render_relative_row_jump(
 9640            prefix: impl Into<String>,
 9641            current_row: u32,
 9642            target_row: u32,
 9643        ) -> Div {
 9644            let (row_diff, arrow) = if target_row < current_row {
 9645                (current_row - target_row, IconName::ArrowUp)
 9646            } else {
 9647                (target_row - current_row, IconName::ArrowDown)
 9648            };
 9649
 9650            h_flex()
 9651                .child(
 9652                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9653                        .color(Color::Muted)
 9654                        .size(LabelSize::Small),
 9655                )
 9656                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9657        }
 9658
 9659        let supports_jump = self
 9660            .edit_prediction_provider
 9661            .as_ref()
 9662            .map(|provider| provider.provider.supports_jump_to_edit())
 9663            .unwrap_or(true);
 9664
 9665        match &completion.completion {
 9666            EditPrediction::MoveWithin {
 9667                target, snapshot, ..
 9668            } => {
 9669                if !supports_jump {
 9670                    return None;
 9671                }
 9672
 9673                Some(
 9674                    h_flex()
 9675                        .px_2()
 9676                        .gap_2()
 9677                        .flex_1()
 9678                        .child(
 9679                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9680                                Icon::new(IconName::ZedPredictDown)
 9681                            } else {
 9682                                Icon::new(IconName::ZedPredictUp)
 9683                            },
 9684                        )
 9685                        .child(Label::new("Jump to Edit")),
 9686                )
 9687            }
 9688            EditPrediction::MoveOutside { snapshot, .. } => {
 9689                let file_name = snapshot
 9690                    .file()
 9691                    .map(|file| file.file_name(cx))
 9692                    .unwrap_or("untitled");
 9693                Some(
 9694                    h_flex()
 9695                        .px_2()
 9696                        .gap_2()
 9697                        .flex_1()
 9698                        .child(Icon::new(IconName::ZedPredict))
 9699                        .child(Label::new(format!("Jump to {file_name}"))),
 9700                )
 9701            }
 9702            EditPrediction::Edit {
 9703                edits,
 9704                edit_preview,
 9705                snapshot,
 9706                display_mode: _,
 9707            } => {
 9708                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9709
 9710                let (highlighted_edits, has_more_lines) =
 9711                    if let Some(edit_preview) = edit_preview.as_ref() {
 9712                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9713                            .first_line_preview()
 9714                    } else {
 9715                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9716                    };
 9717
 9718                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9719                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9720
 9721                let preview = h_flex()
 9722                    .gap_1()
 9723                    .min_w_16()
 9724                    .child(styled_text)
 9725                    .when(has_more_lines, |parent| parent.child(""));
 9726
 9727                let left = if supports_jump && first_edit_row != cursor_point.row {
 9728                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9729                        .into_any_element()
 9730                } else {
 9731                    let icon_name =
 9732                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9733                    Icon::new(icon_name).into_any_element()
 9734                };
 9735
 9736                Some(
 9737                    h_flex()
 9738                        .h_full()
 9739                        .flex_1()
 9740                        .gap_2()
 9741                        .pr_1()
 9742                        .overflow_x_hidden()
 9743                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9744                        .child(left)
 9745                        .child(preview),
 9746                )
 9747            }
 9748        }
 9749    }
 9750
 9751    pub fn render_context_menu(
 9752        &self,
 9753        style: &EditorStyle,
 9754        max_height_in_lines: u32,
 9755        window: &mut Window,
 9756        cx: &mut Context<Editor>,
 9757    ) -> Option<AnyElement> {
 9758        let menu = self.context_menu.borrow();
 9759        let menu = menu.as_ref()?;
 9760        if !menu.visible() {
 9761            return None;
 9762        };
 9763        Some(menu.render(style, max_height_in_lines, window, cx))
 9764    }
 9765
 9766    fn render_context_menu_aside(
 9767        &mut self,
 9768        max_size: Size<Pixels>,
 9769        window: &mut Window,
 9770        cx: &mut Context<Editor>,
 9771    ) -> Option<AnyElement> {
 9772        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9773            if menu.visible() {
 9774                menu.render_aside(max_size, window, cx)
 9775            } else {
 9776                None
 9777            }
 9778        })
 9779    }
 9780
 9781    fn hide_context_menu(
 9782        &mut self,
 9783        window: &mut Window,
 9784        cx: &mut Context<Self>,
 9785    ) -> Option<CodeContextMenu> {
 9786        cx.notify();
 9787        self.completion_tasks.clear();
 9788        let context_menu = self.context_menu.borrow_mut().take();
 9789        self.stale_edit_prediction_in_menu.take();
 9790        self.update_visible_edit_prediction(window, cx);
 9791        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9792            && let Some(completion_provider) = &self.completion_provider
 9793        {
 9794            completion_provider.selection_changed(None, window, cx);
 9795        }
 9796        context_menu
 9797    }
 9798
 9799    fn show_snippet_choices(
 9800        &mut self,
 9801        choices: &Vec<String>,
 9802        selection: Range<Anchor>,
 9803        cx: &mut Context<Self>,
 9804    ) {
 9805        let Some((_, buffer, _)) = self
 9806            .buffer()
 9807            .read(cx)
 9808            .excerpt_containing(selection.start, cx)
 9809        else {
 9810            return;
 9811        };
 9812        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9813        else {
 9814            return;
 9815        };
 9816        if buffer != end_buffer {
 9817            log::error!("expected anchor range to have matching buffer IDs");
 9818            return;
 9819        }
 9820
 9821        let id = post_inc(&mut self.next_completion_id);
 9822        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9823        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9824            CompletionsMenu::new_snippet_choices(
 9825                id,
 9826                true,
 9827                choices,
 9828                selection,
 9829                buffer,
 9830                snippet_sort_order,
 9831            ),
 9832        ));
 9833    }
 9834
 9835    pub fn insert_snippet(
 9836        &mut self,
 9837        insertion_ranges: &[Range<usize>],
 9838        snippet: Snippet,
 9839        window: &mut Window,
 9840        cx: &mut Context<Self>,
 9841    ) -> Result<()> {
 9842        struct Tabstop<T> {
 9843            is_end_tabstop: bool,
 9844            ranges: Vec<Range<T>>,
 9845            choices: Option<Vec<String>>,
 9846        }
 9847
 9848        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9849            let snippet_text: Arc<str> = snippet.text.clone().into();
 9850            let edits = insertion_ranges
 9851                .iter()
 9852                .cloned()
 9853                .map(|range| (range, snippet_text.clone()));
 9854            let autoindent_mode = AutoindentMode::Block {
 9855                original_indent_columns: Vec::new(),
 9856            };
 9857            buffer.edit(edits, Some(autoindent_mode), cx);
 9858
 9859            let snapshot = &*buffer.read(cx);
 9860            let snippet = &snippet;
 9861            snippet
 9862                .tabstops
 9863                .iter()
 9864                .map(|tabstop| {
 9865                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9866                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9867                    });
 9868                    let mut tabstop_ranges = tabstop
 9869                        .ranges
 9870                        .iter()
 9871                        .flat_map(|tabstop_range| {
 9872                            let mut delta = 0_isize;
 9873                            insertion_ranges.iter().map(move |insertion_range| {
 9874                                let insertion_start = insertion_range.start as isize + delta;
 9875                                delta +=
 9876                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9877
 9878                                let start = ((insertion_start + tabstop_range.start) as usize)
 9879                                    .min(snapshot.len());
 9880                                let end = ((insertion_start + tabstop_range.end) as usize)
 9881                                    .min(snapshot.len());
 9882                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9883                            })
 9884                        })
 9885                        .collect::<Vec<_>>();
 9886                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9887
 9888                    Tabstop {
 9889                        is_end_tabstop,
 9890                        ranges: tabstop_ranges,
 9891                        choices: tabstop.choices.clone(),
 9892                    }
 9893                })
 9894                .collect::<Vec<_>>()
 9895        });
 9896        if let Some(tabstop) = tabstops.first() {
 9897            self.change_selections(Default::default(), window, cx, |s| {
 9898                // Reverse order so that the first range is the newest created selection.
 9899                // Completions will use it and autoscroll will prioritize it.
 9900                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9901            });
 9902
 9903            if let Some(choices) = &tabstop.choices
 9904                && let Some(selection) = tabstop.ranges.first()
 9905            {
 9906                self.show_snippet_choices(choices, selection.clone(), cx)
 9907            }
 9908
 9909            // If we're already at the last tabstop and it's at the end of the snippet,
 9910            // we're done, we don't need to keep the state around.
 9911            if !tabstop.is_end_tabstop {
 9912                let choices = tabstops
 9913                    .iter()
 9914                    .map(|tabstop| tabstop.choices.clone())
 9915                    .collect();
 9916
 9917                let ranges = tabstops
 9918                    .into_iter()
 9919                    .map(|tabstop| tabstop.ranges)
 9920                    .collect::<Vec<_>>();
 9921
 9922                self.snippet_stack.push(SnippetState {
 9923                    active_index: 0,
 9924                    ranges,
 9925                    choices,
 9926                });
 9927            }
 9928
 9929            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9930            if self.autoclose_regions.is_empty() {
 9931                let snapshot = self.buffer.read(cx).snapshot(cx);
 9932                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9933                    let selection_head = selection.head();
 9934                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9935                        continue;
 9936                    };
 9937
 9938                    let mut bracket_pair = None;
 9939                    let max_lookup_length = scope
 9940                        .brackets()
 9941                        .map(|(pair, _)| {
 9942                            pair.start
 9943                                .as_str()
 9944                                .chars()
 9945                                .count()
 9946                                .max(pair.end.as_str().chars().count())
 9947                        })
 9948                        .max();
 9949                    if let Some(max_lookup_length) = max_lookup_length {
 9950                        let next_text = snapshot
 9951                            .chars_at(selection_head)
 9952                            .take(max_lookup_length)
 9953                            .collect::<String>();
 9954                        let prev_text = snapshot
 9955                            .reversed_chars_at(selection_head)
 9956                            .take(max_lookup_length)
 9957                            .collect::<String>();
 9958
 9959                        for (pair, enabled) in scope.brackets() {
 9960                            if enabled
 9961                                && pair.close
 9962                                && prev_text.starts_with(pair.start.as_str())
 9963                                && next_text.starts_with(pair.end.as_str())
 9964                            {
 9965                                bracket_pair = Some(pair.clone());
 9966                                break;
 9967                            }
 9968                        }
 9969                    }
 9970
 9971                    if let Some(pair) = bracket_pair {
 9972                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9973                        let autoclose_enabled =
 9974                            self.use_autoclose && snapshot_settings.use_autoclose;
 9975                        if autoclose_enabled {
 9976                            let start = snapshot.anchor_after(selection_head);
 9977                            let end = snapshot.anchor_after(selection_head);
 9978                            self.autoclose_regions.push(AutocloseRegion {
 9979                                selection_id: selection.id,
 9980                                range: start..end,
 9981                                pair,
 9982                            });
 9983                        }
 9984                    }
 9985                }
 9986            }
 9987        }
 9988        Ok(())
 9989    }
 9990
 9991    pub fn move_to_next_snippet_tabstop(
 9992        &mut self,
 9993        window: &mut Window,
 9994        cx: &mut Context<Self>,
 9995    ) -> bool {
 9996        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9997    }
 9998
 9999    pub fn move_to_prev_snippet_tabstop(
10000        &mut self,
10001        window: &mut Window,
10002        cx: &mut Context<Self>,
10003    ) -> bool {
10004        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10005    }
10006
10007    pub fn move_to_snippet_tabstop(
10008        &mut self,
10009        bias: Bias,
10010        window: &mut Window,
10011        cx: &mut Context<Self>,
10012    ) -> bool {
10013        if let Some(mut snippet) = self.snippet_stack.pop() {
10014            match bias {
10015                Bias::Left => {
10016                    if snippet.active_index > 0 {
10017                        snippet.active_index -= 1;
10018                    } else {
10019                        self.snippet_stack.push(snippet);
10020                        return false;
10021                    }
10022                }
10023                Bias::Right => {
10024                    if snippet.active_index + 1 < snippet.ranges.len() {
10025                        snippet.active_index += 1;
10026                    } else {
10027                        self.snippet_stack.push(snippet);
10028                        return false;
10029                    }
10030                }
10031            }
10032            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10033                self.change_selections(Default::default(), window, cx, |s| {
10034                    // Reverse order so that the first range is the newest created selection.
10035                    // Completions will use it and autoscroll will prioritize it.
10036                    s.select_ranges(current_ranges.iter().rev().cloned())
10037                });
10038
10039                if let Some(choices) = &snippet.choices[snippet.active_index]
10040                    && let Some(selection) = current_ranges.first()
10041                {
10042                    self.show_snippet_choices(choices, selection.clone(), cx);
10043                }
10044
10045                // If snippet state is not at the last tabstop, push it back on the stack
10046                if snippet.active_index + 1 < snippet.ranges.len() {
10047                    self.snippet_stack.push(snippet);
10048                }
10049                return true;
10050            }
10051        }
10052
10053        false
10054    }
10055
10056    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10057        self.transact(window, cx, |this, window, cx| {
10058            this.select_all(&SelectAll, window, cx);
10059            this.insert("", window, cx);
10060        });
10061    }
10062
10063    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10064        if self.read_only(cx) {
10065            return;
10066        }
10067        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10068        self.transact(window, cx, |this, window, cx| {
10069            this.select_autoclose_pair(window, cx);
10070
10071            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10072
10073            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10074            if !this.linked_edit_ranges.is_empty() {
10075                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10076                let snapshot = this.buffer.read(cx).snapshot(cx);
10077
10078                for selection in selections.iter() {
10079                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10080                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10081                    if selection_start.buffer_id != selection_end.buffer_id {
10082                        continue;
10083                    }
10084                    if let Some(ranges) =
10085                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10086                    {
10087                        for (buffer, entries) in ranges {
10088                            linked_ranges.entry(buffer).or_default().extend(entries);
10089                        }
10090                    }
10091                }
10092            }
10093
10094            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10095            for selection in &mut selections {
10096                if selection.is_empty() {
10097                    let old_head = selection.head();
10098                    let mut new_head =
10099                        movement::left(&display_map, old_head.to_display_point(&display_map))
10100                            .to_point(&display_map);
10101                    if let Some((buffer, line_buffer_range)) = display_map
10102                        .buffer_snapshot()
10103                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10104                    {
10105                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10106                        let indent_len = match indent_size.kind {
10107                            IndentKind::Space => {
10108                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10109                            }
10110                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10111                        };
10112                        if old_head.column <= indent_size.len && old_head.column > 0 {
10113                            let indent_len = indent_len.get();
10114                            new_head = cmp::min(
10115                                new_head,
10116                                MultiBufferPoint::new(
10117                                    old_head.row,
10118                                    ((old_head.column - 1) / indent_len) * indent_len,
10119                                ),
10120                            );
10121                        }
10122                    }
10123
10124                    selection.set_head(new_head, SelectionGoal::None);
10125                }
10126            }
10127
10128            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10129            this.insert("", window, cx);
10130            let empty_str: Arc<str> = Arc::from("");
10131            for (buffer, edits) in linked_ranges {
10132                let snapshot = buffer.read(cx).snapshot();
10133                use text::ToPoint as TP;
10134
10135                let edits = edits
10136                    .into_iter()
10137                    .map(|range| {
10138                        let end_point = TP::to_point(&range.end, &snapshot);
10139                        let mut start_point = TP::to_point(&range.start, &snapshot);
10140
10141                        if end_point == start_point {
10142                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10143                                .saturating_sub(1);
10144                            start_point =
10145                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10146                        };
10147
10148                        (start_point..end_point, empty_str.clone())
10149                    })
10150                    .sorted_by_key(|(range, _)| range.start)
10151                    .collect::<Vec<_>>();
10152                buffer.update(cx, |this, cx| {
10153                    this.edit(edits, None, cx);
10154                })
10155            }
10156            this.refresh_edit_prediction(true, false, window, cx);
10157            refresh_linked_ranges(this, window, cx);
10158        });
10159    }
10160
10161    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10162        if self.read_only(cx) {
10163            return;
10164        }
10165        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10166        self.transact(window, cx, |this, window, cx| {
10167            this.change_selections(Default::default(), window, cx, |s| {
10168                s.move_with(|map, selection| {
10169                    if selection.is_empty() {
10170                        let cursor = movement::right(map, selection.head());
10171                        selection.end = cursor;
10172                        selection.reversed = true;
10173                        selection.goal = SelectionGoal::None;
10174                    }
10175                })
10176            });
10177            this.insert("", window, cx);
10178            this.refresh_edit_prediction(true, false, window, cx);
10179        });
10180    }
10181
10182    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10183        if self.mode.is_single_line() {
10184            cx.propagate();
10185            return;
10186        }
10187
10188        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10189        if self.move_to_prev_snippet_tabstop(window, cx) {
10190            return;
10191        }
10192        self.outdent(&Outdent, window, cx);
10193    }
10194
10195    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10196        if self.mode.is_single_line() {
10197            cx.propagate();
10198            return;
10199        }
10200
10201        if self.move_to_next_snippet_tabstop(window, cx) {
10202            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10203            return;
10204        }
10205        if self.read_only(cx) {
10206            return;
10207        }
10208        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10209        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10210        let buffer = self.buffer.read(cx);
10211        let snapshot = buffer.snapshot(cx);
10212        let rows_iter = selections.iter().map(|s| s.head().row);
10213        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10214
10215        let has_some_cursor_in_whitespace = selections
10216            .iter()
10217            .filter(|selection| selection.is_empty())
10218            .any(|selection| {
10219                let cursor = selection.head();
10220                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10221                cursor.column < current_indent.len
10222            });
10223
10224        let mut edits = Vec::new();
10225        let mut prev_edited_row = 0;
10226        let mut row_delta = 0;
10227        for selection in &mut selections {
10228            if selection.start.row != prev_edited_row {
10229                row_delta = 0;
10230            }
10231            prev_edited_row = selection.end.row;
10232
10233            // If the selection is non-empty, then increase the indentation of the selected lines.
10234            if !selection.is_empty() {
10235                row_delta =
10236                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10237                continue;
10238            }
10239
10240            let cursor = selection.head();
10241            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10242            if let Some(suggested_indent) =
10243                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10244            {
10245                // Don't do anything if already at suggested indent
10246                // and there is any other cursor which is not
10247                if has_some_cursor_in_whitespace
10248                    && cursor.column == current_indent.len
10249                    && current_indent.len == suggested_indent.len
10250                {
10251                    continue;
10252                }
10253
10254                // Adjust line and move cursor to suggested indent
10255                // if cursor is not at suggested indent
10256                if cursor.column < suggested_indent.len
10257                    && cursor.column <= current_indent.len
10258                    && current_indent.len <= suggested_indent.len
10259                {
10260                    selection.start = Point::new(cursor.row, suggested_indent.len);
10261                    selection.end = selection.start;
10262                    if row_delta == 0 {
10263                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10264                            cursor.row,
10265                            current_indent,
10266                            suggested_indent,
10267                        ));
10268                        row_delta = suggested_indent.len - current_indent.len;
10269                    }
10270                    continue;
10271                }
10272
10273                // If current indent is more than suggested indent
10274                // only move cursor to current indent and skip indent
10275                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10276                    selection.start = Point::new(cursor.row, current_indent.len);
10277                    selection.end = selection.start;
10278                    continue;
10279                }
10280            }
10281
10282            // Otherwise, insert a hard or soft tab.
10283            let settings = buffer.language_settings_at(cursor, cx);
10284            let tab_size = if settings.hard_tabs {
10285                IndentSize::tab()
10286            } else {
10287                let tab_size = settings.tab_size.get();
10288                let indent_remainder = snapshot
10289                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10290                    .flat_map(str::chars)
10291                    .fold(row_delta % tab_size, |counter: u32, c| {
10292                        if c == '\t' {
10293                            0
10294                        } else {
10295                            (counter + 1) % tab_size
10296                        }
10297                    });
10298
10299                let chars_to_next_tab_stop = tab_size - indent_remainder;
10300                IndentSize::spaces(chars_to_next_tab_stop)
10301            };
10302            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10303            selection.end = selection.start;
10304            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10305            row_delta += tab_size.len;
10306        }
10307
10308        self.transact(window, cx, |this, window, cx| {
10309            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10310            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10311            this.refresh_edit_prediction(true, false, window, cx);
10312        });
10313    }
10314
10315    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10316        if self.read_only(cx) {
10317            return;
10318        }
10319        if self.mode.is_single_line() {
10320            cx.propagate();
10321            return;
10322        }
10323
10324        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10325        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10326        let mut prev_edited_row = 0;
10327        let mut row_delta = 0;
10328        let mut edits = Vec::new();
10329        let buffer = self.buffer.read(cx);
10330        let snapshot = buffer.snapshot(cx);
10331        for selection in &mut selections {
10332            if selection.start.row != prev_edited_row {
10333                row_delta = 0;
10334            }
10335            prev_edited_row = selection.end.row;
10336
10337            row_delta =
10338                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10339        }
10340
10341        self.transact(window, cx, |this, window, cx| {
10342            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10343            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10344        });
10345    }
10346
10347    fn indent_selection(
10348        buffer: &MultiBuffer,
10349        snapshot: &MultiBufferSnapshot,
10350        selection: &mut Selection<Point>,
10351        edits: &mut Vec<(Range<Point>, String)>,
10352        delta_for_start_row: u32,
10353        cx: &App,
10354    ) -> u32 {
10355        let settings = buffer.language_settings_at(selection.start, cx);
10356        let tab_size = settings.tab_size.get();
10357        let indent_kind = if settings.hard_tabs {
10358            IndentKind::Tab
10359        } else {
10360            IndentKind::Space
10361        };
10362        let mut start_row = selection.start.row;
10363        let mut end_row = selection.end.row + 1;
10364
10365        // If a selection ends at the beginning of a line, don't indent
10366        // that last line.
10367        if selection.end.column == 0 && selection.end.row > selection.start.row {
10368            end_row -= 1;
10369        }
10370
10371        // Avoid re-indenting a row that has already been indented by a
10372        // previous selection, but still update this selection's column
10373        // to reflect that indentation.
10374        if delta_for_start_row > 0 {
10375            start_row += 1;
10376            selection.start.column += delta_for_start_row;
10377            if selection.end.row == selection.start.row {
10378                selection.end.column += delta_for_start_row;
10379            }
10380        }
10381
10382        let mut delta_for_end_row = 0;
10383        let has_multiple_rows = start_row + 1 != end_row;
10384        for row in start_row..end_row {
10385            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10386            let indent_delta = match (current_indent.kind, indent_kind) {
10387                (IndentKind::Space, IndentKind::Space) => {
10388                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10389                    IndentSize::spaces(columns_to_next_tab_stop)
10390                }
10391                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10392                (_, IndentKind::Tab) => IndentSize::tab(),
10393            };
10394
10395            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10396                0
10397            } else {
10398                selection.start.column
10399            };
10400            let row_start = Point::new(row, start);
10401            edits.push((
10402                row_start..row_start,
10403                indent_delta.chars().collect::<String>(),
10404            ));
10405
10406            // Update this selection's endpoints to reflect the indentation.
10407            if row == selection.start.row {
10408                selection.start.column += indent_delta.len;
10409            }
10410            if row == selection.end.row {
10411                selection.end.column += indent_delta.len;
10412                delta_for_end_row = indent_delta.len;
10413            }
10414        }
10415
10416        if selection.start.row == selection.end.row {
10417            delta_for_start_row + delta_for_end_row
10418        } else {
10419            delta_for_end_row
10420        }
10421    }
10422
10423    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10424        if self.read_only(cx) {
10425            return;
10426        }
10427        if self.mode.is_single_line() {
10428            cx.propagate();
10429            return;
10430        }
10431
10432        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10433        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10434        let selections = self.selections.all::<Point>(&display_map);
10435        let mut deletion_ranges = Vec::new();
10436        let mut last_outdent = None;
10437        {
10438            let buffer = self.buffer.read(cx);
10439            let snapshot = buffer.snapshot(cx);
10440            for selection in &selections {
10441                let settings = buffer.language_settings_at(selection.start, cx);
10442                let tab_size = settings.tab_size.get();
10443                let mut rows = selection.spanned_rows(false, &display_map);
10444
10445                // Avoid re-outdenting a row that has already been outdented by a
10446                // previous selection.
10447                if let Some(last_row) = last_outdent
10448                    && last_row == rows.start
10449                {
10450                    rows.start = rows.start.next_row();
10451                }
10452                let has_multiple_rows = rows.len() > 1;
10453                for row in rows.iter_rows() {
10454                    let indent_size = snapshot.indent_size_for_line(row);
10455                    if indent_size.len > 0 {
10456                        let deletion_len = match indent_size.kind {
10457                            IndentKind::Space => {
10458                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10459                                if columns_to_prev_tab_stop == 0 {
10460                                    tab_size
10461                                } else {
10462                                    columns_to_prev_tab_stop
10463                                }
10464                            }
10465                            IndentKind::Tab => 1,
10466                        };
10467                        let start = if has_multiple_rows
10468                            || deletion_len > selection.start.column
10469                            || indent_size.len < selection.start.column
10470                        {
10471                            0
10472                        } else {
10473                            selection.start.column - deletion_len
10474                        };
10475                        deletion_ranges.push(
10476                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10477                        );
10478                        last_outdent = Some(row);
10479                    }
10480                }
10481            }
10482        }
10483
10484        self.transact(window, cx, |this, window, cx| {
10485            this.buffer.update(cx, |buffer, cx| {
10486                let empty_str: Arc<str> = Arc::default();
10487                buffer.edit(
10488                    deletion_ranges
10489                        .into_iter()
10490                        .map(|range| (range, empty_str.clone())),
10491                    None,
10492                    cx,
10493                );
10494            });
10495            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10496            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10497        });
10498    }
10499
10500    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10501        if self.read_only(cx) {
10502            return;
10503        }
10504        if self.mode.is_single_line() {
10505            cx.propagate();
10506            return;
10507        }
10508
10509        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10510        let selections = self
10511            .selections
10512            .all::<usize>(&self.display_snapshot(cx))
10513            .into_iter()
10514            .map(|s| s.range());
10515
10516        self.transact(window, cx, |this, window, cx| {
10517            this.buffer.update(cx, |buffer, cx| {
10518                buffer.autoindent_ranges(selections, cx);
10519            });
10520            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10521            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10522        });
10523    }
10524
10525    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10526        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10527        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10528        let selections = self.selections.all::<Point>(&display_map);
10529
10530        let mut new_cursors = Vec::new();
10531        let mut edit_ranges = Vec::new();
10532        let mut selections = selections.iter().peekable();
10533        while let Some(selection) = selections.next() {
10534            let mut rows = selection.spanned_rows(false, &display_map);
10535
10536            // Accumulate contiguous regions of rows that we want to delete.
10537            while let Some(next_selection) = selections.peek() {
10538                let next_rows = next_selection.spanned_rows(false, &display_map);
10539                if next_rows.start <= rows.end {
10540                    rows.end = next_rows.end;
10541                    selections.next().unwrap();
10542                } else {
10543                    break;
10544                }
10545            }
10546
10547            let buffer = display_map.buffer_snapshot();
10548            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10549            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10550                // If there's a line after the range, delete the \n from the end of the row range
10551                (
10552                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10553                    rows.end,
10554                )
10555            } else {
10556                // If there isn't a line after the range, delete the \n from the line before the
10557                // start of the row range
10558                edit_start = edit_start.saturating_sub(1);
10559                (buffer.len(), rows.start.previous_row())
10560            };
10561
10562            let text_layout_details = self.text_layout_details(window);
10563            let x = display_map.x_for_display_point(
10564                selection.head().to_display_point(&display_map),
10565                &text_layout_details,
10566            );
10567            let row = Point::new(target_row.0, 0)
10568                .to_display_point(&display_map)
10569                .row();
10570            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10571
10572            new_cursors.push((
10573                selection.id,
10574                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10575                SelectionGoal::None,
10576            ));
10577            edit_ranges.push(edit_start..edit_end);
10578        }
10579
10580        self.transact(window, cx, |this, window, cx| {
10581            let buffer = this.buffer.update(cx, |buffer, cx| {
10582                let empty_str: Arc<str> = Arc::default();
10583                buffer.edit(
10584                    edit_ranges
10585                        .into_iter()
10586                        .map(|range| (range, empty_str.clone())),
10587                    None,
10588                    cx,
10589                );
10590                buffer.snapshot(cx)
10591            });
10592            let new_selections = new_cursors
10593                .into_iter()
10594                .map(|(id, cursor, goal)| {
10595                    let cursor = cursor.to_point(&buffer);
10596                    Selection {
10597                        id,
10598                        start: cursor,
10599                        end: cursor,
10600                        reversed: false,
10601                        goal,
10602                    }
10603                })
10604                .collect();
10605
10606            this.change_selections(Default::default(), window, cx, |s| {
10607                s.select(new_selections);
10608            });
10609        });
10610    }
10611
10612    pub fn join_lines_impl(
10613        &mut self,
10614        insert_whitespace: bool,
10615        window: &mut Window,
10616        cx: &mut Context<Self>,
10617    ) {
10618        if self.read_only(cx) {
10619            return;
10620        }
10621        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10622        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10623            let start = MultiBufferRow(selection.start.row);
10624            // Treat single line selections as if they include the next line. Otherwise this action
10625            // would do nothing for single line selections individual cursors.
10626            let end = if selection.start.row == selection.end.row {
10627                MultiBufferRow(selection.start.row + 1)
10628            } else {
10629                MultiBufferRow(selection.end.row)
10630            };
10631
10632            if let Some(last_row_range) = row_ranges.last_mut()
10633                && start <= last_row_range.end
10634            {
10635                last_row_range.end = end;
10636                continue;
10637            }
10638            row_ranges.push(start..end);
10639        }
10640
10641        let snapshot = self.buffer.read(cx).snapshot(cx);
10642        let mut cursor_positions = Vec::new();
10643        for row_range in &row_ranges {
10644            let anchor = snapshot.anchor_before(Point::new(
10645                row_range.end.previous_row().0,
10646                snapshot.line_len(row_range.end.previous_row()),
10647            ));
10648            cursor_positions.push(anchor..anchor);
10649        }
10650
10651        self.transact(window, cx, |this, window, cx| {
10652            for row_range in row_ranges.into_iter().rev() {
10653                for row in row_range.iter_rows().rev() {
10654                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10655                    let next_line_row = row.next_row();
10656                    let indent = snapshot.indent_size_for_line(next_line_row);
10657                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10658
10659                    let replace =
10660                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10661                            " "
10662                        } else {
10663                            ""
10664                        };
10665
10666                    this.buffer.update(cx, |buffer, cx| {
10667                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10668                    });
10669                }
10670            }
10671
10672            this.change_selections(Default::default(), window, cx, |s| {
10673                s.select_anchor_ranges(cursor_positions)
10674            });
10675        });
10676    }
10677
10678    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10679        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10680        self.join_lines_impl(true, window, cx);
10681    }
10682
10683    pub fn sort_lines_case_sensitive(
10684        &mut self,
10685        _: &SortLinesCaseSensitive,
10686        window: &mut Window,
10687        cx: &mut Context<Self>,
10688    ) {
10689        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10690    }
10691
10692    pub fn sort_lines_by_length(
10693        &mut self,
10694        _: &SortLinesByLength,
10695        window: &mut Window,
10696        cx: &mut Context<Self>,
10697    ) {
10698        self.manipulate_immutable_lines(window, cx, |lines| {
10699            lines.sort_by_key(|&line| line.chars().count())
10700        })
10701    }
10702
10703    pub fn sort_lines_case_insensitive(
10704        &mut self,
10705        _: &SortLinesCaseInsensitive,
10706        window: &mut Window,
10707        cx: &mut Context<Self>,
10708    ) {
10709        self.manipulate_immutable_lines(window, cx, |lines| {
10710            lines.sort_by_key(|line| line.to_lowercase())
10711        })
10712    }
10713
10714    pub fn unique_lines_case_insensitive(
10715        &mut self,
10716        _: &UniqueLinesCaseInsensitive,
10717        window: &mut Window,
10718        cx: &mut Context<Self>,
10719    ) {
10720        self.manipulate_immutable_lines(window, cx, |lines| {
10721            let mut seen = HashSet::default();
10722            lines.retain(|line| seen.insert(line.to_lowercase()));
10723        })
10724    }
10725
10726    pub fn unique_lines_case_sensitive(
10727        &mut self,
10728        _: &UniqueLinesCaseSensitive,
10729        window: &mut Window,
10730        cx: &mut Context<Self>,
10731    ) {
10732        self.manipulate_immutable_lines(window, cx, |lines| {
10733            let mut seen = HashSet::default();
10734            lines.retain(|line| seen.insert(*line));
10735        })
10736    }
10737
10738    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10739        let snapshot = self.buffer.read(cx).snapshot(cx);
10740        for selection in self.selections.disjoint_anchors_arc().iter() {
10741            if snapshot
10742                .language_at(selection.start)
10743                .and_then(|lang| lang.config().wrap_characters.as_ref())
10744                .is_some()
10745            {
10746                return true;
10747            }
10748        }
10749        false
10750    }
10751
10752    fn wrap_selections_in_tag(
10753        &mut self,
10754        _: &WrapSelectionsInTag,
10755        window: &mut Window,
10756        cx: &mut Context<Self>,
10757    ) {
10758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10759
10760        let snapshot = self.buffer.read(cx).snapshot(cx);
10761
10762        let mut edits = Vec::new();
10763        let mut boundaries = Vec::new();
10764
10765        for selection in self
10766            .selections
10767            .all::<Point>(&self.display_snapshot(cx))
10768            .iter()
10769        {
10770            let Some(wrap_config) = snapshot
10771                .language_at(selection.start)
10772                .and_then(|lang| lang.config().wrap_characters.clone())
10773            else {
10774                continue;
10775            };
10776
10777            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10778            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10779
10780            let start_before = snapshot.anchor_before(selection.start);
10781            let end_after = snapshot.anchor_after(selection.end);
10782
10783            edits.push((start_before..start_before, open_tag));
10784            edits.push((end_after..end_after, close_tag));
10785
10786            boundaries.push((
10787                start_before,
10788                end_after,
10789                wrap_config.start_prefix.len(),
10790                wrap_config.end_suffix.len(),
10791            ));
10792        }
10793
10794        if edits.is_empty() {
10795            return;
10796        }
10797
10798        self.transact(window, cx, |this, window, cx| {
10799            let buffer = this.buffer.update(cx, |buffer, cx| {
10800                buffer.edit(edits, None, cx);
10801                buffer.snapshot(cx)
10802            });
10803
10804            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10805            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10806                boundaries.into_iter()
10807            {
10808                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10809                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10810                new_selections.push(open_offset..open_offset);
10811                new_selections.push(close_offset..close_offset);
10812            }
10813
10814            this.change_selections(Default::default(), window, cx, |s| {
10815                s.select_ranges(new_selections);
10816            });
10817
10818            this.request_autoscroll(Autoscroll::fit(), cx);
10819        });
10820    }
10821
10822    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10823        let Some(project) = self.project.clone() else {
10824            return;
10825        };
10826        self.reload(project, window, cx)
10827            .detach_and_notify_err(window, cx);
10828    }
10829
10830    pub fn restore_file(
10831        &mut self,
10832        _: &::git::RestoreFile,
10833        window: &mut Window,
10834        cx: &mut Context<Self>,
10835    ) {
10836        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10837        let mut buffer_ids = HashSet::default();
10838        let snapshot = self.buffer().read(cx).snapshot(cx);
10839        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10840            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10841        }
10842
10843        let buffer = self.buffer().read(cx);
10844        let ranges = buffer_ids
10845            .into_iter()
10846            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10847            .collect::<Vec<_>>();
10848
10849        self.restore_hunks_in_ranges(ranges, window, cx);
10850    }
10851
10852    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10854        let selections = self
10855            .selections
10856            .all(&self.display_snapshot(cx))
10857            .into_iter()
10858            .map(|s| s.range())
10859            .collect();
10860        self.restore_hunks_in_ranges(selections, window, cx);
10861    }
10862
10863    pub fn restore_hunks_in_ranges(
10864        &mut self,
10865        ranges: Vec<Range<Point>>,
10866        window: &mut Window,
10867        cx: &mut Context<Editor>,
10868    ) {
10869        let mut revert_changes = HashMap::default();
10870        let chunk_by = self
10871            .snapshot(window, cx)
10872            .hunks_for_ranges(ranges)
10873            .into_iter()
10874            .chunk_by(|hunk| hunk.buffer_id);
10875        for (buffer_id, hunks) in &chunk_by {
10876            let hunks = hunks.collect::<Vec<_>>();
10877            for hunk in &hunks {
10878                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10879            }
10880            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10881        }
10882        drop(chunk_by);
10883        if !revert_changes.is_empty() {
10884            self.transact(window, cx, |editor, window, cx| {
10885                editor.restore(revert_changes, window, cx);
10886            });
10887        }
10888    }
10889
10890    pub fn open_active_item_in_terminal(
10891        &mut self,
10892        _: &OpenInTerminal,
10893        window: &mut Window,
10894        cx: &mut Context<Self>,
10895    ) {
10896        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10897            let project_path = buffer.read(cx).project_path(cx)?;
10898            let project = self.project()?.read(cx);
10899            let entry = project.entry_for_path(&project_path, cx)?;
10900            let parent = match &entry.canonical_path {
10901                Some(canonical_path) => canonical_path.to_path_buf(),
10902                None => project.absolute_path(&project_path, cx)?,
10903            }
10904            .parent()?
10905            .to_path_buf();
10906            Some(parent)
10907        }) {
10908            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10909        }
10910    }
10911
10912    fn set_breakpoint_context_menu(
10913        &mut self,
10914        display_row: DisplayRow,
10915        position: Option<Anchor>,
10916        clicked_point: gpui::Point<Pixels>,
10917        window: &mut Window,
10918        cx: &mut Context<Self>,
10919    ) {
10920        let source = self
10921            .buffer
10922            .read(cx)
10923            .snapshot(cx)
10924            .anchor_before(Point::new(display_row.0, 0u32));
10925
10926        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10927
10928        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10929            self,
10930            source,
10931            clicked_point,
10932            context_menu,
10933            window,
10934            cx,
10935        );
10936    }
10937
10938    fn add_edit_breakpoint_block(
10939        &mut self,
10940        anchor: Anchor,
10941        breakpoint: &Breakpoint,
10942        edit_action: BreakpointPromptEditAction,
10943        window: &mut Window,
10944        cx: &mut Context<Self>,
10945    ) {
10946        let weak_editor = cx.weak_entity();
10947        let bp_prompt = cx.new(|cx| {
10948            BreakpointPromptEditor::new(
10949                weak_editor,
10950                anchor,
10951                breakpoint.clone(),
10952                edit_action,
10953                window,
10954                cx,
10955            )
10956        });
10957
10958        let height = bp_prompt.update(cx, |this, cx| {
10959            this.prompt
10960                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10961        });
10962        let cloned_prompt = bp_prompt.clone();
10963        let blocks = vec![BlockProperties {
10964            style: BlockStyle::Sticky,
10965            placement: BlockPlacement::Above(anchor),
10966            height: Some(height),
10967            render: Arc::new(move |cx| {
10968                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10969                cloned_prompt.clone().into_any_element()
10970            }),
10971            priority: 0,
10972        }];
10973
10974        let focus_handle = bp_prompt.focus_handle(cx);
10975        window.focus(&focus_handle);
10976
10977        let block_ids = self.insert_blocks(blocks, None, cx);
10978        bp_prompt.update(cx, |prompt, _| {
10979            prompt.add_block_ids(block_ids);
10980        });
10981    }
10982
10983    pub(crate) fn breakpoint_at_row(
10984        &self,
10985        row: u32,
10986        window: &mut Window,
10987        cx: &mut Context<Self>,
10988    ) -> Option<(Anchor, Breakpoint)> {
10989        let snapshot = self.snapshot(window, cx);
10990        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10991
10992        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10993    }
10994
10995    pub(crate) fn breakpoint_at_anchor(
10996        &self,
10997        breakpoint_position: Anchor,
10998        snapshot: &EditorSnapshot,
10999        cx: &mut Context<Self>,
11000    ) -> Option<(Anchor, Breakpoint)> {
11001        let buffer = self
11002            .buffer
11003            .read(cx)
11004            .buffer_for_anchor(breakpoint_position, cx)?;
11005
11006        let enclosing_excerpt = breakpoint_position.excerpt_id;
11007        let buffer_snapshot = buffer.read(cx).snapshot();
11008
11009        let row = buffer_snapshot
11010            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11011            .row;
11012
11013        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11014        let anchor_end = snapshot
11015            .buffer_snapshot()
11016            .anchor_after(Point::new(row, line_len));
11017
11018        self.breakpoint_store
11019            .as_ref()?
11020            .read_with(cx, |breakpoint_store, cx| {
11021                breakpoint_store
11022                    .breakpoints(
11023                        &buffer,
11024                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11025                        &buffer_snapshot,
11026                        cx,
11027                    )
11028                    .next()
11029                    .and_then(|(bp, _)| {
11030                        let breakpoint_row = buffer_snapshot
11031                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11032                            .row;
11033
11034                        if breakpoint_row == row {
11035                            snapshot
11036                                .buffer_snapshot()
11037                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11038                                .map(|position| (position, bp.bp.clone()))
11039                        } else {
11040                            None
11041                        }
11042                    })
11043            })
11044    }
11045
11046    pub fn edit_log_breakpoint(
11047        &mut self,
11048        _: &EditLogBreakpoint,
11049        window: &mut Window,
11050        cx: &mut Context<Self>,
11051    ) {
11052        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11053            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11054                message: None,
11055                state: BreakpointState::Enabled,
11056                condition: None,
11057                hit_condition: None,
11058            });
11059
11060            self.add_edit_breakpoint_block(
11061                anchor,
11062                &breakpoint,
11063                BreakpointPromptEditAction::Log,
11064                window,
11065                cx,
11066            );
11067        }
11068    }
11069
11070    fn breakpoints_at_cursors(
11071        &self,
11072        window: &mut Window,
11073        cx: &mut Context<Self>,
11074    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11075        let snapshot = self.snapshot(window, cx);
11076        let cursors = self
11077            .selections
11078            .disjoint_anchors_arc()
11079            .iter()
11080            .map(|selection| {
11081                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11082
11083                let breakpoint_position = self
11084                    .breakpoint_at_row(cursor_position.row, window, cx)
11085                    .map(|bp| bp.0)
11086                    .unwrap_or_else(|| {
11087                        snapshot
11088                            .display_snapshot
11089                            .buffer_snapshot()
11090                            .anchor_after(Point::new(cursor_position.row, 0))
11091                    });
11092
11093                let breakpoint = self
11094                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11095                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11096
11097                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11098            })
11099            // 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.
11100            .collect::<HashMap<Anchor, _>>();
11101
11102        cursors.into_iter().collect()
11103    }
11104
11105    pub fn enable_breakpoint(
11106        &mut self,
11107        _: &crate::actions::EnableBreakpoint,
11108        window: &mut Window,
11109        cx: &mut Context<Self>,
11110    ) {
11111        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11112            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11113                continue;
11114            };
11115            self.edit_breakpoint_at_anchor(
11116                anchor,
11117                breakpoint,
11118                BreakpointEditAction::InvertState,
11119                cx,
11120            );
11121        }
11122    }
11123
11124    pub fn disable_breakpoint(
11125        &mut self,
11126        _: &crate::actions::DisableBreakpoint,
11127        window: &mut Window,
11128        cx: &mut Context<Self>,
11129    ) {
11130        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11131            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11132                continue;
11133            };
11134            self.edit_breakpoint_at_anchor(
11135                anchor,
11136                breakpoint,
11137                BreakpointEditAction::InvertState,
11138                cx,
11139            );
11140        }
11141    }
11142
11143    pub fn toggle_breakpoint(
11144        &mut self,
11145        _: &crate::actions::ToggleBreakpoint,
11146        window: &mut Window,
11147        cx: &mut Context<Self>,
11148    ) {
11149        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11150            if let Some(breakpoint) = breakpoint {
11151                self.edit_breakpoint_at_anchor(
11152                    anchor,
11153                    breakpoint,
11154                    BreakpointEditAction::Toggle,
11155                    cx,
11156                );
11157            } else {
11158                self.edit_breakpoint_at_anchor(
11159                    anchor,
11160                    Breakpoint::new_standard(),
11161                    BreakpointEditAction::Toggle,
11162                    cx,
11163                );
11164            }
11165        }
11166    }
11167
11168    pub fn edit_breakpoint_at_anchor(
11169        &mut self,
11170        breakpoint_position: Anchor,
11171        breakpoint: Breakpoint,
11172        edit_action: BreakpointEditAction,
11173        cx: &mut Context<Self>,
11174    ) {
11175        let Some(breakpoint_store) = &self.breakpoint_store else {
11176            return;
11177        };
11178
11179        let Some(buffer) = self
11180            .buffer
11181            .read(cx)
11182            .buffer_for_anchor(breakpoint_position, cx)
11183        else {
11184            return;
11185        };
11186
11187        breakpoint_store.update(cx, |breakpoint_store, cx| {
11188            breakpoint_store.toggle_breakpoint(
11189                buffer,
11190                BreakpointWithPosition {
11191                    position: breakpoint_position.text_anchor,
11192                    bp: breakpoint,
11193                },
11194                edit_action,
11195                cx,
11196            );
11197        });
11198
11199        cx.notify();
11200    }
11201
11202    #[cfg(any(test, feature = "test-support"))]
11203    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11204        self.breakpoint_store.clone()
11205    }
11206
11207    pub fn prepare_restore_change(
11208        &self,
11209        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11210        hunk: &MultiBufferDiffHunk,
11211        cx: &mut App,
11212    ) -> Option<()> {
11213        if hunk.is_created_file() {
11214            return None;
11215        }
11216        let buffer = self.buffer.read(cx);
11217        let diff = buffer.diff_for(hunk.buffer_id)?;
11218        let buffer = buffer.buffer(hunk.buffer_id)?;
11219        let buffer = buffer.read(cx);
11220        let original_text = diff
11221            .read(cx)
11222            .base_text()
11223            .as_rope()
11224            .slice(hunk.diff_base_byte_range.clone());
11225        let buffer_snapshot = buffer.snapshot();
11226        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11227        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11228            probe
11229                .0
11230                .start
11231                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11232                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11233        }) {
11234            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11235            Some(())
11236        } else {
11237            None
11238        }
11239    }
11240
11241    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11242        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11243    }
11244
11245    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11246        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11247    }
11248
11249    fn manipulate_lines<M>(
11250        &mut self,
11251        window: &mut Window,
11252        cx: &mut Context<Self>,
11253        mut manipulate: M,
11254    ) where
11255        M: FnMut(&str) -> LineManipulationResult,
11256    {
11257        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11258
11259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11260        let buffer = self.buffer.read(cx).snapshot(cx);
11261
11262        let mut edits = Vec::new();
11263
11264        let selections = self.selections.all::<Point>(&display_map);
11265        let mut selections = selections.iter().peekable();
11266        let mut contiguous_row_selections = Vec::new();
11267        let mut new_selections = Vec::new();
11268        let mut added_lines = 0;
11269        let mut removed_lines = 0;
11270
11271        while let Some(selection) = selections.next() {
11272            let (start_row, end_row) = consume_contiguous_rows(
11273                &mut contiguous_row_selections,
11274                selection,
11275                &display_map,
11276                &mut selections,
11277            );
11278
11279            let start_point = Point::new(start_row.0, 0);
11280            let end_point = Point::new(
11281                end_row.previous_row().0,
11282                buffer.line_len(end_row.previous_row()),
11283            );
11284            let text = buffer
11285                .text_for_range(start_point..end_point)
11286                .collect::<String>();
11287
11288            let LineManipulationResult {
11289                new_text,
11290                line_count_before,
11291                line_count_after,
11292            } = manipulate(&text);
11293
11294            edits.push((start_point..end_point, new_text));
11295
11296            // Selections must change based on added and removed line count
11297            let start_row =
11298                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11299            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11300            new_selections.push(Selection {
11301                id: selection.id,
11302                start: start_row,
11303                end: end_row,
11304                goal: SelectionGoal::None,
11305                reversed: selection.reversed,
11306            });
11307
11308            if line_count_after > line_count_before {
11309                added_lines += line_count_after - line_count_before;
11310            } else if line_count_before > line_count_after {
11311                removed_lines += line_count_before - line_count_after;
11312            }
11313        }
11314
11315        self.transact(window, cx, |this, window, cx| {
11316            let buffer = this.buffer.update(cx, |buffer, cx| {
11317                buffer.edit(edits, None, cx);
11318                buffer.snapshot(cx)
11319            });
11320
11321            // Recalculate offsets on newly edited buffer
11322            let new_selections = new_selections
11323                .iter()
11324                .map(|s| {
11325                    let start_point = Point::new(s.start.0, 0);
11326                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11327                    Selection {
11328                        id: s.id,
11329                        start: buffer.point_to_offset(start_point),
11330                        end: buffer.point_to_offset(end_point),
11331                        goal: s.goal,
11332                        reversed: s.reversed,
11333                    }
11334                })
11335                .collect();
11336
11337            this.change_selections(Default::default(), window, cx, |s| {
11338                s.select(new_selections);
11339            });
11340
11341            this.request_autoscroll(Autoscroll::fit(), cx);
11342        });
11343    }
11344
11345    fn manipulate_immutable_lines<Fn>(
11346        &mut self,
11347        window: &mut Window,
11348        cx: &mut Context<Self>,
11349        mut callback: Fn,
11350    ) where
11351        Fn: FnMut(&mut Vec<&str>),
11352    {
11353        self.manipulate_lines(window, cx, |text| {
11354            let mut lines: Vec<&str> = text.split('\n').collect();
11355            let line_count_before = lines.len();
11356
11357            callback(&mut lines);
11358
11359            LineManipulationResult {
11360                new_text: lines.join("\n"),
11361                line_count_before,
11362                line_count_after: lines.len(),
11363            }
11364        });
11365    }
11366
11367    fn manipulate_mutable_lines<Fn>(
11368        &mut self,
11369        window: &mut Window,
11370        cx: &mut Context<Self>,
11371        mut callback: Fn,
11372    ) where
11373        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11374    {
11375        self.manipulate_lines(window, cx, |text| {
11376            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11377            let line_count_before = lines.len();
11378
11379            callback(&mut lines);
11380
11381            LineManipulationResult {
11382                new_text: lines.join("\n"),
11383                line_count_before,
11384                line_count_after: lines.len(),
11385            }
11386        });
11387    }
11388
11389    pub fn convert_indentation_to_spaces(
11390        &mut self,
11391        _: &ConvertIndentationToSpaces,
11392        window: &mut Window,
11393        cx: &mut Context<Self>,
11394    ) {
11395        let settings = self.buffer.read(cx).language_settings(cx);
11396        let tab_size = settings.tab_size.get() as usize;
11397
11398        self.manipulate_mutable_lines(window, cx, |lines| {
11399            // Allocates a reasonably sized scratch buffer once for the whole loop
11400            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11401            // Avoids recomputing spaces that could be inserted many times
11402            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11403                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11404                .collect();
11405
11406            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11407                let mut chars = line.as_ref().chars();
11408                let mut col = 0;
11409                let mut changed = false;
11410
11411                for ch in chars.by_ref() {
11412                    match ch {
11413                        ' ' => {
11414                            reindented_line.push(' ');
11415                            col += 1;
11416                        }
11417                        '\t' => {
11418                            // \t are converted to spaces depending on the current column
11419                            let spaces_len = tab_size - (col % tab_size);
11420                            reindented_line.extend(&space_cache[spaces_len - 1]);
11421                            col += spaces_len;
11422                            changed = true;
11423                        }
11424                        _ => {
11425                            // If we dont append before break, the character is consumed
11426                            reindented_line.push(ch);
11427                            break;
11428                        }
11429                    }
11430                }
11431
11432                if !changed {
11433                    reindented_line.clear();
11434                    continue;
11435                }
11436                // Append the rest of the line and replace old reference with new one
11437                reindented_line.extend(chars);
11438                *line = Cow::Owned(reindented_line.clone());
11439                reindented_line.clear();
11440            }
11441        });
11442    }
11443
11444    pub fn convert_indentation_to_tabs(
11445        &mut self,
11446        _: &ConvertIndentationToTabs,
11447        window: &mut Window,
11448        cx: &mut Context<Self>,
11449    ) {
11450        let settings = self.buffer.read(cx).language_settings(cx);
11451        let tab_size = settings.tab_size.get() as usize;
11452
11453        self.manipulate_mutable_lines(window, cx, |lines| {
11454            // Allocates a reasonably sized buffer once for the whole loop
11455            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11456            // Avoids recomputing spaces that could be inserted many times
11457            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11458                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11459                .collect();
11460
11461            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11462                let mut chars = line.chars();
11463                let mut spaces_count = 0;
11464                let mut first_non_indent_char = None;
11465                let mut changed = false;
11466
11467                for ch in chars.by_ref() {
11468                    match ch {
11469                        ' ' => {
11470                            // Keep track of spaces. Append \t when we reach tab_size
11471                            spaces_count += 1;
11472                            changed = true;
11473                            if spaces_count == tab_size {
11474                                reindented_line.push('\t');
11475                                spaces_count = 0;
11476                            }
11477                        }
11478                        '\t' => {
11479                            reindented_line.push('\t');
11480                            spaces_count = 0;
11481                        }
11482                        _ => {
11483                            // Dont append it yet, we might have remaining spaces
11484                            first_non_indent_char = Some(ch);
11485                            break;
11486                        }
11487                    }
11488                }
11489
11490                if !changed {
11491                    reindented_line.clear();
11492                    continue;
11493                }
11494                // Remaining spaces that didn't make a full tab stop
11495                if spaces_count > 0 {
11496                    reindented_line.extend(&space_cache[spaces_count - 1]);
11497                }
11498                // If we consume an extra character that was not indentation, add it back
11499                if let Some(extra_char) = first_non_indent_char {
11500                    reindented_line.push(extra_char);
11501                }
11502                // Append the rest of the line and replace old reference with new one
11503                reindented_line.extend(chars);
11504                *line = Cow::Owned(reindented_line.clone());
11505                reindented_line.clear();
11506            }
11507        });
11508    }
11509
11510    pub fn convert_to_upper_case(
11511        &mut self,
11512        _: &ConvertToUpperCase,
11513        window: &mut Window,
11514        cx: &mut Context<Self>,
11515    ) {
11516        self.manipulate_text(window, cx, |text| text.to_uppercase())
11517    }
11518
11519    pub fn convert_to_lower_case(
11520        &mut self,
11521        _: &ConvertToLowerCase,
11522        window: &mut Window,
11523        cx: &mut Context<Self>,
11524    ) {
11525        self.manipulate_text(window, cx, |text| text.to_lowercase())
11526    }
11527
11528    pub fn convert_to_title_case(
11529        &mut self,
11530        _: &ConvertToTitleCase,
11531        window: &mut Window,
11532        cx: &mut Context<Self>,
11533    ) {
11534        self.manipulate_text(window, cx, |text| {
11535            text.split('\n')
11536                .map(|line| line.to_case(Case::Title))
11537                .join("\n")
11538        })
11539    }
11540
11541    pub fn convert_to_snake_case(
11542        &mut self,
11543        _: &ConvertToSnakeCase,
11544        window: &mut Window,
11545        cx: &mut Context<Self>,
11546    ) {
11547        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11548    }
11549
11550    pub fn convert_to_kebab_case(
11551        &mut self,
11552        _: &ConvertToKebabCase,
11553        window: &mut Window,
11554        cx: &mut Context<Self>,
11555    ) {
11556        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11557    }
11558
11559    pub fn convert_to_upper_camel_case(
11560        &mut self,
11561        _: &ConvertToUpperCamelCase,
11562        window: &mut Window,
11563        cx: &mut Context<Self>,
11564    ) {
11565        self.manipulate_text(window, cx, |text| {
11566            text.split('\n')
11567                .map(|line| line.to_case(Case::UpperCamel))
11568                .join("\n")
11569        })
11570    }
11571
11572    pub fn convert_to_lower_camel_case(
11573        &mut self,
11574        _: &ConvertToLowerCamelCase,
11575        window: &mut Window,
11576        cx: &mut Context<Self>,
11577    ) {
11578        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11579    }
11580
11581    pub fn convert_to_opposite_case(
11582        &mut self,
11583        _: &ConvertToOppositeCase,
11584        window: &mut Window,
11585        cx: &mut Context<Self>,
11586    ) {
11587        self.manipulate_text(window, cx, |text| {
11588            text.chars()
11589                .fold(String::with_capacity(text.len()), |mut t, c| {
11590                    if c.is_uppercase() {
11591                        t.extend(c.to_lowercase());
11592                    } else {
11593                        t.extend(c.to_uppercase());
11594                    }
11595                    t
11596                })
11597        })
11598    }
11599
11600    pub fn convert_to_sentence_case(
11601        &mut self,
11602        _: &ConvertToSentenceCase,
11603        window: &mut Window,
11604        cx: &mut Context<Self>,
11605    ) {
11606        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11607    }
11608
11609    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11610        self.manipulate_text(window, cx, |text| {
11611            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11612            if has_upper_case_characters {
11613                text.to_lowercase()
11614            } else {
11615                text.to_uppercase()
11616            }
11617        })
11618    }
11619
11620    pub fn convert_to_rot13(
11621        &mut self,
11622        _: &ConvertToRot13,
11623        window: &mut Window,
11624        cx: &mut Context<Self>,
11625    ) {
11626        self.manipulate_text(window, cx, |text| {
11627            text.chars()
11628                .map(|c| match c {
11629                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11630                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11631                    _ => c,
11632                })
11633                .collect()
11634        })
11635    }
11636
11637    pub fn convert_to_rot47(
11638        &mut self,
11639        _: &ConvertToRot47,
11640        window: &mut Window,
11641        cx: &mut Context<Self>,
11642    ) {
11643        self.manipulate_text(window, cx, |text| {
11644            text.chars()
11645                .map(|c| {
11646                    let code_point = c as u32;
11647                    if code_point >= 33 && code_point <= 126 {
11648                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11649                    }
11650                    c
11651                })
11652                .collect()
11653        })
11654    }
11655
11656    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11657    where
11658        Fn: FnMut(&str) -> String,
11659    {
11660        let buffer = self.buffer.read(cx).snapshot(cx);
11661
11662        let mut new_selections = Vec::new();
11663        let mut edits = Vec::new();
11664        let mut selection_adjustment = 0i32;
11665
11666        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11667            let selection_is_empty = selection.is_empty();
11668
11669            let (start, end) = if selection_is_empty {
11670                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11671                (word_range.start, word_range.end)
11672            } else {
11673                (
11674                    buffer.point_to_offset(selection.start),
11675                    buffer.point_to_offset(selection.end),
11676                )
11677            };
11678
11679            let text = buffer.text_for_range(start..end).collect::<String>();
11680            let old_length = text.len() as i32;
11681            let text = callback(&text);
11682
11683            new_selections.push(Selection {
11684                start: (start as i32 - selection_adjustment) as usize,
11685                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11686                goal: SelectionGoal::None,
11687                id: selection.id,
11688                reversed: selection.reversed,
11689            });
11690
11691            selection_adjustment += old_length - text.len() as i32;
11692
11693            edits.push((start..end, text));
11694        }
11695
11696        self.transact(window, cx, |this, window, cx| {
11697            this.buffer.update(cx, |buffer, cx| {
11698                buffer.edit(edits, None, cx);
11699            });
11700
11701            this.change_selections(Default::default(), window, cx, |s| {
11702                s.select(new_selections);
11703            });
11704
11705            this.request_autoscroll(Autoscroll::fit(), cx);
11706        });
11707    }
11708
11709    pub fn move_selection_on_drop(
11710        &mut self,
11711        selection: &Selection<Anchor>,
11712        target: DisplayPoint,
11713        is_cut: bool,
11714        window: &mut Window,
11715        cx: &mut Context<Self>,
11716    ) {
11717        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11718        let buffer = display_map.buffer_snapshot();
11719        let mut edits = Vec::new();
11720        let insert_point = display_map
11721            .clip_point(target, Bias::Left)
11722            .to_point(&display_map);
11723        let text = buffer
11724            .text_for_range(selection.start..selection.end)
11725            .collect::<String>();
11726        if is_cut {
11727            edits.push(((selection.start..selection.end), String::new()));
11728        }
11729        let insert_anchor = buffer.anchor_before(insert_point);
11730        edits.push(((insert_anchor..insert_anchor), text));
11731        let last_edit_start = insert_anchor.bias_left(buffer);
11732        let last_edit_end = insert_anchor.bias_right(buffer);
11733        self.transact(window, cx, |this, window, cx| {
11734            this.buffer.update(cx, |buffer, cx| {
11735                buffer.edit(edits, None, cx);
11736            });
11737            this.change_selections(Default::default(), window, cx, |s| {
11738                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11739            });
11740        });
11741    }
11742
11743    pub fn clear_selection_drag_state(&mut self) {
11744        self.selection_drag_state = SelectionDragState::None;
11745    }
11746
11747    pub fn duplicate(
11748        &mut self,
11749        upwards: bool,
11750        whole_lines: bool,
11751        window: &mut Window,
11752        cx: &mut Context<Self>,
11753    ) {
11754        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11755
11756        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11757        let buffer = display_map.buffer_snapshot();
11758        let selections = self.selections.all::<Point>(&display_map);
11759
11760        let mut edits = Vec::new();
11761        let mut selections_iter = selections.iter().peekable();
11762        while let Some(selection) = selections_iter.next() {
11763            let mut rows = selection.spanned_rows(false, &display_map);
11764            // duplicate line-wise
11765            if whole_lines || selection.start == selection.end {
11766                // Avoid duplicating the same lines twice.
11767                while let Some(next_selection) = selections_iter.peek() {
11768                    let next_rows = next_selection.spanned_rows(false, &display_map);
11769                    if next_rows.start < rows.end {
11770                        rows.end = next_rows.end;
11771                        selections_iter.next().unwrap();
11772                    } else {
11773                        break;
11774                    }
11775                }
11776
11777                // Copy the text from the selected row region and splice it either at the start
11778                // or end of the region.
11779                let start = Point::new(rows.start.0, 0);
11780                let end = Point::new(
11781                    rows.end.previous_row().0,
11782                    buffer.line_len(rows.end.previous_row()),
11783                );
11784
11785                let mut text = buffer.text_for_range(start..end).collect::<String>();
11786
11787                let insert_location = if upwards {
11788                    // When duplicating upward, we need to insert before the current line.
11789                    // If we're on the last line and it doesn't end with a newline,
11790                    // we need to add a newline before the duplicated content.
11791                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11792                        && buffer.max_point().column > 0
11793                        && !text.ends_with('\n');
11794
11795                    if needs_leading_newline {
11796                        text.insert(0, '\n');
11797                        end
11798                    } else {
11799                        text.push('\n');
11800                        Point::new(rows.end.0, 0)
11801                    }
11802                } else {
11803                    text.push('\n');
11804                    start
11805                };
11806                edits.push((insert_location..insert_location, text));
11807            } else {
11808                // duplicate character-wise
11809                let start = selection.start;
11810                let end = selection.end;
11811                let text = buffer.text_for_range(start..end).collect::<String>();
11812                edits.push((selection.end..selection.end, text));
11813            }
11814        }
11815
11816        self.transact(window, cx, |this, _, cx| {
11817            this.buffer.update(cx, |buffer, cx| {
11818                buffer.edit(edits, None, cx);
11819            });
11820
11821            this.request_autoscroll(Autoscroll::fit(), cx);
11822        });
11823    }
11824
11825    pub fn duplicate_line_up(
11826        &mut self,
11827        _: &DuplicateLineUp,
11828        window: &mut Window,
11829        cx: &mut Context<Self>,
11830    ) {
11831        self.duplicate(true, true, window, cx);
11832    }
11833
11834    pub fn duplicate_line_down(
11835        &mut self,
11836        _: &DuplicateLineDown,
11837        window: &mut Window,
11838        cx: &mut Context<Self>,
11839    ) {
11840        self.duplicate(false, true, window, cx);
11841    }
11842
11843    pub fn duplicate_selection(
11844        &mut self,
11845        _: &DuplicateSelection,
11846        window: &mut Window,
11847        cx: &mut Context<Self>,
11848    ) {
11849        self.duplicate(false, false, window, cx);
11850    }
11851
11852    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11854        if self.mode.is_single_line() {
11855            cx.propagate();
11856            return;
11857        }
11858
11859        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11860        let buffer = self.buffer.read(cx).snapshot(cx);
11861
11862        let mut edits = Vec::new();
11863        let mut unfold_ranges = Vec::new();
11864        let mut refold_creases = Vec::new();
11865
11866        let selections = self.selections.all::<Point>(&display_map);
11867        let mut selections = selections.iter().peekable();
11868        let mut contiguous_row_selections = Vec::new();
11869        let mut new_selections = Vec::new();
11870
11871        while let Some(selection) = selections.next() {
11872            // Find all the selections that span a contiguous row range
11873            let (start_row, end_row) = consume_contiguous_rows(
11874                &mut contiguous_row_selections,
11875                selection,
11876                &display_map,
11877                &mut selections,
11878            );
11879
11880            // Move the text spanned by the row range to be before the line preceding the row range
11881            if start_row.0 > 0 {
11882                let range_to_move = Point::new(
11883                    start_row.previous_row().0,
11884                    buffer.line_len(start_row.previous_row()),
11885                )
11886                    ..Point::new(
11887                        end_row.previous_row().0,
11888                        buffer.line_len(end_row.previous_row()),
11889                    );
11890                let insertion_point = display_map
11891                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11892                    .0;
11893
11894                // Don't move lines across excerpts
11895                if buffer
11896                    .excerpt_containing(insertion_point..range_to_move.end)
11897                    .is_some()
11898                {
11899                    let text = buffer
11900                        .text_for_range(range_to_move.clone())
11901                        .flat_map(|s| s.chars())
11902                        .skip(1)
11903                        .chain(['\n'])
11904                        .collect::<String>();
11905
11906                    edits.push((
11907                        buffer.anchor_after(range_to_move.start)
11908                            ..buffer.anchor_before(range_to_move.end),
11909                        String::new(),
11910                    ));
11911                    let insertion_anchor = buffer.anchor_after(insertion_point);
11912                    edits.push((insertion_anchor..insertion_anchor, text));
11913
11914                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11915
11916                    // Move selections up
11917                    new_selections.extend(contiguous_row_selections.drain(..).map(
11918                        |mut selection| {
11919                            selection.start.row -= row_delta;
11920                            selection.end.row -= row_delta;
11921                            selection
11922                        },
11923                    ));
11924
11925                    // Move folds up
11926                    unfold_ranges.push(range_to_move.clone());
11927                    for fold in display_map.folds_in_range(
11928                        buffer.anchor_before(range_to_move.start)
11929                            ..buffer.anchor_after(range_to_move.end),
11930                    ) {
11931                        let mut start = fold.range.start.to_point(&buffer);
11932                        let mut end = fold.range.end.to_point(&buffer);
11933                        start.row -= row_delta;
11934                        end.row -= row_delta;
11935                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11936                    }
11937                }
11938            }
11939
11940            // If we didn't move line(s), preserve the existing selections
11941            new_selections.append(&mut contiguous_row_selections);
11942        }
11943
11944        self.transact(window, cx, |this, window, cx| {
11945            this.unfold_ranges(&unfold_ranges, true, true, cx);
11946            this.buffer.update(cx, |buffer, cx| {
11947                for (range, text) in edits {
11948                    buffer.edit([(range, text)], None, cx);
11949                }
11950            });
11951            this.fold_creases(refold_creases, true, window, cx);
11952            this.change_selections(Default::default(), window, cx, |s| {
11953                s.select(new_selections);
11954            })
11955        });
11956    }
11957
11958    pub fn move_line_down(
11959        &mut self,
11960        _: &MoveLineDown,
11961        window: &mut Window,
11962        cx: &mut Context<Self>,
11963    ) {
11964        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11965        if self.mode.is_single_line() {
11966            cx.propagate();
11967            return;
11968        }
11969
11970        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11971        let buffer = self.buffer.read(cx).snapshot(cx);
11972
11973        let mut edits = Vec::new();
11974        let mut unfold_ranges = Vec::new();
11975        let mut refold_creases = Vec::new();
11976
11977        let selections = self.selections.all::<Point>(&display_map);
11978        let mut selections = selections.iter().peekable();
11979        let mut contiguous_row_selections = Vec::new();
11980        let mut new_selections = Vec::new();
11981
11982        while let Some(selection) = selections.next() {
11983            // Find all the selections that span a contiguous row range
11984            let (start_row, end_row) = consume_contiguous_rows(
11985                &mut contiguous_row_selections,
11986                selection,
11987                &display_map,
11988                &mut selections,
11989            );
11990
11991            // Move the text spanned by the row range to be after the last line of the row range
11992            if end_row.0 <= buffer.max_point().row {
11993                let range_to_move =
11994                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11995                let insertion_point = display_map
11996                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11997                    .0;
11998
11999                // Don't move lines across excerpt boundaries
12000                if buffer
12001                    .excerpt_containing(range_to_move.start..insertion_point)
12002                    .is_some()
12003                {
12004                    let mut text = String::from("\n");
12005                    text.extend(buffer.text_for_range(range_to_move.clone()));
12006                    text.pop(); // Drop trailing newline
12007                    edits.push((
12008                        buffer.anchor_after(range_to_move.start)
12009                            ..buffer.anchor_before(range_to_move.end),
12010                        String::new(),
12011                    ));
12012                    let insertion_anchor = buffer.anchor_after(insertion_point);
12013                    edits.push((insertion_anchor..insertion_anchor, text));
12014
12015                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12016
12017                    // Move selections down
12018                    new_selections.extend(contiguous_row_selections.drain(..).map(
12019                        |mut selection| {
12020                            selection.start.row += row_delta;
12021                            selection.end.row += row_delta;
12022                            selection
12023                        },
12024                    ));
12025
12026                    // Move folds down
12027                    unfold_ranges.push(range_to_move.clone());
12028                    for fold in display_map.folds_in_range(
12029                        buffer.anchor_before(range_to_move.start)
12030                            ..buffer.anchor_after(range_to_move.end),
12031                    ) {
12032                        let mut start = fold.range.start.to_point(&buffer);
12033                        let mut end = fold.range.end.to_point(&buffer);
12034                        start.row += row_delta;
12035                        end.row += row_delta;
12036                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12037                    }
12038                }
12039            }
12040
12041            // If we didn't move line(s), preserve the existing selections
12042            new_selections.append(&mut contiguous_row_selections);
12043        }
12044
12045        self.transact(window, cx, |this, window, cx| {
12046            this.unfold_ranges(&unfold_ranges, true, true, cx);
12047            this.buffer.update(cx, |buffer, cx| {
12048                for (range, text) in edits {
12049                    buffer.edit([(range, text)], None, cx);
12050                }
12051            });
12052            this.fold_creases(refold_creases, true, window, cx);
12053            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12054        });
12055    }
12056
12057    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12058        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12059        let text_layout_details = &self.text_layout_details(window);
12060        self.transact(window, cx, |this, window, cx| {
12061            let edits = this.change_selections(Default::default(), window, cx, |s| {
12062                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12063                s.move_with(|display_map, selection| {
12064                    if !selection.is_empty() {
12065                        return;
12066                    }
12067
12068                    let mut head = selection.head();
12069                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12070                    if head.column() == display_map.line_len(head.row()) {
12071                        transpose_offset = display_map
12072                            .buffer_snapshot()
12073                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12074                    }
12075
12076                    if transpose_offset == 0 {
12077                        return;
12078                    }
12079
12080                    *head.column_mut() += 1;
12081                    head = display_map.clip_point(head, Bias::Right);
12082                    let goal = SelectionGoal::HorizontalPosition(
12083                        display_map
12084                            .x_for_display_point(head, text_layout_details)
12085                            .into(),
12086                    );
12087                    selection.collapse_to(head, goal);
12088
12089                    let transpose_start = display_map
12090                        .buffer_snapshot()
12091                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12092                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12093                        let transpose_end = display_map
12094                            .buffer_snapshot()
12095                            .clip_offset(transpose_offset + 1, Bias::Right);
12096                        if let Some(ch) = display_map
12097                            .buffer_snapshot()
12098                            .chars_at(transpose_start)
12099                            .next()
12100                        {
12101                            edits.push((transpose_start..transpose_offset, String::new()));
12102                            edits.push((transpose_end..transpose_end, ch.to_string()));
12103                        }
12104                    }
12105                });
12106                edits
12107            });
12108            this.buffer
12109                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12110            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12111            this.change_selections(Default::default(), window, cx, |s| {
12112                s.select(selections);
12113            });
12114        });
12115    }
12116
12117    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12119        if self.mode.is_single_line() {
12120            cx.propagate();
12121            return;
12122        }
12123
12124        self.rewrap_impl(RewrapOptions::default(), cx)
12125    }
12126
12127    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12128        let buffer = self.buffer.read(cx).snapshot(cx);
12129        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12130
12131        #[derive(Clone, Debug, PartialEq)]
12132        enum CommentFormat {
12133            /// single line comment, with prefix for line
12134            Line(String),
12135            /// single line within a block comment, with prefix for line
12136            BlockLine(String),
12137            /// a single line of a block comment that includes the initial delimiter
12138            BlockCommentWithStart(BlockCommentConfig),
12139            /// a single line of a block comment that includes the ending delimiter
12140            BlockCommentWithEnd(BlockCommentConfig),
12141        }
12142
12143        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12144        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12145            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12146                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12147                .peekable();
12148
12149            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12150                row
12151            } else {
12152                return Vec::new();
12153            };
12154
12155            let language_settings = buffer.language_settings_at(selection.head(), cx);
12156            let language_scope = buffer.language_scope_at(selection.head());
12157
12158            let indent_and_prefix_for_row =
12159                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12160                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12161                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12162                        &language_scope
12163                    {
12164                        let indent_end = Point::new(row, indent.len);
12165                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12166                        let line_text_after_indent = buffer
12167                            .text_for_range(indent_end..line_end)
12168                            .collect::<String>();
12169
12170                        let is_within_comment_override = buffer
12171                            .language_scope_at(indent_end)
12172                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12173                        let comment_delimiters = if is_within_comment_override {
12174                            // we are within a comment syntax node, but we don't
12175                            // yet know what kind of comment: block, doc or line
12176                            match (
12177                                language_scope.documentation_comment(),
12178                                language_scope.block_comment(),
12179                            ) {
12180                                (Some(config), _) | (_, Some(config))
12181                                    if buffer.contains_str_at(indent_end, &config.start) =>
12182                                {
12183                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12184                                }
12185                                (Some(config), _) | (_, Some(config))
12186                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12187                                {
12188                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12189                                }
12190                                (Some(config), _) | (_, Some(config))
12191                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12192                                {
12193                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12194                                }
12195                                (_, _) => language_scope
12196                                    .line_comment_prefixes()
12197                                    .iter()
12198                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12199                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12200                            }
12201                        } else {
12202                            // we not in an overridden comment node, but we may
12203                            // be within a non-overridden line comment node
12204                            language_scope
12205                                .line_comment_prefixes()
12206                                .iter()
12207                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12208                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12209                        };
12210
12211                        let rewrap_prefix = language_scope
12212                            .rewrap_prefixes()
12213                            .iter()
12214                            .find_map(|prefix_regex| {
12215                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12216                                    if mat.start() == 0 {
12217                                        Some(mat.as_str().to_string())
12218                                    } else {
12219                                        None
12220                                    }
12221                                })
12222                            })
12223                            .flatten();
12224                        (comment_delimiters, rewrap_prefix)
12225                    } else {
12226                        (None, None)
12227                    };
12228                    (indent, comment_prefix, rewrap_prefix)
12229                };
12230
12231            let mut ranges = Vec::new();
12232            let from_empty_selection = selection.is_empty();
12233
12234            let mut current_range_start = first_row;
12235            let mut prev_row = first_row;
12236            let (
12237                mut current_range_indent,
12238                mut current_range_comment_delimiters,
12239                mut current_range_rewrap_prefix,
12240            ) = indent_and_prefix_for_row(first_row);
12241
12242            for row in non_blank_rows_iter.skip(1) {
12243                let has_paragraph_break = row > prev_row + 1;
12244
12245                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12246                    indent_and_prefix_for_row(row);
12247
12248                let has_indent_change = row_indent != current_range_indent;
12249                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12250
12251                let has_boundary_change = has_comment_change
12252                    || row_rewrap_prefix.is_some()
12253                    || (has_indent_change && current_range_comment_delimiters.is_some());
12254
12255                if has_paragraph_break || has_boundary_change {
12256                    ranges.push((
12257                        language_settings.clone(),
12258                        Point::new(current_range_start, 0)
12259                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12260                        current_range_indent,
12261                        current_range_comment_delimiters.clone(),
12262                        current_range_rewrap_prefix.clone(),
12263                        from_empty_selection,
12264                    ));
12265                    current_range_start = row;
12266                    current_range_indent = row_indent;
12267                    current_range_comment_delimiters = row_comment_delimiters;
12268                    current_range_rewrap_prefix = row_rewrap_prefix;
12269                }
12270                prev_row = row;
12271            }
12272
12273            ranges.push((
12274                language_settings.clone(),
12275                Point::new(current_range_start, 0)
12276                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12277                current_range_indent,
12278                current_range_comment_delimiters,
12279                current_range_rewrap_prefix,
12280                from_empty_selection,
12281            ));
12282
12283            ranges
12284        });
12285
12286        let mut edits = Vec::new();
12287        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12288
12289        for (
12290            language_settings,
12291            wrap_range,
12292            mut indent_size,
12293            comment_prefix,
12294            rewrap_prefix,
12295            from_empty_selection,
12296        ) in wrap_ranges
12297        {
12298            let mut start_row = wrap_range.start.row;
12299            let mut end_row = wrap_range.end.row;
12300
12301            // Skip selections that overlap with a range that has already been rewrapped.
12302            let selection_range = start_row..end_row;
12303            if rewrapped_row_ranges
12304                .iter()
12305                .any(|range| range.overlaps(&selection_range))
12306            {
12307                continue;
12308            }
12309
12310            let tab_size = language_settings.tab_size;
12311
12312            let (line_prefix, inside_comment) = match &comment_prefix {
12313                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12314                    (Some(prefix.as_str()), true)
12315                }
12316                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12317                    (Some(prefix.as_ref()), true)
12318                }
12319                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12320                    start: _,
12321                    end: _,
12322                    prefix,
12323                    tab_size,
12324                })) => {
12325                    indent_size.len += tab_size;
12326                    (Some(prefix.as_ref()), true)
12327                }
12328                None => (None, false),
12329            };
12330            let indent_prefix = indent_size.chars().collect::<String>();
12331            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12332
12333            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12334                RewrapBehavior::InComments => inside_comment,
12335                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12336                RewrapBehavior::Anywhere => true,
12337            };
12338
12339            let should_rewrap = options.override_language_settings
12340                || allow_rewrap_based_on_language
12341                || self.hard_wrap.is_some();
12342            if !should_rewrap {
12343                continue;
12344            }
12345
12346            if from_empty_selection {
12347                'expand_upwards: while start_row > 0 {
12348                    let prev_row = start_row - 1;
12349                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12350                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12351                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12352                    {
12353                        start_row = prev_row;
12354                    } else {
12355                        break 'expand_upwards;
12356                    }
12357                }
12358
12359                'expand_downwards: while end_row < buffer.max_point().row {
12360                    let next_row = end_row + 1;
12361                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12362                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12363                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12364                    {
12365                        end_row = next_row;
12366                    } else {
12367                        break 'expand_downwards;
12368                    }
12369                }
12370            }
12371
12372            let start = Point::new(start_row, 0);
12373            let start_offset = ToOffset::to_offset(&start, &buffer);
12374            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12375            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12376            let mut first_line_delimiter = None;
12377            let mut last_line_delimiter = None;
12378            let Some(lines_without_prefixes) = selection_text
12379                .lines()
12380                .enumerate()
12381                .map(|(ix, line)| {
12382                    let line_trimmed = line.trim_start();
12383                    if rewrap_prefix.is_some() && ix > 0 {
12384                        Ok(line_trimmed)
12385                    } else if let Some(
12386                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12387                            start,
12388                            prefix,
12389                            end,
12390                            tab_size,
12391                        })
12392                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12393                            start,
12394                            prefix,
12395                            end,
12396                            tab_size,
12397                        }),
12398                    ) = &comment_prefix
12399                    {
12400                        let line_trimmed = line_trimmed
12401                            .strip_prefix(start.as_ref())
12402                            .map(|s| {
12403                                let mut indent_size = indent_size;
12404                                indent_size.len -= tab_size;
12405                                let indent_prefix: String = indent_size.chars().collect();
12406                                first_line_delimiter = Some((indent_prefix, start));
12407                                s.trim_start()
12408                            })
12409                            .unwrap_or(line_trimmed);
12410                        let line_trimmed = line_trimmed
12411                            .strip_suffix(end.as_ref())
12412                            .map(|s| {
12413                                last_line_delimiter = Some(end);
12414                                s.trim_end()
12415                            })
12416                            .unwrap_or(line_trimmed);
12417                        let line_trimmed = line_trimmed
12418                            .strip_prefix(prefix.as_ref())
12419                            .unwrap_or(line_trimmed);
12420                        Ok(line_trimmed)
12421                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12422                        line_trimmed.strip_prefix(prefix).with_context(|| {
12423                            format!("line did not start with prefix {prefix:?}: {line:?}")
12424                        })
12425                    } else {
12426                        line_trimmed
12427                            .strip_prefix(&line_prefix.trim_start())
12428                            .with_context(|| {
12429                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12430                            })
12431                    }
12432                })
12433                .collect::<Result<Vec<_>, _>>()
12434                .log_err()
12435            else {
12436                continue;
12437            };
12438
12439            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12440                buffer
12441                    .language_settings_at(Point::new(start_row, 0), cx)
12442                    .preferred_line_length as usize
12443            });
12444
12445            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12446                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12447            } else {
12448                line_prefix.clone()
12449            };
12450
12451            let wrapped_text = {
12452                let mut wrapped_text = wrap_with_prefix(
12453                    line_prefix,
12454                    subsequent_lines_prefix,
12455                    lines_without_prefixes.join("\n"),
12456                    wrap_column,
12457                    tab_size,
12458                    options.preserve_existing_whitespace,
12459                );
12460
12461                if let Some((indent, delimiter)) = first_line_delimiter {
12462                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12463                }
12464                if let Some(last_line) = last_line_delimiter {
12465                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12466                }
12467
12468                wrapped_text
12469            };
12470
12471            // TODO: should always use char-based diff while still supporting cursor behavior that
12472            // matches vim.
12473            let mut diff_options = DiffOptions::default();
12474            if options.override_language_settings {
12475                diff_options.max_word_diff_len = 0;
12476                diff_options.max_word_diff_line_count = 0;
12477            } else {
12478                diff_options.max_word_diff_len = usize::MAX;
12479                diff_options.max_word_diff_line_count = usize::MAX;
12480            }
12481
12482            for (old_range, new_text) in
12483                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12484            {
12485                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12486                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12487                edits.push((edit_start..edit_end, new_text));
12488            }
12489
12490            rewrapped_row_ranges.push(start_row..=end_row);
12491        }
12492
12493        self.buffer
12494            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12495    }
12496
12497    pub fn cut_common(
12498        &mut self,
12499        cut_no_selection_line: bool,
12500        window: &mut Window,
12501        cx: &mut Context<Self>,
12502    ) -> ClipboardItem {
12503        let mut text = String::new();
12504        let buffer = self.buffer.read(cx).snapshot(cx);
12505        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12506        let mut clipboard_selections = Vec::with_capacity(selections.len());
12507        {
12508            let max_point = buffer.max_point();
12509            let mut is_first = true;
12510            for selection in &mut selections {
12511                let is_entire_line =
12512                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12513                if is_entire_line {
12514                    selection.start = Point::new(selection.start.row, 0);
12515                    if !selection.is_empty() && selection.end.column == 0 {
12516                        selection.end = cmp::min(max_point, selection.end);
12517                    } else {
12518                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12519                    }
12520                    selection.goal = SelectionGoal::None;
12521                }
12522                if is_first {
12523                    is_first = false;
12524                } else {
12525                    text += "\n";
12526                }
12527                let mut len = 0;
12528                for chunk in buffer.text_for_range(selection.start..selection.end) {
12529                    text.push_str(chunk);
12530                    len += chunk.len();
12531                }
12532                clipboard_selections.push(ClipboardSelection {
12533                    len,
12534                    is_entire_line,
12535                    first_line_indent: buffer
12536                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12537                        .len,
12538                });
12539            }
12540        }
12541
12542        self.transact(window, cx, |this, window, cx| {
12543            this.change_selections(Default::default(), window, cx, |s| {
12544                s.select(selections);
12545            });
12546            this.insert("", window, cx);
12547        });
12548        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12549    }
12550
12551    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12552        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12553        let item = self.cut_common(true, window, cx);
12554        cx.write_to_clipboard(item);
12555    }
12556
12557    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12558        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12559        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12560            s.move_with(|snapshot, sel| {
12561                if sel.is_empty() {
12562                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12563                }
12564                if sel.is_empty() {
12565                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12566                }
12567            });
12568        });
12569        let item = self.cut_common(false, window, cx);
12570        cx.set_global(KillRing(item))
12571    }
12572
12573    pub fn kill_ring_yank(
12574        &mut self,
12575        _: &KillRingYank,
12576        window: &mut Window,
12577        cx: &mut Context<Self>,
12578    ) {
12579        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12580        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12581            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12582                (kill_ring.text().to_string(), kill_ring.metadata_json())
12583            } else {
12584                return;
12585            }
12586        } else {
12587            return;
12588        };
12589        self.do_paste(&text, metadata, false, window, cx);
12590    }
12591
12592    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12593        self.do_copy(true, cx);
12594    }
12595
12596    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12597        self.do_copy(false, cx);
12598    }
12599
12600    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12601        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12602        let buffer = self.buffer.read(cx).read(cx);
12603        let mut text = String::new();
12604
12605        let mut clipboard_selections = Vec::with_capacity(selections.len());
12606        {
12607            let max_point = buffer.max_point();
12608            let mut is_first = true;
12609            for selection in &selections {
12610                let mut start = selection.start;
12611                let mut end = selection.end;
12612                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12613                let mut add_trailing_newline = false;
12614                if is_entire_line {
12615                    start = Point::new(start.row, 0);
12616                    let next_line_start = Point::new(end.row + 1, 0);
12617                    if next_line_start <= max_point {
12618                        end = next_line_start;
12619                    } else {
12620                        // We're on the last line without a trailing newline.
12621                        // Copy to the end of the line and add a newline afterwards.
12622                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12623                        add_trailing_newline = true;
12624                    }
12625                }
12626
12627                let mut trimmed_selections = Vec::new();
12628                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12629                    let row = MultiBufferRow(start.row);
12630                    let first_indent = buffer.indent_size_for_line(row);
12631                    if first_indent.len == 0 || start.column > first_indent.len {
12632                        trimmed_selections.push(start..end);
12633                    } else {
12634                        trimmed_selections.push(
12635                            Point::new(row.0, first_indent.len)
12636                                ..Point::new(row.0, buffer.line_len(row)),
12637                        );
12638                        for row in start.row + 1..=end.row {
12639                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12640                            if row == end.row {
12641                                line_len = end.column;
12642                            }
12643                            if line_len == 0 {
12644                                trimmed_selections
12645                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12646                                continue;
12647                            }
12648                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12649                            if row_indent_size.len >= first_indent.len {
12650                                trimmed_selections.push(
12651                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12652                                );
12653                            } else {
12654                                trimmed_selections.clear();
12655                                trimmed_selections.push(start..end);
12656                                break;
12657                            }
12658                        }
12659                    }
12660                } else {
12661                    trimmed_selections.push(start..end);
12662                }
12663
12664                for trimmed_range in trimmed_selections {
12665                    if is_first {
12666                        is_first = false;
12667                    } else {
12668                        text += "\n";
12669                    }
12670                    let mut len = 0;
12671                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12672                        text.push_str(chunk);
12673                        len += chunk.len();
12674                    }
12675                    if add_trailing_newline {
12676                        text.push('\n');
12677                        len += 1;
12678                    }
12679                    clipboard_selections.push(ClipboardSelection {
12680                        len,
12681                        is_entire_line,
12682                        first_line_indent: buffer
12683                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12684                            .len,
12685                    });
12686                }
12687            }
12688        }
12689
12690        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12691            text,
12692            clipboard_selections,
12693        ));
12694    }
12695
12696    pub fn do_paste(
12697        &mut self,
12698        text: &String,
12699        clipboard_selections: Option<Vec<ClipboardSelection>>,
12700        handle_entire_lines: bool,
12701        window: &mut Window,
12702        cx: &mut Context<Self>,
12703    ) {
12704        if self.read_only(cx) {
12705            return;
12706        }
12707
12708        let clipboard_text = Cow::Borrowed(text.as_str());
12709
12710        self.transact(window, cx, |this, window, cx| {
12711            let had_active_edit_prediction = this.has_active_edit_prediction();
12712            let display_map = this.display_snapshot(cx);
12713            let old_selections = this.selections.all::<usize>(&display_map);
12714            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12715
12716            if let Some(mut clipboard_selections) = clipboard_selections {
12717                let all_selections_were_entire_line =
12718                    clipboard_selections.iter().all(|s| s.is_entire_line);
12719                let first_selection_indent_column =
12720                    clipboard_selections.first().map(|s| s.first_line_indent);
12721                if clipboard_selections.len() != old_selections.len() {
12722                    clipboard_selections.drain(..);
12723                }
12724                let mut auto_indent_on_paste = true;
12725
12726                this.buffer.update(cx, |buffer, cx| {
12727                    let snapshot = buffer.read(cx);
12728                    auto_indent_on_paste = snapshot
12729                        .language_settings_at(cursor_offset, cx)
12730                        .auto_indent_on_paste;
12731
12732                    let mut start_offset = 0;
12733                    let mut edits = Vec::new();
12734                    let mut original_indent_columns = Vec::new();
12735                    for (ix, selection) in old_selections.iter().enumerate() {
12736                        let to_insert;
12737                        let entire_line;
12738                        let original_indent_column;
12739                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12740                            let end_offset = start_offset + clipboard_selection.len;
12741                            to_insert = &clipboard_text[start_offset..end_offset];
12742                            entire_line = clipboard_selection.is_entire_line;
12743                            start_offset = end_offset + 1;
12744                            original_indent_column = Some(clipboard_selection.first_line_indent);
12745                        } else {
12746                            to_insert = &*clipboard_text;
12747                            entire_line = all_selections_were_entire_line;
12748                            original_indent_column = first_selection_indent_column
12749                        }
12750
12751                        let (range, to_insert) =
12752                            if selection.is_empty() && handle_entire_lines && entire_line {
12753                                // If the corresponding selection was empty when this slice of the
12754                                // clipboard text was written, then the entire line containing the
12755                                // selection was copied. If this selection is also currently empty,
12756                                // then paste the line before the current line of the buffer.
12757                                let column = selection.start.to_point(&snapshot).column as usize;
12758                                let line_start = selection.start - column;
12759                                (line_start..line_start, Cow::Borrowed(to_insert))
12760                            } else {
12761                                let language = snapshot.language_at(selection.head());
12762                                let range = selection.range();
12763                                if let Some(language) = language
12764                                    && language.name() == "Markdown".into()
12765                                {
12766                                    edit_for_markdown_paste(
12767                                        &snapshot,
12768                                        range,
12769                                        to_insert,
12770                                        url::Url::parse(to_insert).ok(),
12771                                    )
12772                                } else {
12773                                    (range, Cow::Borrowed(to_insert))
12774                                }
12775                            };
12776
12777                        edits.push((range, to_insert));
12778                        original_indent_columns.push(original_indent_column);
12779                    }
12780                    drop(snapshot);
12781
12782                    buffer.edit(
12783                        edits,
12784                        if auto_indent_on_paste {
12785                            Some(AutoindentMode::Block {
12786                                original_indent_columns,
12787                            })
12788                        } else {
12789                            None
12790                        },
12791                        cx,
12792                    );
12793                });
12794
12795                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12796                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12797            } else {
12798                let url = url::Url::parse(&clipboard_text).ok();
12799
12800                let auto_indent_mode = if !clipboard_text.is_empty() {
12801                    Some(AutoindentMode::Block {
12802                        original_indent_columns: Vec::new(),
12803                    })
12804                } else {
12805                    None
12806                };
12807
12808                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12809                    let snapshot = buffer.snapshot(cx);
12810
12811                    let anchors = old_selections
12812                        .iter()
12813                        .map(|s| {
12814                            let anchor = snapshot.anchor_after(s.head());
12815                            s.map(|_| anchor)
12816                        })
12817                        .collect::<Vec<_>>();
12818
12819                    let mut edits = Vec::new();
12820
12821                    for selection in old_selections.iter() {
12822                        let language = snapshot.language_at(selection.head());
12823                        let range = selection.range();
12824
12825                        let (edit_range, edit_text) = if let Some(language) = language
12826                            && language.name() == "Markdown".into()
12827                        {
12828                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12829                        } else {
12830                            (range, clipboard_text.clone())
12831                        };
12832
12833                        edits.push((edit_range, edit_text));
12834                    }
12835
12836                    drop(snapshot);
12837                    buffer.edit(edits, auto_indent_mode, cx);
12838
12839                    anchors
12840                });
12841
12842                this.change_selections(Default::default(), window, cx, |s| {
12843                    s.select_anchors(selection_anchors);
12844                });
12845            }
12846
12847            let trigger_in_words =
12848                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12849
12850            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12851        });
12852    }
12853
12854    pub fn diff_clipboard_with_selection(
12855        &mut self,
12856        _: &DiffClipboardWithSelection,
12857        window: &mut Window,
12858        cx: &mut Context<Self>,
12859    ) {
12860        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12861
12862        if selections.is_empty() {
12863            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12864            return;
12865        };
12866
12867        let clipboard_text = match cx.read_from_clipboard() {
12868            Some(item) => match item.entries().first() {
12869                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12870                _ => None,
12871            },
12872            None => None,
12873        };
12874
12875        let Some(clipboard_text) = clipboard_text else {
12876            log::warn!("Clipboard doesn't contain text.");
12877            return;
12878        };
12879
12880        window.dispatch_action(
12881            Box::new(DiffClipboardWithSelectionData {
12882                clipboard_text,
12883                editor: cx.entity(),
12884            }),
12885            cx,
12886        );
12887    }
12888
12889    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12890        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12891        if let Some(item) = cx.read_from_clipboard() {
12892            let entries = item.entries();
12893
12894            match entries.first() {
12895                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12896                // of all the pasted entries.
12897                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12898                    .do_paste(
12899                        clipboard_string.text(),
12900                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12901                        true,
12902                        window,
12903                        cx,
12904                    ),
12905                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12906            }
12907        }
12908    }
12909
12910    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12911        if self.read_only(cx) {
12912            return;
12913        }
12914
12915        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12916
12917        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12918            if let Some((selections, _)) =
12919                self.selection_history.transaction(transaction_id).cloned()
12920            {
12921                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12922                    s.select_anchors(selections.to_vec());
12923                });
12924            } else {
12925                log::error!(
12926                    "No entry in selection_history found for undo. \
12927                     This may correspond to a bug where undo does not update the selection. \
12928                     If this is occurring, please add details to \
12929                     https://github.com/zed-industries/zed/issues/22692"
12930                );
12931            }
12932            self.request_autoscroll(Autoscroll::fit(), cx);
12933            self.unmark_text(window, cx);
12934            self.refresh_edit_prediction(true, false, window, cx);
12935            cx.emit(EditorEvent::Edited { transaction_id });
12936            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12937        }
12938    }
12939
12940    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12941        if self.read_only(cx) {
12942            return;
12943        }
12944
12945        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12946
12947        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12948            if let Some((_, Some(selections))) =
12949                self.selection_history.transaction(transaction_id).cloned()
12950            {
12951                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12952                    s.select_anchors(selections.to_vec());
12953                });
12954            } else {
12955                log::error!(
12956                    "No entry in selection_history found for redo. \
12957                     This may correspond to a bug where undo does not update the selection. \
12958                     If this is occurring, please add details to \
12959                     https://github.com/zed-industries/zed/issues/22692"
12960                );
12961            }
12962            self.request_autoscroll(Autoscroll::fit(), cx);
12963            self.unmark_text(window, cx);
12964            self.refresh_edit_prediction(true, false, window, cx);
12965            cx.emit(EditorEvent::Edited { transaction_id });
12966        }
12967    }
12968
12969    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12970        self.buffer
12971            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12972    }
12973
12974    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12975        self.buffer
12976            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12977    }
12978
12979    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12980        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12981        self.change_selections(Default::default(), window, cx, |s| {
12982            s.move_with(|map, selection| {
12983                let cursor = if selection.is_empty() {
12984                    movement::left(map, selection.start)
12985                } else {
12986                    selection.start
12987                };
12988                selection.collapse_to(cursor, SelectionGoal::None);
12989            });
12990        })
12991    }
12992
12993    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12994        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12995        self.change_selections(Default::default(), window, cx, |s| {
12996            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12997        })
12998    }
12999
13000    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13001        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13002        self.change_selections(Default::default(), window, cx, |s| {
13003            s.move_with(|map, selection| {
13004                let cursor = if selection.is_empty() {
13005                    movement::right(map, selection.end)
13006                } else {
13007                    selection.end
13008                };
13009                selection.collapse_to(cursor, SelectionGoal::None)
13010            });
13011        })
13012    }
13013
13014    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13016        self.change_selections(Default::default(), window, cx, |s| {
13017            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13018        });
13019    }
13020
13021    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13022        if self.take_rename(true, window, cx).is_some() {
13023            return;
13024        }
13025
13026        if self.mode.is_single_line() {
13027            cx.propagate();
13028            return;
13029        }
13030
13031        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13032
13033        let text_layout_details = &self.text_layout_details(window);
13034        let selection_count = self.selections.count();
13035        let first_selection = self.selections.first_anchor();
13036
13037        self.change_selections(Default::default(), window, cx, |s| {
13038            s.move_with(|map, selection| {
13039                if !selection.is_empty() {
13040                    selection.goal = SelectionGoal::None;
13041                }
13042                let (cursor, goal) = movement::up(
13043                    map,
13044                    selection.start,
13045                    selection.goal,
13046                    false,
13047                    text_layout_details,
13048                );
13049                selection.collapse_to(cursor, goal);
13050            });
13051        });
13052
13053        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13054        {
13055            cx.propagate();
13056        }
13057    }
13058
13059    pub fn move_up_by_lines(
13060        &mut self,
13061        action: &MoveUpByLines,
13062        window: &mut Window,
13063        cx: &mut Context<Self>,
13064    ) {
13065        if self.take_rename(true, window, cx).is_some() {
13066            return;
13067        }
13068
13069        if self.mode.is_single_line() {
13070            cx.propagate();
13071            return;
13072        }
13073
13074        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13075
13076        let text_layout_details = &self.text_layout_details(window);
13077
13078        self.change_selections(Default::default(), window, cx, |s| {
13079            s.move_with(|map, selection| {
13080                if !selection.is_empty() {
13081                    selection.goal = SelectionGoal::None;
13082                }
13083                let (cursor, goal) = movement::up_by_rows(
13084                    map,
13085                    selection.start,
13086                    action.lines,
13087                    selection.goal,
13088                    false,
13089                    text_layout_details,
13090                );
13091                selection.collapse_to(cursor, goal);
13092            });
13093        })
13094    }
13095
13096    pub fn move_down_by_lines(
13097        &mut self,
13098        action: &MoveDownByLines,
13099        window: &mut Window,
13100        cx: &mut Context<Self>,
13101    ) {
13102        if self.take_rename(true, window, cx).is_some() {
13103            return;
13104        }
13105
13106        if self.mode.is_single_line() {
13107            cx.propagate();
13108            return;
13109        }
13110
13111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13112
13113        let text_layout_details = &self.text_layout_details(window);
13114
13115        self.change_selections(Default::default(), window, cx, |s| {
13116            s.move_with(|map, selection| {
13117                if !selection.is_empty() {
13118                    selection.goal = SelectionGoal::None;
13119                }
13120                let (cursor, goal) = movement::down_by_rows(
13121                    map,
13122                    selection.start,
13123                    action.lines,
13124                    selection.goal,
13125                    false,
13126                    text_layout_details,
13127                );
13128                selection.collapse_to(cursor, goal);
13129            });
13130        })
13131    }
13132
13133    pub fn select_down_by_lines(
13134        &mut self,
13135        action: &SelectDownByLines,
13136        window: &mut Window,
13137        cx: &mut Context<Self>,
13138    ) {
13139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13140        let text_layout_details = &self.text_layout_details(window);
13141        self.change_selections(Default::default(), window, cx, |s| {
13142            s.move_heads_with(|map, head, goal| {
13143                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13144            })
13145        })
13146    }
13147
13148    pub fn select_up_by_lines(
13149        &mut self,
13150        action: &SelectUpByLines,
13151        window: &mut Window,
13152        cx: &mut Context<Self>,
13153    ) {
13154        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13155        let text_layout_details = &self.text_layout_details(window);
13156        self.change_selections(Default::default(), window, cx, |s| {
13157            s.move_heads_with(|map, head, goal| {
13158                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13159            })
13160        })
13161    }
13162
13163    pub fn select_page_up(
13164        &mut self,
13165        _: &SelectPageUp,
13166        window: &mut Window,
13167        cx: &mut Context<Self>,
13168    ) {
13169        let Some(row_count) = self.visible_row_count() else {
13170            return;
13171        };
13172
13173        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13174
13175        let text_layout_details = &self.text_layout_details(window);
13176
13177        self.change_selections(Default::default(), window, cx, |s| {
13178            s.move_heads_with(|map, head, goal| {
13179                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13180            })
13181        })
13182    }
13183
13184    pub fn move_page_up(
13185        &mut self,
13186        action: &MovePageUp,
13187        window: &mut Window,
13188        cx: &mut Context<Self>,
13189    ) {
13190        if self.take_rename(true, window, cx).is_some() {
13191            return;
13192        }
13193
13194        if self
13195            .context_menu
13196            .borrow_mut()
13197            .as_mut()
13198            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13199            .unwrap_or(false)
13200        {
13201            return;
13202        }
13203
13204        if matches!(self.mode, EditorMode::SingleLine) {
13205            cx.propagate();
13206            return;
13207        }
13208
13209        let Some(row_count) = self.visible_row_count() else {
13210            return;
13211        };
13212
13213        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13214
13215        let effects = if action.center_cursor {
13216            SelectionEffects::scroll(Autoscroll::center())
13217        } else {
13218            SelectionEffects::default()
13219        };
13220
13221        let text_layout_details = &self.text_layout_details(window);
13222
13223        self.change_selections(effects, window, cx, |s| {
13224            s.move_with(|map, selection| {
13225                if !selection.is_empty() {
13226                    selection.goal = SelectionGoal::None;
13227                }
13228                let (cursor, goal) = movement::up_by_rows(
13229                    map,
13230                    selection.end,
13231                    row_count,
13232                    selection.goal,
13233                    false,
13234                    text_layout_details,
13235                );
13236                selection.collapse_to(cursor, goal);
13237            });
13238        });
13239    }
13240
13241    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13243        let text_layout_details = &self.text_layout_details(window);
13244        self.change_selections(Default::default(), window, cx, |s| {
13245            s.move_heads_with(|map, head, goal| {
13246                movement::up(map, head, goal, false, text_layout_details)
13247            })
13248        })
13249    }
13250
13251    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13252        self.take_rename(true, window, cx);
13253
13254        if self.mode.is_single_line() {
13255            cx.propagate();
13256            return;
13257        }
13258
13259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13260
13261        let text_layout_details = &self.text_layout_details(window);
13262        let selection_count = self.selections.count();
13263        let first_selection = self.selections.first_anchor();
13264
13265        self.change_selections(Default::default(), window, cx, |s| {
13266            s.move_with(|map, selection| {
13267                if !selection.is_empty() {
13268                    selection.goal = SelectionGoal::None;
13269                }
13270                let (cursor, goal) = movement::down(
13271                    map,
13272                    selection.end,
13273                    selection.goal,
13274                    false,
13275                    text_layout_details,
13276                );
13277                selection.collapse_to(cursor, goal);
13278            });
13279        });
13280
13281        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13282        {
13283            cx.propagate();
13284        }
13285    }
13286
13287    pub fn select_page_down(
13288        &mut self,
13289        _: &SelectPageDown,
13290        window: &mut Window,
13291        cx: &mut Context<Self>,
13292    ) {
13293        let Some(row_count) = self.visible_row_count() else {
13294            return;
13295        };
13296
13297        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13298
13299        let text_layout_details = &self.text_layout_details(window);
13300
13301        self.change_selections(Default::default(), window, cx, |s| {
13302            s.move_heads_with(|map, head, goal| {
13303                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13304            })
13305        })
13306    }
13307
13308    pub fn move_page_down(
13309        &mut self,
13310        action: &MovePageDown,
13311        window: &mut Window,
13312        cx: &mut Context<Self>,
13313    ) {
13314        if self.take_rename(true, window, cx).is_some() {
13315            return;
13316        }
13317
13318        if self
13319            .context_menu
13320            .borrow_mut()
13321            .as_mut()
13322            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13323            .unwrap_or(false)
13324        {
13325            return;
13326        }
13327
13328        if matches!(self.mode, EditorMode::SingleLine) {
13329            cx.propagate();
13330            return;
13331        }
13332
13333        let Some(row_count) = self.visible_row_count() else {
13334            return;
13335        };
13336
13337        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13338
13339        let effects = if action.center_cursor {
13340            SelectionEffects::scroll(Autoscroll::center())
13341        } else {
13342            SelectionEffects::default()
13343        };
13344
13345        let text_layout_details = &self.text_layout_details(window);
13346        self.change_selections(effects, window, cx, |s| {
13347            s.move_with(|map, selection| {
13348                if !selection.is_empty() {
13349                    selection.goal = SelectionGoal::None;
13350                }
13351                let (cursor, goal) = movement::down_by_rows(
13352                    map,
13353                    selection.end,
13354                    row_count,
13355                    selection.goal,
13356                    false,
13357                    text_layout_details,
13358                );
13359                selection.collapse_to(cursor, goal);
13360            });
13361        });
13362    }
13363
13364    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13365        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13366        let text_layout_details = &self.text_layout_details(window);
13367        self.change_selections(Default::default(), window, cx, |s| {
13368            s.move_heads_with(|map, head, goal| {
13369                movement::down(map, head, goal, false, text_layout_details)
13370            })
13371        });
13372    }
13373
13374    pub fn context_menu_first(
13375        &mut self,
13376        _: &ContextMenuFirst,
13377        window: &mut Window,
13378        cx: &mut Context<Self>,
13379    ) {
13380        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13381            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13382        }
13383    }
13384
13385    pub fn context_menu_prev(
13386        &mut self,
13387        _: &ContextMenuPrevious,
13388        window: &mut Window,
13389        cx: &mut Context<Self>,
13390    ) {
13391        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13392            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13393        }
13394    }
13395
13396    pub fn context_menu_next(
13397        &mut self,
13398        _: &ContextMenuNext,
13399        window: &mut Window,
13400        cx: &mut Context<Self>,
13401    ) {
13402        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13403            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13404        }
13405    }
13406
13407    pub fn context_menu_last(
13408        &mut self,
13409        _: &ContextMenuLast,
13410        window: &mut Window,
13411        cx: &mut Context<Self>,
13412    ) {
13413        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13414            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13415        }
13416    }
13417
13418    pub fn signature_help_prev(
13419        &mut self,
13420        _: &SignatureHelpPrevious,
13421        _: &mut Window,
13422        cx: &mut Context<Self>,
13423    ) {
13424        if let Some(popover) = self.signature_help_state.popover_mut() {
13425            if popover.current_signature == 0 {
13426                popover.current_signature = popover.signatures.len() - 1;
13427            } else {
13428                popover.current_signature -= 1;
13429            }
13430            cx.notify();
13431        }
13432    }
13433
13434    pub fn signature_help_next(
13435        &mut self,
13436        _: &SignatureHelpNext,
13437        _: &mut Window,
13438        cx: &mut Context<Self>,
13439    ) {
13440        if let Some(popover) = self.signature_help_state.popover_mut() {
13441            if popover.current_signature + 1 == popover.signatures.len() {
13442                popover.current_signature = 0;
13443            } else {
13444                popover.current_signature += 1;
13445            }
13446            cx.notify();
13447        }
13448    }
13449
13450    pub fn move_to_previous_word_start(
13451        &mut self,
13452        _: &MoveToPreviousWordStart,
13453        window: &mut Window,
13454        cx: &mut Context<Self>,
13455    ) {
13456        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13457        self.change_selections(Default::default(), window, cx, |s| {
13458            s.move_cursors_with(|map, head, _| {
13459                (
13460                    movement::previous_word_start(map, head),
13461                    SelectionGoal::None,
13462                )
13463            });
13464        })
13465    }
13466
13467    pub fn move_to_previous_subword_start(
13468        &mut self,
13469        _: &MoveToPreviousSubwordStart,
13470        window: &mut Window,
13471        cx: &mut Context<Self>,
13472    ) {
13473        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13474        self.change_selections(Default::default(), window, cx, |s| {
13475            s.move_cursors_with(|map, head, _| {
13476                (
13477                    movement::previous_subword_start(map, head),
13478                    SelectionGoal::None,
13479                )
13480            });
13481        })
13482    }
13483
13484    pub fn select_to_previous_word_start(
13485        &mut self,
13486        _: &SelectToPreviousWordStart,
13487        window: &mut Window,
13488        cx: &mut Context<Self>,
13489    ) {
13490        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13491        self.change_selections(Default::default(), window, cx, |s| {
13492            s.move_heads_with(|map, head, _| {
13493                (
13494                    movement::previous_word_start(map, head),
13495                    SelectionGoal::None,
13496                )
13497            });
13498        })
13499    }
13500
13501    pub fn select_to_previous_subword_start(
13502        &mut self,
13503        _: &SelectToPreviousSubwordStart,
13504        window: &mut Window,
13505        cx: &mut Context<Self>,
13506    ) {
13507        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13508        self.change_selections(Default::default(), window, cx, |s| {
13509            s.move_heads_with(|map, head, _| {
13510                (
13511                    movement::previous_subword_start(map, head),
13512                    SelectionGoal::None,
13513                )
13514            });
13515        })
13516    }
13517
13518    pub fn delete_to_previous_word_start(
13519        &mut self,
13520        action: &DeleteToPreviousWordStart,
13521        window: &mut Window,
13522        cx: &mut Context<Self>,
13523    ) {
13524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13525        self.transact(window, cx, |this, window, cx| {
13526            this.select_autoclose_pair(window, cx);
13527            this.change_selections(Default::default(), window, cx, |s| {
13528                s.move_with(|map, selection| {
13529                    if selection.is_empty() {
13530                        let mut cursor = if action.ignore_newlines {
13531                            movement::previous_word_start(map, selection.head())
13532                        } else {
13533                            movement::previous_word_start_or_newline(map, selection.head())
13534                        };
13535                        cursor = movement::adjust_greedy_deletion(
13536                            map,
13537                            selection.head(),
13538                            cursor,
13539                            action.ignore_brackets,
13540                        );
13541                        selection.set_head(cursor, SelectionGoal::None);
13542                    }
13543                });
13544            });
13545            this.insert("", window, cx);
13546        });
13547    }
13548
13549    pub fn delete_to_previous_subword_start(
13550        &mut self,
13551        _: &DeleteToPreviousSubwordStart,
13552        window: &mut Window,
13553        cx: &mut Context<Self>,
13554    ) {
13555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13556        self.transact(window, cx, |this, window, cx| {
13557            this.select_autoclose_pair(window, cx);
13558            this.change_selections(Default::default(), window, cx, |s| {
13559                s.move_with(|map, selection| {
13560                    if selection.is_empty() {
13561                        let mut cursor = movement::previous_subword_start(map, selection.head());
13562                        cursor =
13563                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13564                        selection.set_head(cursor, SelectionGoal::None);
13565                    }
13566                });
13567            });
13568            this.insert("", window, cx);
13569        });
13570    }
13571
13572    pub fn move_to_next_word_end(
13573        &mut self,
13574        _: &MoveToNextWordEnd,
13575        window: &mut Window,
13576        cx: &mut Context<Self>,
13577    ) {
13578        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13579        self.change_selections(Default::default(), window, cx, |s| {
13580            s.move_cursors_with(|map, head, _| {
13581                (movement::next_word_end(map, head), SelectionGoal::None)
13582            });
13583        })
13584    }
13585
13586    pub fn move_to_next_subword_end(
13587        &mut self,
13588        _: &MoveToNextSubwordEnd,
13589        window: &mut Window,
13590        cx: &mut Context<Self>,
13591    ) {
13592        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13593        self.change_selections(Default::default(), window, cx, |s| {
13594            s.move_cursors_with(|map, head, _| {
13595                (movement::next_subword_end(map, head), SelectionGoal::None)
13596            });
13597        })
13598    }
13599
13600    pub fn select_to_next_word_end(
13601        &mut self,
13602        _: &SelectToNextWordEnd,
13603        window: &mut Window,
13604        cx: &mut Context<Self>,
13605    ) {
13606        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13607        self.change_selections(Default::default(), window, cx, |s| {
13608            s.move_heads_with(|map, head, _| {
13609                (movement::next_word_end(map, head), SelectionGoal::None)
13610            });
13611        })
13612    }
13613
13614    pub fn select_to_next_subword_end(
13615        &mut self,
13616        _: &SelectToNextSubwordEnd,
13617        window: &mut Window,
13618        cx: &mut Context<Self>,
13619    ) {
13620        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13621        self.change_selections(Default::default(), window, cx, |s| {
13622            s.move_heads_with(|map, head, _| {
13623                (movement::next_subword_end(map, head), SelectionGoal::None)
13624            });
13625        })
13626    }
13627
13628    pub fn delete_to_next_word_end(
13629        &mut self,
13630        action: &DeleteToNextWordEnd,
13631        window: &mut Window,
13632        cx: &mut Context<Self>,
13633    ) {
13634        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13635        self.transact(window, cx, |this, window, cx| {
13636            this.change_selections(Default::default(), window, cx, |s| {
13637                s.move_with(|map, selection| {
13638                    if selection.is_empty() {
13639                        let mut cursor = if action.ignore_newlines {
13640                            movement::next_word_end(map, selection.head())
13641                        } else {
13642                            movement::next_word_end_or_newline(map, selection.head())
13643                        };
13644                        cursor = movement::adjust_greedy_deletion(
13645                            map,
13646                            selection.head(),
13647                            cursor,
13648                            action.ignore_brackets,
13649                        );
13650                        selection.set_head(cursor, SelectionGoal::None);
13651                    }
13652                });
13653            });
13654            this.insert("", window, cx);
13655        });
13656    }
13657
13658    pub fn delete_to_next_subword_end(
13659        &mut self,
13660        _: &DeleteToNextSubwordEnd,
13661        window: &mut Window,
13662        cx: &mut Context<Self>,
13663    ) {
13664        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13665        self.transact(window, cx, |this, window, cx| {
13666            this.change_selections(Default::default(), window, cx, |s| {
13667                s.move_with(|map, selection| {
13668                    if selection.is_empty() {
13669                        let mut cursor = movement::next_subword_end(map, selection.head());
13670                        cursor =
13671                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13672                        selection.set_head(cursor, SelectionGoal::None);
13673                    }
13674                });
13675            });
13676            this.insert("", window, cx);
13677        });
13678    }
13679
13680    pub fn move_to_beginning_of_line(
13681        &mut self,
13682        action: &MoveToBeginningOfLine,
13683        window: &mut Window,
13684        cx: &mut Context<Self>,
13685    ) {
13686        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13687        self.change_selections(Default::default(), window, cx, |s| {
13688            s.move_cursors_with(|map, head, _| {
13689                (
13690                    movement::indented_line_beginning(
13691                        map,
13692                        head,
13693                        action.stop_at_soft_wraps,
13694                        action.stop_at_indent,
13695                    ),
13696                    SelectionGoal::None,
13697                )
13698            });
13699        })
13700    }
13701
13702    pub fn select_to_beginning_of_line(
13703        &mut self,
13704        action: &SelectToBeginningOfLine,
13705        window: &mut Window,
13706        cx: &mut Context<Self>,
13707    ) {
13708        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13709        self.change_selections(Default::default(), window, cx, |s| {
13710            s.move_heads_with(|map, head, _| {
13711                (
13712                    movement::indented_line_beginning(
13713                        map,
13714                        head,
13715                        action.stop_at_soft_wraps,
13716                        action.stop_at_indent,
13717                    ),
13718                    SelectionGoal::None,
13719                )
13720            });
13721        });
13722    }
13723
13724    pub fn delete_to_beginning_of_line(
13725        &mut self,
13726        action: &DeleteToBeginningOfLine,
13727        window: &mut Window,
13728        cx: &mut Context<Self>,
13729    ) {
13730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13731        self.transact(window, cx, |this, window, cx| {
13732            this.change_selections(Default::default(), window, cx, |s| {
13733                s.move_with(|_, selection| {
13734                    selection.reversed = true;
13735                });
13736            });
13737
13738            this.select_to_beginning_of_line(
13739                &SelectToBeginningOfLine {
13740                    stop_at_soft_wraps: false,
13741                    stop_at_indent: action.stop_at_indent,
13742                },
13743                window,
13744                cx,
13745            );
13746            this.backspace(&Backspace, window, cx);
13747        });
13748    }
13749
13750    pub fn move_to_end_of_line(
13751        &mut self,
13752        action: &MoveToEndOfLine,
13753        window: &mut Window,
13754        cx: &mut Context<Self>,
13755    ) {
13756        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13757        self.change_selections(Default::default(), window, cx, |s| {
13758            s.move_cursors_with(|map, head, _| {
13759                (
13760                    movement::line_end(map, head, action.stop_at_soft_wraps),
13761                    SelectionGoal::None,
13762                )
13763            });
13764        })
13765    }
13766
13767    pub fn select_to_end_of_line(
13768        &mut self,
13769        action: &SelectToEndOfLine,
13770        window: &mut Window,
13771        cx: &mut Context<Self>,
13772    ) {
13773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13774        self.change_selections(Default::default(), window, cx, |s| {
13775            s.move_heads_with(|map, head, _| {
13776                (
13777                    movement::line_end(map, head, action.stop_at_soft_wraps),
13778                    SelectionGoal::None,
13779                )
13780            });
13781        })
13782    }
13783
13784    pub fn delete_to_end_of_line(
13785        &mut self,
13786        _: &DeleteToEndOfLine,
13787        window: &mut Window,
13788        cx: &mut Context<Self>,
13789    ) {
13790        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13791        self.transact(window, cx, |this, window, cx| {
13792            this.select_to_end_of_line(
13793                &SelectToEndOfLine {
13794                    stop_at_soft_wraps: false,
13795                },
13796                window,
13797                cx,
13798            );
13799            this.delete(&Delete, window, cx);
13800        });
13801    }
13802
13803    pub fn cut_to_end_of_line(
13804        &mut self,
13805        action: &CutToEndOfLine,
13806        window: &mut Window,
13807        cx: &mut Context<Self>,
13808    ) {
13809        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13810        self.transact(window, cx, |this, window, cx| {
13811            this.select_to_end_of_line(
13812                &SelectToEndOfLine {
13813                    stop_at_soft_wraps: false,
13814                },
13815                window,
13816                cx,
13817            );
13818            if !action.stop_at_newlines {
13819                this.change_selections(Default::default(), window, cx, |s| {
13820                    s.move_with(|_, sel| {
13821                        if sel.is_empty() {
13822                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13823                        }
13824                    });
13825                });
13826            }
13827            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13828            let item = this.cut_common(false, window, cx);
13829            cx.write_to_clipboard(item);
13830        });
13831    }
13832
13833    pub fn move_to_start_of_paragraph(
13834        &mut self,
13835        _: &MoveToStartOfParagraph,
13836        window: &mut Window,
13837        cx: &mut Context<Self>,
13838    ) {
13839        if matches!(self.mode, EditorMode::SingleLine) {
13840            cx.propagate();
13841            return;
13842        }
13843        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13844        self.change_selections(Default::default(), window, cx, |s| {
13845            s.move_with(|map, selection| {
13846                selection.collapse_to(
13847                    movement::start_of_paragraph(map, selection.head(), 1),
13848                    SelectionGoal::None,
13849                )
13850            });
13851        })
13852    }
13853
13854    pub fn move_to_end_of_paragraph(
13855        &mut self,
13856        _: &MoveToEndOfParagraph,
13857        window: &mut Window,
13858        cx: &mut Context<Self>,
13859    ) {
13860        if matches!(self.mode, EditorMode::SingleLine) {
13861            cx.propagate();
13862            return;
13863        }
13864        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13865        self.change_selections(Default::default(), window, cx, |s| {
13866            s.move_with(|map, selection| {
13867                selection.collapse_to(
13868                    movement::end_of_paragraph(map, selection.head(), 1),
13869                    SelectionGoal::None,
13870                )
13871            });
13872        })
13873    }
13874
13875    pub fn select_to_start_of_paragraph(
13876        &mut self,
13877        _: &SelectToStartOfParagraph,
13878        window: &mut Window,
13879        cx: &mut Context<Self>,
13880    ) {
13881        if matches!(self.mode, EditorMode::SingleLine) {
13882            cx.propagate();
13883            return;
13884        }
13885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13886        self.change_selections(Default::default(), window, cx, |s| {
13887            s.move_heads_with(|map, head, _| {
13888                (
13889                    movement::start_of_paragraph(map, head, 1),
13890                    SelectionGoal::None,
13891                )
13892            });
13893        })
13894    }
13895
13896    pub fn select_to_end_of_paragraph(
13897        &mut self,
13898        _: &SelectToEndOfParagraph,
13899        window: &mut Window,
13900        cx: &mut Context<Self>,
13901    ) {
13902        if matches!(self.mode, EditorMode::SingleLine) {
13903            cx.propagate();
13904            return;
13905        }
13906        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13907        self.change_selections(Default::default(), window, cx, |s| {
13908            s.move_heads_with(|map, head, _| {
13909                (
13910                    movement::end_of_paragraph(map, head, 1),
13911                    SelectionGoal::None,
13912                )
13913            });
13914        })
13915    }
13916
13917    pub fn move_to_start_of_excerpt(
13918        &mut self,
13919        _: &MoveToStartOfExcerpt,
13920        window: &mut Window,
13921        cx: &mut Context<Self>,
13922    ) {
13923        if matches!(self.mode, EditorMode::SingleLine) {
13924            cx.propagate();
13925            return;
13926        }
13927        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13928        self.change_selections(Default::default(), window, cx, |s| {
13929            s.move_with(|map, selection| {
13930                selection.collapse_to(
13931                    movement::start_of_excerpt(
13932                        map,
13933                        selection.head(),
13934                        workspace::searchable::Direction::Prev,
13935                    ),
13936                    SelectionGoal::None,
13937                )
13938            });
13939        })
13940    }
13941
13942    pub fn move_to_start_of_next_excerpt(
13943        &mut self,
13944        _: &MoveToStartOfNextExcerpt,
13945        window: &mut Window,
13946        cx: &mut Context<Self>,
13947    ) {
13948        if matches!(self.mode, EditorMode::SingleLine) {
13949            cx.propagate();
13950            return;
13951        }
13952
13953        self.change_selections(Default::default(), window, cx, |s| {
13954            s.move_with(|map, selection| {
13955                selection.collapse_to(
13956                    movement::start_of_excerpt(
13957                        map,
13958                        selection.head(),
13959                        workspace::searchable::Direction::Next,
13960                    ),
13961                    SelectionGoal::None,
13962                )
13963            });
13964        })
13965    }
13966
13967    pub fn move_to_end_of_excerpt(
13968        &mut self,
13969        _: &MoveToEndOfExcerpt,
13970        window: &mut Window,
13971        cx: &mut Context<Self>,
13972    ) {
13973        if matches!(self.mode, EditorMode::SingleLine) {
13974            cx.propagate();
13975            return;
13976        }
13977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13978        self.change_selections(Default::default(), window, cx, |s| {
13979            s.move_with(|map, selection| {
13980                selection.collapse_to(
13981                    movement::end_of_excerpt(
13982                        map,
13983                        selection.head(),
13984                        workspace::searchable::Direction::Next,
13985                    ),
13986                    SelectionGoal::None,
13987                )
13988            });
13989        })
13990    }
13991
13992    pub fn move_to_end_of_previous_excerpt(
13993        &mut self,
13994        _: &MoveToEndOfPreviousExcerpt,
13995        window: &mut Window,
13996        cx: &mut Context<Self>,
13997    ) {
13998        if matches!(self.mode, EditorMode::SingleLine) {
13999            cx.propagate();
14000            return;
14001        }
14002        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14003        self.change_selections(Default::default(), window, cx, |s| {
14004            s.move_with(|map, selection| {
14005                selection.collapse_to(
14006                    movement::end_of_excerpt(
14007                        map,
14008                        selection.head(),
14009                        workspace::searchable::Direction::Prev,
14010                    ),
14011                    SelectionGoal::None,
14012                )
14013            });
14014        })
14015    }
14016
14017    pub fn select_to_start_of_excerpt(
14018        &mut self,
14019        _: &SelectToStartOfExcerpt,
14020        window: &mut Window,
14021        cx: &mut Context<Self>,
14022    ) {
14023        if matches!(self.mode, EditorMode::SingleLine) {
14024            cx.propagate();
14025            return;
14026        }
14027        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14028        self.change_selections(Default::default(), window, cx, |s| {
14029            s.move_heads_with(|map, head, _| {
14030                (
14031                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14032                    SelectionGoal::None,
14033                )
14034            });
14035        })
14036    }
14037
14038    pub fn select_to_start_of_next_excerpt(
14039        &mut self,
14040        _: &SelectToStartOfNextExcerpt,
14041        window: &mut Window,
14042        cx: &mut Context<Self>,
14043    ) {
14044        if matches!(self.mode, EditorMode::SingleLine) {
14045            cx.propagate();
14046            return;
14047        }
14048        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14049        self.change_selections(Default::default(), window, cx, |s| {
14050            s.move_heads_with(|map, head, _| {
14051                (
14052                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14053                    SelectionGoal::None,
14054                )
14055            });
14056        })
14057    }
14058
14059    pub fn select_to_end_of_excerpt(
14060        &mut self,
14061        _: &SelectToEndOfExcerpt,
14062        window: &mut Window,
14063        cx: &mut Context<Self>,
14064    ) {
14065        if matches!(self.mode, EditorMode::SingleLine) {
14066            cx.propagate();
14067            return;
14068        }
14069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14070        self.change_selections(Default::default(), window, cx, |s| {
14071            s.move_heads_with(|map, head, _| {
14072                (
14073                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14074                    SelectionGoal::None,
14075                )
14076            });
14077        })
14078    }
14079
14080    pub fn select_to_end_of_previous_excerpt(
14081        &mut self,
14082        _: &SelectToEndOfPreviousExcerpt,
14083        window: &mut Window,
14084        cx: &mut Context<Self>,
14085    ) {
14086        if matches!(self.mode, EditorMode::SingleLine) {
14087            cx.propagate();
14088            return;
14089        }
14090        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14091        self.change_selections(Default::default(), window, cx, |s| {
14092            s.move_heads_with(|map, head, _| {
14093                (
14094                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14095                    SelectionGoal::None,
14096                )
14097            });
14098        })
14099    }
14100
14101    pub fn move_to_beginning(
14102        &mut self,
14103        _: &MoveToBeginning,
14104        window: &mut Window,
14105        cx: &mut Context<Self>,
14106    ) {
14107        if matches!(self.mode, EditorMode::SingleLine) {
14108            cx.propagate();
14109            return;
14110        }
14111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14112        self.change_selections(Default::default(), window, cx, |s| {
14113            s.select_ranges(vec![0..0]);
14114        });
14115    }
14116
14117    pub fn select_to_beginning(
14118        &mut self,
14119        _: &SelectToBeginning,
14120        window: &mut Window,
14121        cx: &mut Context<Self>,
14122    ) {
14123        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14124        selection.set_head(Point::zero(), SelectionGoal::None);
14125        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14126        self.change_selections(Default::default(), window, cx, |s| {
14127            s.select(vec![selection]);
14128        });
14129    }
14130
14131    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14132        if matches!(self.mode, EditorMode::SingleLine) {
14133            cx.propagate();
14134            return;
14135        }
14136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14137        let cursor = self.buffer.read(cx).read(cx).len();
14138        self.change_selections(Default::default(), window, cx, |s| {
14139            s.select_ranges(vec![cursor..cursor])
14140        });
14141    }
14142
14143    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14144        self.nav_history = nav_history;
14145    }
14146
14147    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14148        self.nav_history.as_ref()
14149    }
14150
14151    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14152        self.push_to_nav_history(
14153            self.selections.newest_anchor().head(),
14154            None,
14155            false,
14156            true,
14157            cx,
14158        );
14159    }
14160
14161    fn push_to_nav_history(
14162        &mut self,
14163        cursor_anchor: Anchor,
14164        new_position: Option<Point>,
14165        is_deactivate: bool,
14166        always: bool,
14167        cx: &mut Context<Self>,
14168    ) {
14169        if let Some(nav_history) = self.nav_history.as_mut() {
14170            let buffer = self.buffer.read(cx).read(cx);
14171            let cursor_position = cursor_anchor.to_point(&buffer);
14172            let scroll_state = self.scroll_manager.anchor();
14173            let scroll_top_row = scroll_state.top_row(&buffer);
14174            drop(buffer);
14175
14176            if let Some(new_position) = new_position {
14177                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14178                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14179                    return;
14180                }
14181            }
14182
14183            nav_history.push(
14184                Some(NavigationData {
14185                    cursor_anchor,
14186                    cursor_position,
14187                    scroll_anchor: scroll_state,
14188                    scroll_top_row,
14189                }),
14190                cx,
14191            );
14192            cx.emit(EditorEvent::PushedToNavHistory {
14193                anchor: cursor_anchor,
14194                is_deactivate,
14195            })
14196        }
14197    }
14198
14199    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14200        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14201        let buffer = self.buffer.read(cx).snapshot(cx);
14202        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14203        selection.set_head(buffer.len(), SelectionGoal::None);
14204        self.change_selections(Default::default(), window, cx, |s| {
14205            s.select(vec![selection]);
14206        });
14207    }
14208
14209    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14210        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14211        let end = self.buffer.read(cx).read(cx).len();
14212        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14213            s.select_ranges(vec![0..end]);
14214        });
14215    }
14216
14217    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14218        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14219        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14220        let mut selections = self.selections.all::<Point>(&display_map);
14221        let max_point = display_map.buffer_snapshot().max_point();
14222        for selection in &mut selections {
14223            let rows = selection.spanned_rows(true, &display_map);
14224            selection.start = Point::new(rows.start.0, 0);
14225            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14226            selection.reversed = false;
14227        }
14228        self.change_selections(Default::default(), window, cx, |s| {
14229            s.select(selections);
14230        });
14231    }
14232
14233    pub fn split_selection_into_lines(
14234        &mut self,
14235        action: &SplitSelectionIntoLines,
14236        window: &mut Window,
14237        cx: &mut Context<Self>,
14238    ) {
14239        let selections = self
14240            .selections
14241            .all::<Point>(&self.display_snapshot(cx))
14242            .into_iter()
14243            .map(|selection| selection.start..selection.end)
14244            .collect::<Vec<_>>();
14245        self.unfold_ranges(&selections, true, true, cx);
14246
14247        let mut new_selection_ranges = Vec::new();
14248        {
14249            let buffer = self.buffer.read(cx).read(cx);
14250            for selection in selections {
14251                for row in selection.start.row..selection.end.row {
14252                    let line_start = Point::new(row, 0);
14253                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14254
14255                    if action.keep_selections {
14256                        // Keep the selection range for each line
14257                        let selection_start = if row == selection.start.row {
14258                            selection.start
14259                        } else {
14260                            line_start
14261                        };
14262                        new_selection_ranges.push(selection_start..line_end);
14263                    } else {
14264                        // Collapse to cursor at end of line
14265                        new_selection_ranges.push(line_end..line_end);
14266                    }
14267                }
14268
14269                let is_multiline_selection = selection.start.row != selection.end.row;
14270                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14271                // so this action feels more ergonomic when paired with other selection operations
14272                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14273                if !should_skip_last {
14274                    if action.keep_selections {
14275                        if is_multiline_selection {
14276                            let line_start = Point::new(selection.end.row, 0);
14277                            new_selection_ranges.push(line_start..selection.end);
14278                        } else {
14279                            new_selection_ranges.push(selection.start..selection.end);
14280                        }
14281                    } else {
14282                        new_selection_ranges.push(selection.end..selection.end);
14283                    }
14284                }
14285            }
14286        }
14287        self.change_selections(Default::default(), window, cx, |s| {
14288            s.select_ranges(new_selection_ranges);
14289        });
14290    }
14291
14292    pub fn add_selection_above(
14293        &mut self,
14294        action: &AddSelectionAbove,
14295        window: &mut Window,
14296        cx: &mut Context<Self>,
14297    ) {
14298        self.add_selection(true, action.skip_soft_wrap, window, cx);
14299    }
14300
14301    pub fn add_selection_below(
14302        &mut self,
14303        action: &AddSelectionBelow,
14304        window: &mut Window,
14305        cx: &mut Context<Self>,
14306    ) {
14307        self.add_selection(false, action.skip_soft_wrap, window, cx);
14308    }
14309
14310    fn add_selection(
14311        &mut self,
14312        above: bool,
14313        skip_soft_wrap: bool,
14314        window: &mut Window,
14315        cx: &mut Context<Self>,
14316    ) {
14317        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14318
14319        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14320        let all_selections = self.selections.all::<Point>(&display_map);
14321        let text_layout_details = self.text_layout_details(window);
14322
14323        let (mut columnar_selections, new_selections_to_columnarize) = {
14324            if let Some(state) = self.add_selections_state.as_ref() {
14325                let columnar_selection_ids: HashSet<_> = state
14326                    .groups
14327                    .iter()
14328                    .flat_map(|group| group.stack.iter())
14329                    .copied()
14330                    .collect();
14331
14332                all_selections
14333                    .into_iter()
14334                    .partition(|s| columnar_selection_ids.contains(&s.id))
14335            } else {
14336                (Vec::new(), all_selections)
14337            }
14338        };
14339
14340        let mut state = self
14341            .add_selections_state
14342            .take()
14343            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14344
14345        for selection in new_selections_to_columnarize {
14346            let range = selection.display_range(&display_map).sorted();
14347            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14348            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14349            let positions = start_x.min(end_x)..start_x.max(end_x);
14350            let mut stack = Vec::new();
14351            for row in range.start.row().0..=range.end.row().0 {
14352                if let Some(selection) = self.selections.build_columnar_selection(
14353                    &display_map,
14354                    DisplayRow(row),
14355                    &positions,
14356                    selection.reversed,
14357                    &text_layout_details,
14358                ) {
14359                    stack.push(selection.id);
14360                    columnar_selections.push(selection);
14361                }
14362            }
14363            if !stack.is_empty() {
14364                if above {
14365                    stack.reverse();
14366                }
14367                state.groups.push(AddSelectionsGroup { above, stack });
14368            }
14369        }
14370
14371        let mut final_selections = Vec::new();
14372        let end_row = if above {
14373            DisplayRow(0)
14374        } else {
14375            display_map.max_point().row()
14376        };
14377
14378        let mut last_added_item_per_group = HashMap::default();
14379        for group in state.groups.iter_mut() {
14380            if let Some(last_id) = group.stack.last() {
14381                last_added_item_per_group.insert(*last_id, group);
14382            }
14383        }
14384
14385        for selection in columnar_selections {
14386            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14387                if above == group.above {
14388                    let range = selection.display_range(&display_map).sorted();
14389                    debug_assert_eq!(range.start.row(), range.end.row());
14390                    let mut row = range.start.row();
14391                    let positions =
14392                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14393                            Pixels::from(start)..Pixels::from(end)
14394                        } else {
14395                            let start_x =
14396                                display_map.x_for_display_point(range.start, &text_layout_details);
14397                            let end_x =
14398                                display_map.x_for_display_point(range.end, &text_layout_details);
14399                            start_x.min(end_x)..start_x.max(end_x)
14400                        };
14401
14402                    let mut maybe_new_selection = None;
14403                    let direction = if above { -1 } else { 1 };
14404
14405                    while row != end_row {
14406                        if skip_soft_wrap {
14407                            row = display_map
14408                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14409                                .row();
14410                        } else if above {
14411                            row.0 -= 1;
14412                        } else {
14413                            row.0 += 1;
14414                        }
14415
14416                        if let Some(new_selection) = self.selections.build_columnar_selection(
14417                            &display_map,
14418                            row,
14419                            &positions,
14420                            selection.reversed,
14421                            &text_layout_details,
14422                        ) {
14423                            maybe_new_selection = Some(new_selection);
14424                            break;
14425                        }
14426                    }
14427
14428                    if let Some(new_selection) = maybe_new_selection {
14429                        group.stack.push(new_selection.id);
14430                        if above {
14431                            final_selections.push(new_selection);
14432                            final_selections.push(selection);
14433                        } else {
14434                            final_selections.push(selection);
14435                            final_selections.push(new_selection);
14436                        }
14437                    } else {
14438                        final_selections.push(selection);
14439                    }
14440                } else {
14441                    group.stack.pop();
14442                }
14443            } else {
14444                final_selections.push(selection);
14445            }
14446        }
14447
14448        self.change_selections(Default::default(), window, cx, |s| {
14449            s.select(final_selections);
14450        });
14451
14452        let final_selection_ids: HashSet<_> = self
14453            .selections
14454            .all::<Point>(&display_map)
14455            .iter()
14456            .map(|s| s.id)
14457            .collect();
14458        state.groups.retain_mut(|group| {
14459            // selections might get merged above so we remove invalid items from stacks
14460            group.stack.retain(|id| final_selection_ids.contains(id));
14461
14462            // single selection in stack can be treated as initial state
14463            group.stack.len() > 1
14464        });
14465
14466        if !state.groups.is_empty() {
14467            self.add_selections_state = Some(state);
14468        }
14469    }
14470
14471    fn select_match_ranges(
14472        &mut self,
14473        range: Range<usize>,
14474        reversed: bool,
14475        replace_newest: bool,
14476        auto_scroll: Option<Autoscroll>,
14477        window: &mut Window,
14478        cx: &mut Context<Editor>,
14479    ) {
14480        self.unfold_ranges(
14481            std::slice::from_ref(&range),
14482            false,
14483            auto_scroll.is_some(),
14484            cx,
14485        );
14486        let effects = if let Some(scroll) = auto_scroll {
14487            SelectionEffects::scroll(scroll)
14488        } else {
14489            SelectionEffects::no_scroll()
14490        };
14491        self.change_selections(effects, window, cx, |s| {
14492            if replace_newest {
14493                s.delete(s.newest_anchor().id);
14494            }
14495            if reversed {
14496                s.insert_range(range.end..range.start);
14497            } else {
14498                s.insert_range(range);
14499            }
14500        });
14501    }
14502
14503    pub fn select_next_match_internal(
14504        &mut self,
14505        display_map: &DisplaySnapshot,
14506        replace_newest: bool,
14507        autoscroll: Option<Autoscroll>,
14508        window: &mut Window,
14509        cx: &mut Context<Self>,
14510    ) -> Result<()> {
14511        let buffer = display_map.buffer_snapshot();
14512        let mut selections = self.selections.all::<usize>(&display_map);
14513        if let Some(mut select_next_state) = self.select_next_state.take() {
14514            let query = &select_next_state.query;
14515            if !select_next_state.done {
14516                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14517                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14518                let mut next_selected_range = None;
14519
14520                // Collect and sort selection ranges for efficient overlap checking
14521                let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect();
14522                selection_ranges.sort_by_key(|r| r.start);
14523
14524                let bytes_after_last_selection =
14525                    buffer.bytes_in_range(last_selection.end..buffer.len());
14526                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14527                let query_matches = query
14528                    .stream_find_iter(bytes_after_last_selection)
14529                    .map(|result| (last_selection.end, result))
14530                    .chain(
14531                        query
14532                            .stream_find_iter(bytes_before_first_selection)
14533                            .map(|result| (0, result)),
14534                    );
14535
14536                for (start_offset, query_match) in query_matches {
14537                    let query_match = query_match.unwrap(); // can only fail due to I/O
14538                    let offset_range =
14539                        start_offset + query_match.start()..start_offset + query_match.end();
14540
14541                    if !select_next_state.wordwise
14542                        || (!buffer.is_inside_word(offset_range.start, None)
14543                            && !buffer.is_inside_word(offset_range.end, None))
14544                    {
14545                        // Use binary search to check for overlap (O(log n))
14546                        let overlaps = selection_ranges
14547                            .binary_search_by(|range| {
14548                                if range.end <= offset_range.start {
14549                                    std::cmp::Ordering::Less
14550                                } else if range.start >= offset_range.end {
14551                                    std::cmp::Ordering::Greater
14552                                } else {
14553                                    std::cmp::Ordering::Equal
14554                                }
14555                            })
14556                            .is_ok();
14557
14558                        if !overlaps {
14559                            next_selected_range = Some(offset_range);
14560                            break;
14561                        }
14562                    }
14563                }
14564
14565                if let Some(next_selected_range) = next_selected_range {
14566                    self.select_match_ranges(
14567                        next_selected_range,
14568                        last_selection.reversed,
14569                        replace_newest,
14570                        autoscroll,
14571                        window,
14572                        cx,
14573                    );
14574                } else {
14575                    select_next_state.done = true;
14576                }
14577            }
14578
14579            self.select_next_state = Some(select_next_state);
14580        } else {
14581            let mut only_carets = true;
14582            let mut same_text_selected = true;
14583            let mut selected_text = None;
14584
14585            let mut selections_iter = selections.iter().peekable();
14586            while let Some(selection) = selections_iter.next() {
14587                if selection.start != selection.end {
14588                    only_carets = false;
14589                }
14590
14591                if same_text_selected {
14592                    if selected_text.is_none() {
14593                        selected_text =
14594                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14595                    }
14596
14597                    if let Some(next_selection) = selections_iter.peek() {
14598                        if next_selection.range().len() == selection.range().len() {
14599                            let next_selected_text = buffer
14600                                .text_for_range(next_selection.range())
14601                                .collect::<String>();
14602                            if Some(next_selected_text) != selected_text {
14603                                same_text_selected = false;
14604                                selected_text = None;
14605                            }
14606                        } else {
14607                            same_text_selected = false;
14608                            selected_text = None;
14609                        }
14610                    }
14611                }
14612            }
14613
14614            if only_carets {
14615                for selection in &mut selections {
14616                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14617                    selection.start = word_range.start;
14618                    selection.end = word_range.end;
14619                    selection.goal = SelectionGoal::None;
14620                    selection.reversed = false;
14621                    self.select_match_ranges(
14622                        selection.start..selection.end,
14623                        selection.reversed,
14624                        replace_newest,
14625                        autoscroll,
14626                        window,
14627                        cx,
14628                    );
14629                }
14630
14631                if selections.len() == 1 {
14632                    let selection = selections
14633                        .last()
14634                        .expect("ensured that there's only one selection");
14635                    let query = buffer
14636                        .text_for_range(selection.start..selection.end)
14637                        .collect::<String>();
14638                    let is_empty = query.is_empty();
14639                    let select_state = SelectNextState {
14640                        query: AhoCorasick::new(&[query])?,
14641                        wordwise: true,
14642                        done: is_empty,
14643                    };
14644                    self.select_next_state = Some(select_state);
14645                } else {
14646                    self.select_next_state = None;
14647                }
14648            } else if let Some(selected_text) = selected_text {
14649                self.select_next_state = Some(SelectNextState {
14650                    query: AhoCorasick::new(&[selected_text])?,
14651                    wordwise: false,
14652                    done: false,
14653                });
14654                self.select_next_match_internal(
14655                    display_map,
14656                    replace_newest,
14657                    autoscroll,
14658                    window,
14659                    cx,
14660                )?;
14661            }
14662        }
14663        Ok(())
14664    }
14665
14666    pub fn select_all_matches(
14667        &mut self,
14668        _action: &SelectAllMatches,
14669        window: &mut Window,
14670        cx: &mut Context<Self>,
14671    ) -> Result<()> {
14672        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14673
14674        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14675
14676        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14677        let Some(select_next_state) = self.select_next_state.as_mut() else {
14678            return Ok(());
14679        };
14680        if select_next_state.done {
14681            return Ok(());
14682        }
14683
14684        let mut new_selections = Vec::new();
14685
14686        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14687        let buffer = display_map.buffer_snapshot();
14688        let query_matches = select_next_state
14689            .query
14690            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14691
14692        for query_match in query_matches.into_iter() {
14693            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14694            let offset_range = if reversed {
14695                query_match.end()..query_match.start()
14696            } else {
14697                query_match.start()..query_match.end()
14698            };
14699
14700            if !select_next_state.wordwise
14701                || (!buffer.is_inside_word(offset_range.start, None)
14702                    && !buffer.is_inside_word(offset_range.end, None))
14703            {
14704                new_selections.push(offset_range.start..offset_range.end);
14705            }
14706        }
14707
14708        select_next_state.done = true;
14709
14710        if new_selections.is_empty() {
14711            log::error!("bug: new_selections is empty in select_all_matches");
14712            return Ok(());
14713        }
14714
14715        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14716        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14717            selections.select_ranges(new_selections)
14718        });
14719
14720        Ok(())
14721    }
14722
14723    pub fn select_next(
14724        &mut self,
14725        action: &SelectNext,
14726        window: &mut Window,
14727        cx: &mut Context<Self>,
14728    ) -> Result<()> {
14729        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14730        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14731        self.select_next_match_internal(
14732            &display_map,
14733            action.replace_newest,
14734            Some(Autoscroll::newest()),
14735            window,
14736            cx,
14737        )?;
14738        Ok(())
14739    }
14740
14741    pub fn select_previous(
14742        &mut self,
14743        action: &SelectPrevious,
14744        window: &mut Window,
14745        cx: &mut Context<Self>,
14746    ) -> Result<()> {
14747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14748        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14749        let buffer = display_map.buffer_snapshot();
14750        let mut selections = self.selections.all::<usize>(&display_map);
14751        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14752            let query = &select_prev_state.query;
14753            if !select_prev_state.done {
14754                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14755                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14756                let mut next_selected_range = None;
14757                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14758                let bytes_before_last_selection =
14759                    buffer.reversed_bytes_in_range(0..last_selection.start);
14760                let bytes_after_first_selection =
14761                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14762                let query_matches = query
14763                    .stream_find_iter(bytes_before_last_selection)
14764                    .map(|result| (last_selection.start, result))
14765                    .chain(
14766                        query
14767                            .stream_find_iter(bytes_after_first_selection)
14768                            .map(|result| (buffer.len(), result)),
14769                    );
14770                for (end_offset, query_match) in query_matches {
14771                    let query_match = query_match.unwrap(); // can only fail due to I/O
14772                    let offset_range =
14773                        end_offset - query_match.end()..end_offset - query_match.start();
14774
14775                    if !select_prev_state.wordwise
14776                        || (!buffer.is_inside_word(offset_range.start, None)
14777                            && !buffer.is_inside_word(offset_range.end, None))
14778                    {
14779                        next_selected_range = Some(offset_range);
14780                        break;
14781                    }
14782                }
14783
14784                if let Some(next_selected_range) = next_selected_range {
14785                    self.select_match_ranges(
14786                        next_selected_range,
14787                        last_selection.reversed,
14788                        action.replace_newest,
14789                        Some(Autoscroll::newest()),
14790                        window,
14791                        cx,
14792                    );
14793                } else {
14794                    select_prev_state.done = true;
14795                }
14796            }
14797
14798            self.select_prev_state = Some(select_prev_state);
14799        } else {
14800            let mut only_carets = true;
14801            let mut same_text_selected = true;
14802            let mut selected_text = None;
14803
14804            let mut selections_iter = selections.iter().peekable();
14805            while let Some(selection) = selections_iter.next() {
14806                if selection.start != selection.end {
14807                    only_carets = false;
14808                }
14809
14810                if same_text_selected {
14811                    if selected_text.is_none() {
14812                        selected_text =
14813                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14814                    }
14815
14816                    if let Some(next_selection) = selections_iter.peek() {
14817                        if next_selection.range().len() == selection.range().len() {
14818                            let next_selected_text = buffer
14819                                .text_for_range(next_selection.range())
14820                                .collect::<String>();
14821                            if Some(next_selected_text) != selected_text {
14822                                same_text_selected = false;
14823                                selected_text = None;
14824                            }
14825                        } else {
14826                            same_text_selected = false;
14827                            selected_text = None;
14828                        }
14829                    }
14830                }
14831            }
14832
14833            if only_carets {
14834                for selection in &mut selections {
14835                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14836                    selection.start = word_range.start;
14837                    selection.end = word_range.end;
14838                    selection.goal = SelectionGoal::None;
14839                    selection.reversed = false;
14840                    self.select_match_ranges(
14841                        selection.start..selection.end,
14842                        selection.reversed,
14843                        action.replace_newest,
14844                        Some(Autoscroll::newest()),
14845                        window,
14846                        cx,
14847                    );
14848                }
14849                if selections.len() == 1 {
14850                    let selection = selections
14851                        .last()
14852                        .expect("ensured that there's only one selection");
14853                    let query = buffer
14854                        .text_for_range(selection.start..selection.end)
14855                        .collect::<String>();
14856                    let is_empty = query.is_empty();
14857                    let select_state = SelectNextState {
14858                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14859                        wordwise: true,
14860                        done: is_empty,
14861                    };
14862                    self.select_prev_state = Some(select_state);
14863                } else {
14864                    self.select_prev_state = None;
14865                }
14866            } else if let Some(selected_text) = selected_text {
14867                self.select_prev_state = Some(SelectNextState {
14868                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14869                    wordwise: false,
14870                    done: false,
14871                });
14872                self.select_previous(action, window, cx)?;
14873            }
14874        }
14875        Ok(())
14876    }
14877
14878    pub fn find_next_match(
14879        &mut self,
14880        _: &FindNextMatch,
14881        window: &mut Window,
14882        cx: &mut Context<Self>,
14883    ) -> Result<()> {
14884        let selections = self.selections.disjoint_anchors_arc();
14885        match selections.first() {
14886            Some(first) if selections.len() >= 2 => {
14887                self.change_selections(Default::default(), window, cx, |s| {
14888                    s.select_ranges([first.range()]);
14889                });
14890            }
14891            _ => self.select_next(
14892                &SelectNext {
14893                    replace_newest: true,
14894                },
14895                window,
14896                cx,
14897            )?,
14898        }
14899        Ok(())
14900    }
14901
14902    pub fn find_previous_match(
14903        &mut self,
14904        _: &FindPreviousMatch,
14905        window: &mut Window,
14906        cx: &mut Context<Self>,
14907    ) -> Result<()> {
14908        let selections = self.selections.disjoint_anchors_arc();
14909        match selections.last() {
14910            Some(last) if selections.len() >= 2 => {
14911                self.change_selections(Default::default(), window, cx, |s| {
14912                    s.select_ranges([last.range()]);
14913                });
14914            }
14915            _ => self.select_previous(
14916                &SelectPrevious {
14917                    replace_newest: true,
14918                },
14919                window,
14920                cx,
14921            )?,
14922        }
14923        Ok(())
14924    }
14925
14926    pub fn toggle_comments(
14927        &mut self,
14928        action: &ToggleComments,
14929        window: &mut Window,
14930        cx: &mut Context<Self>,
14931    ) {
14932        if self.read_only(cx) {
14933            return;
14934        }
14935        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14936        let text_layout_details = &self.text_layout_details(window);
14937        self.transact(window, cx, |this, window, cx| {
14938            let mut selections = this
14939                .selections
14940                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14941            let mut edits = Vec::new();
14942            let mut selection_edit_ranges = Vec::new();
14943            let mut last_toggled_row = None;
14944            let snapshot = this.buffer.read(cx).read(cx);
14945            let empty_str: Arc<str> = Arc::default();
14946            let mut suffixes_inserted = Vec::new();
14947            let ignore_indent = action.ignore_indent;
14948
14949            fn comment_prefix_range(
14950                snapshot: &MultiBufferSnapshot,
14951                row: MultiBufferRow,
14952                comment_prefix: &str,
14953                comment_prefix_whitespace: &str,
14954                ignore_indent: bool,
14955            ) -> Range<Point> {
14956                let indent_size = if ignore_indent {
14957                    0
14958                } else {
14959                    snapshot.indent_size_for_line(row).len
14960                };
14961
14962                let start = Point::new(row.0, indent_size);
14963
14964                let mut line_bytes = snapshot
14965                    .bytes_in_range(start..snapshot.max_point())
14966                    .flatten()
14967                    .copied();
14968
14969                // If this line currently begins with the line comment prefix, then record
14970                // the range containing the prefix.
14971                if line_bytes
14972                    .by_ref()
14973                    .take(comment_prefix.len())
14974                    .eq(comment_prefix.bytes())
14975                {
14976                    // Include any whitespace that matches the comment prefix.
14977                    let matching_whitespace_len = line_bytes
14978                        .zip(comment_prefix_whitespace.bytes())
14979                        .take_while(|(a, b)| a == b)
14980                        .count() as u32;
14981                    let end = Point::new(
14982                        start.row,
14983                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14984                    );
14985                    start..end
14986                } else {
14987                    start..start
14988                }
14989            }
14990
14991            fn comment_suffix_range(
14992                snapshot: &MultiBufferSnapshot,
14993                row: MultiBufferRow,
14994                comment_suffix: &str,
14995                comment_suffix_has_leading_space: bool,
14996            ) -> Range<Point> {
14997                let end = Point::new(row.0, snapshot.line_len(row));
14998                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14999
15000                let mut line_end_bytes = snapshot
15001                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15002                    .flatten()
15003                    .copied();
15004
15005                let leading_space_len = if suffix_start_column > 0
15006                    && line_end_bytes.next() == Some(b' ')
15007                    && comment_suffix_has_leading_space
15008                {
15009                    1
15010                } else {
15011                    0
15012                };
15013
15014                // If this line currently begins with the line comment prefix, then record
15015                // the range containing the prefix.
15016                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15017                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15018                    start..end
15019                } else {
15020                    end..end
15021                }
15022            }
15023
15024            // TODO: Handle selections that cross excerpts
15025            for selection in &mut selections {
15026                let start_column = snapshot
15027                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15028                    .len;
15029                let language = if let Some(language) =
15030                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15031                {
15032                    language
15033                } else {
15034                    continue;
15035                };
15036
15037                selection_edit_ranges.clear();
15038
15039                // If multiple selections contain a given row, avoid processing that
15040                // row more than once.
15041                let mut start_row = MultiBufferRow(selection.start.row);
15042                if last_toggled_row == Some(start_row) {
15043                    start_row = start_row.next_row();
15044                }
15045                let end_row =
15046                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15047                        MultiBufferRow(selection.end.row - 1)
15048                    } else {
15049                        MultiBufferRow(selection.end.row)
15050                    };
15051                last_toggled_row = Some(end_row);
15052
15053                if start_row > end_row {
15054                    continue;
15055                }
15056
15057                // If the language has line comments, toggle those.
15058                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15059
15060                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15061                if ignore_indent {
15062                    full_comment_prefixes = full_comment_prefixes
15063                        .into_iter()
15064                        .map(|s| Arc::from(s.trim_end()))
15065                        .collect();
15066                }
15067
15068                if !full_comment_prefixes.is_empty() {
15069                    let first_prefix = full_comment_prefixes
15070                        .first()
15071                        .expect("prefixes is non-empty");
15072                    let prefix_trimmed_lengths = full_comment_prefixes
15073                        .iter()
15074                        .map(|p| p.trim_end_matches(' ').len())
15075                        .collect::<SmallVec<[usize; 4]>>();
15076
15077                    let mut all_selection_lines_are_comments = true;
15078
15079                    for row in start_row.0..=end_row.0 {
15080                        let row = MultiBufferRow(row);
15081                        if start_row < end_row && snapshot.is_line_blank(row) {
15082                            continue;
15083                        }
15084
15085                        let prefix_range = full_comment_prefixes
15086                            .iter()
15087                            .zip(prefix_trimmed_lengths.iter().copied())
15088                            .map(|(prefix, trimmed_prefix_len)| {
15089                                comment_prefix_range(
15090                                    snapshot.deref(),
15091                                    row,
15092                                    &prefix[..trimmed_prefix_len],
15093                                    &prefix[trimmed_prefix_len..],
15094                                    ignore_indent,
15095                                )
15096                            })
15097                            .max_by_key(|range| range.end.column - range.start.column)
15098                            .expect("prefixes is non-empty");
15099
15100                        if prefix_range.is_empty() {
15101                            all_selection_lines_are_comments = false;
15102                        }
15103
15104                        selection_edit_ranges.push(prefix_range);
15105                    }
15106
15107                    if all_selection_lines_are_comments {
15108                        edits.extend(
15109                            selection_edit_ranges
15110                                .iter()
15111                                .cloned()
15112                                .map(|range| (range, empty_str.clone())),
15113                        );
15114                    } else {
15115                        let min_column = selection_edit_ranges
15116                            .iter()
15117                            .map(|range| range.start.column)
15118                            .min()
15119                            .unwrap_or(0);
15120                        edits.extend(selection_edit_ranges.iter().map(|range| {
15121                            let position = Point::new(range.start.row, min_column);
15122                            (position..position, first_prefix.clone())
15123                        }));
15124                    }
15125                } else if let Some(BlockCommentConfig {
15126                    start: full_comment_prefix,
15127                    end: comment_suffix,
15128                    ..
15129                }) = language.block_comment()
15130                {
15131                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15132                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15133                    let prefix_range = comment_prefix_range(
15134                        snapshot.deref(),
15135                        start_row,
15136                        comment_prefix,
15137                        comment_prefix_whitespace,
15138                        ignore_indent,
15139                    );
15140                    let suffix_range = comment_suffix_range(
15141                        snapshot.deref(),
15142                        end_row,
15143                        comment_suffix.trim_start_matches(' '),
15144                        comment_suffix.starts_with(' '),
15145                    );
15146
15147                    if prefix_range.is_empty() || suffix_range.is_empty() {
15148                        edits.push((
15149                            prefix_range.start..prefix_range.start,
15150                            full_comment_prefix.clone(),
15151                        ));
15152                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15153                        suffixes_inserted.push((end_row, comment_suffix.len()));
15154                    } else {
15155                        edits.push((prefix_range, empty_str.clone()));
15156                        edits.push((suffix_range, empty_str.clone()));
15157                    }
15158                } else {
15159                    continue;
15160                }
15161            }
15162
15163            drop(snapshot);
15164            this.buffer.update(cx, |buffer, cx| {
15165                buffer.edit(edits, None, cx);
15166            });
15167
15168            // Adjust selections so that they end before any comment suffixes that
15169            // were inserted.
15170            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15171            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15172            let snapshot = this.buffer.read(cx).read(cx);
15173            for selection in &mut selections {
15174                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15175                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15176                        Ordering::Less => {
15177                            suffixes_inserted.next();
15178                            continue;
15179                        }
15180                        Ordering::Greater => break,
15181                        Ordering::Equal => {
15182                            if selection.end.column == snapshot.line_len(row) {
15183                                if selection.is_empty() {
15184                                    selection.start.column -= suffix_len as u32;
15185                                }
15186                                selection.end.column -= suffix_len as u32;
15187                            }
15188                            break;
15189                        }
15190                    }
15191                }
15192            }
15193
15194            drop(snapshot);
15195            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15196
15197            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15198            let selections_on_single_row = selections.windows(2).all(|selections| {
15199                selections[0].start.row == selections[1].start.row
15200                    && selections[0].end.row == selections[1].end.row
15201                    && selections[0].start.row == selections[0].end.row
15202            });
15203            let selections_selecting = selections
15204                .iter()
15205                .any(|selection| selection.start != selection.end);
15206            let advance_downwards = action.advance_downwards
15207                && selections_on_single_row
15208                && !selections_selecting
15209                && !matches!(this.mode, EditorMode::SingleLine);
15210
15211            if advance_downwards {
15212                let snapshot = this.buffer.read(cx).snapshot(cx);
15213
15214                this.change_selections(Default::default(), window, cx, |s| {
15215                    s.move_cursors_with(|display_snapshot, display_point, _| {
15216                        let mut point = display_point.to_point(display_snapshot);
15217                        point.row += 1;
15218                        point = snapshot.clip_point(point, Bias::Left);
15219                        let display_point = point.to_display_point(display_snapshot);
15220                        let goal = SelectionGoal::HorizontalPosition(
15221                            display_snapshot
15222                                .x_for_display_point(display_point, text_layout_details)
15223                                .into(),
15224                        );
15225                        (display_point, goal)
15226                    })
15227                });
15228            }
15229        });
15230    }
15231
15232    pub fn select_enclosing_symbol(
15233        &mut self,
15234        _: &SelectEnclosingSymbol,
15235        window: &mut Window,
15236        cx: &mut Context<Self>,
15237    ) {
15238        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15239
15240        let buffer = self.buffer.read(cx).snapshot(cx);
15241        let old_selections = self
15242            .selections
15243            .all::<usize>(&self.display_snapshot(cx))
15244            .into_boxed_slice();
15245
15246        fn update_selection(
15247            selection: &Selection<usize>,
15248            buffer_snap: &MultiBufferSnapshot,
15249        ) -> Option<Selection<usize>> {
15250            let cursor = selection.head();
15251            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15252            for symbol in symbols.iter().rev() {
15253                let start = symbol.range.start.to_offset(buffer_snap);
15254                let end = symbol.range.end.to_offset(buffer_snap);
15255                let new_range = start..end;
15256                if start < selection.start || end > selection.end {
15257                    return Some(Selection {
15258                        id: selection.id,
15259                        start: new_range.start,
15260                        end: new_range.end,
15261                        goal: SelectionGoal::None,
15262                        reversed: selection.reversed,
15263                    });
15264                }
15265            }
15266            None
15267        }
15268
15269        let mut selected_larger_symbol = false;
15270        let new_selections = old_selections
15271            .iter()
15272            .map(|selection| match update_selection(selection, &buffer) {
15273                Some(new_selection) => {
15274                    if new_selection.range() != selection.range() {
15275                        selected_larger_symbol = true;
15276                    }
15277                    new_selection
15278                }
15279                None => selection.clone(),
15280            })
15281            .collect::<Vec<_>>();
15282
15283        if selected_larger_symbol {
15284            self.change_selections(Default::default(), window, cx, |s| {
15285                s.select(new_selections);
15286            });
15287        }
15288    }
15289
15290    pub fn select_larger_syntax_node(
15291        &mut self,
15292        _: &SelectLargerSyntaxNode,
15293        window: &mut Window,
15294        cx: &mut Context<Self>,
15295    ) {
15296        let Some(visible_row_count) = self.visible_row_count() else {
15297            return;
15298        };
15299        let old_selections: Box<[_]> = self
15300            .selections
15301            .all::<usize>(&self.display_snapshot(cx))
15302            .into();
15303        if old_selections.is_empty() {
15304            return;
15305        }
15306
15307        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15308
15309        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15310        let buffer = self.buffer.read(cx).snapshot(cx);
15311
15312        let mut selected_larger_node = false;
15313        let mut new_selections = old_selections
15314            .iter()
15315            .map(|selection| {
15316                let old_range = selection.start..selection.end;
15317
15318                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15319                    // manually select word at selection
15320                    if ["string_content", "inline"].contains(&node.kind()) {
15321                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15322                        // ignore if word is already selected
15323                        if !word_range.is_empty() && old_range != word_range {
15324                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15325                            // only select word if start and end point belongs to same word
15326                            if word_range == last_word_range {
15327                                selected_larger_node = true;
15328                                return Selection {
15329                                    id: selection.id,
15330                                    start: word_range.start,
15331                                    end: word_range.end,
15332                                    goal: SelectionGoal::None,
15333                                    reversed: selection.reversed,
15334                                };
15335                            }
15336                        }
15337                    }
15338                }
15339
15340                let mut new_range = old_range.clone();
15341                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15342                    new_range = range;
15343                    if !node.is_named() {
15344                        continue;
15345                    }
15346                    if !display_map.intersects_fold(new_range.start)
15347                        && !display_map.intersects_fold(new_range.end)
15348                    {
15349                        break;
15350                    }
15351                }
15352
15353                selected_larger_node |= new_range != old_range;
15354                Selection {
15355                    id: selection.id,
15356                    start: new_range.start,
15357                    end: new_range.end,
15358                    goal: SelectionGoal::None,
15359                    reversed: selection.reversed,
15360                }
15361            })
15362            .collect::<Vec<_>>();
15363
15364        if !selected_larger_node {
15365            return; // don't put this call in the history
15366        }
15367
15368        // scroll based on transformation done to the last selection created by the user
15369        let (last_old, last_new) = old_selections
15370            .last()
15371            .zip(new_selections.last().cloned())
15372            .expect("old_selections isn't empty");
15373
15374        // revert selection
15375        let is_selection_reversed = {
15376            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15377            new_selections.last_mut().expect("checked above").reversed =
15378                should_newest_selection_be_reversed;
15379            should_newest_selection_be_reversed
15380        };
15381
15382        if selected_larger_node {
15383            self.select_syntax_node_history.disable_clearing = true;
15384            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15385                s.select(new_selections.clone());
15386            });
15387            self.select_syntax_node_history.disable_clearing = false;
15388        }
15389
15390        let start_row = last_new.start.to_display_point(&display_map).row().0;
15391        let end_row = last_new.end.to_display_point(&display_map).row().0;
15392        let selection_height = end_row - start_row + 1;
15393        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15394
15395        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15396        let scroll_behavior = if fits_on_the_screen {
15397            self.request_autoscroll(Autoscroll::fit(), cx);
15398            SelectSyntaxNodeScrollBehavior::FitSelection
15399        } else if is_selection_reversed {
15400            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15401            SelectSyntaxNodeScrollBehavior::CursorTop
15402        } else {
15403            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15404            SelectSyntaxNodeScrollBehavior::CursorBottom
15405        };
15406
15407        self.select_syntax_node_history.push((
15408            old_selections,
15409            scroll_behavior,
15410            is_selection_reversed,
15411        ));
15412    }
15413
15414    pub fn select_smaller_syntax_node(
15415        &mut self,
15416        _: &SelectSmallerSyntaxNode,
15417        window: &mut Window,
15418        cx: &mut Context<Self>,
15419    ) {
15420        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15421
15422        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15423            self.select_syntax_node_history.pop()
15424        {
15425            if let Some(selection) = selections.last_mut() {
15426                selection.reversed = is_selection_reversed;
15427            }
15428
15429            self.select_syntax_node_history.disable_clearing = true;
15430            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15431                s.select(selections.to_vec());
15432            });
15433            self.select_syntax_node_history.disable_clearing = false;
15434
15435            match scroll_behavior {
15436                SelectSyntaxNodeScrollBehavior::CursorTop => {
15437                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15438                }
15439                SelectSyntaxNodeScrollBehavior::FitSelection => {
15440                    self.request_autoscroll(Autoscroll::fit(), cx);
15441                }
15442                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15443                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15444                }
15445            }
15446        }
15447    }
15448
15449    pub fn unwrap_syntax_node(
15450        &mut self,
15451        _: &UnwrapSyntaxNode,
15452        window: &mut Window,
15453        cx: &mut Context<Self>,
15454    ) {
15455        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15456
15457        let buffer = self.buffer.read(cx).snapshot(cx);
15458        let selections = self
15459            .selections
15460            .all::<usize>(&self.display_snapshot(cx))
15461            .into_iter()
15462            // subtracting the offset requires sorting
15463            .sorted_by_key(|i| i.start);
15464
15465        let full_edits = selections
15466            .into_iter()
15467            .filter_map(|selection| {
15468                let child = if selection.is_empty()
15469                    && let Some((_, ancestor_range)) =
15470                        buffer.syntax_ancestor(selection.start..selection.end)
15471                {
15472                    ancestor_range
15473                } else {
15474                    selection.range()
15475                };
15476
15477                let mut parent = child.clone();
15478                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15479                    parent = ancestor_range;
15480                    if parent.start < child.start || parent.end > child.end {
15481                        break;
15482                    }
15483                }
15484
15485                if parent == child {
15486                    return None;
15487                }
15488                let text = buffer.text_for_range(child).collect::<String>();
15489                Some((selection.id, parent, text))
15490            })
15491            .collect::<Vec<_>>();
15492        if full_edits.is_empty() {
15493            return;
15494        }
15495
15496        self.transact(window, cx, |this, window, cx| {
15497            this.buffer.update(cx, |buffer, cx| {
15498                buffer.edit(
15499                    full_edits
15500                        .iter()
15501                        .map(|(_, p, t)| (p.clone(), t.clone()))
15502                        .collect::<Vec<_>>(),
15503                    None,
15504                    cx,
15505                );
15506            });
15507            this.change_selections(Default::default(), window, cx, |s| {
15508                let mut offset = 0;
15509                let mut selections = vec![];
15510                for (id, parent, text) in full_edits {
15511                    let start = parent.start - offset;
15512                    offset += parent.len() - text.len();
15513                    selections.push(Selection {
15514                        id,
15515                        start,
15516                        end: start + text.len(),
15517                        reversed: false,
15518                        goal: Default::default(),
15519                    });
15520                }
15521                s.select(selections);
15522            });
15523        });
15524    }
15525
15526    pub fn select_next_syntax_node(
15527        &mut self,
15528        _: &SelectNextSyntaxNode,
15529        window: &mut Window,
15530        cx: &mut Context<Self>,
15531    ) {
15532        let old_selections: Box<[_]> = self
15533            .selections
15534            .all::<usize>(&self.display_snapshot(cx))
15535            .into();
15536        if old_selections.is_empty() {
15537            return;
15538        }
15539
15540        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15541
15542        let buffer = self.buffer.read(cx).snapshot(cx);
15543        let mut selected_sibling = false;
15544
15545        let new_selections = old_selections
15546            .iter()
15547            .map(|selection| {
15548                let old_range = selection.start..selection.end;
15549
15550                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15551                    let new_range = node.byte_range();
15552                    selected_sibling = true;
15553                    Selection {
15554                        id: selection.id,
15555                        start: new_range.start,
15556                        end: new_range.end,
15557                        goal: SelectionGoal::None,
15558                        reversed: selection.reversed,
15559                    }
15560                } else {
15561                    selection.clone()
15562                }
15563            })
15564            .collect::<Vec<_>>();
15565
15566        if selected_sibling {
15567            self.change_selections(
15568                SelectionEffects::scroll(Autoscroll::fit()),
15569                window,
15570                cx,
15571                |s| {
15572                    s.select(new_selections);
15573                },
15574            );
15575        }
15576    }
15577
15578    pub fn select_prev_syntax_node(
15579        &mut self,
15580        _: &SelectPreviousSyntaxNode,
15581        window: &mut Window,
15582        cx: &mut Context<Self>,
15583    ) {
15584        let old_selections: Box<[_]> = self
15585            .selections
15586            .all::<usize>(&self.display_snapshot(cx))
15587            .into();
15588        if old_selections.is_empty() {
15589            return;
15590        }
15591
15592        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15593
15594        let buffer = self.buffer.read(cx).snapshot(cx);
15595        let mut selected_sibling = false;
15596
15597        let new_selections = old_selections
15598            .iter()
15599            .map(|selection| {
15600                let old_range = selection.start..selection.end;
15601
15602                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15603                    let new_range = node.byte_range();
15604                    selected_sibling = true;
15605                    Selection {
15606                        id: selection.id,
15607                        start: new_range.start,
15608                        end: new_range.end,
15609                        goal: SelectionGoal::None,
15610                        reversed: selection.reversed,
15611                    }
15612                } else {
15613                    selection.clone()
15614                }
15615            })
15616            .collect::<Vec<_>>();
15617
15618        if selected_sibling {
15619            self.change_selections(
15620                SelectionEffects::scroll(Autoscroll::fit()),
15621                window,
15622                cx,
15623                |s| {
15624                    s.select(new_selections);
15625                },
15626            );
15627        }
15628    }
15629
15630    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15631        if !EditorSettings::get_global(cx).gutter.runnables {
15632            self.clear_tasks();
15633            return Task::ready(());
15634        }
15635        let project = self.project().map(Entity::downgrade);
15636        let task_sources = self.lsp_task_sources(cx);
15637        let multi_buffer = self.buffer.downgrade();
15638        cx.spawn_in(window, async move |editor, cx| {
15639            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15640            let Some(project) = project.and_then(|p| p.upgrade()) else {
15641                return;
15642            };
15643            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15644                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15645            }) else {
15646                return;
15647            };
15648
15649            let hide_runnables = project
15650                .update(cx, |project, _| project.is_via_collab())
15651                .unwrap_or(true);
15652            if hide_runnables {
15653                return;
15654            }
15655            let new_rows =
15656                cx.background_spawn({
15657                    let snapshot = display_snapshot.clone();
15658                    async move {
15659                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15660                    }
15661                })
15662                    .await;
15663            let Ok(lsp_tasks) =
15664                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15665            else {
15666                return;
15667            };
15668            let lsp_tasks = lsp_tasks.await;
15669
15670            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15671                lsp_tasks
15672                    .into_iter()
15673                    .flat_map(|(kind, tasks)| {
15674                        tasks.into_iter().filter_map(move |(location, task)| {
15675                            Some((kind.clone(), location?, task))
15676                        })
15677                    })
15678                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15679                        let buffer = location.target.buffer;
15680                        let buffer_snapshot = buffer.read(cx).snapshot();
15681                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15682                            |(excerpt_id, snapshot, _)| {
15683                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15684                                    display_snapshot
15685                                        .buffer_snapshot()
15686                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15687                                } else {
15688                                    None
15689                                }
15690                            },
15691                        );
15692                        if let Some(offset) = offset {
15693                            let task_buffer_range =
15694                                location.target.range.to_point(&buffer_snapshot);
15695                            let context_buffer_range =
15696                                task_buffer_range.to_offset(&buffer_snapshot);
15697                            let context_range = BufferOffset(context_buffer_range.start)
15698                                ..BufferOffset(context_buffer_range.end);
15699
15700                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15701                                .or_insert_with(|| RunnableTasks {
15702                                    templates: Vec::new(),
15703                                    offset,
15704                                    column: task_buffer_range.start.column,
15705                                    extra_variables: HashMap::default(),
15706                                    context_range,
15707                                })
15708                                .templates
15709                                .push((kind, task.original_task().clone()));
15710                        }
15711
15712                        acc
15713                    })
15714            }) else {
15715                return;
15716            };
15717
15718            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15719                buffer.language_settings(cx).tasks.prefer_lsp
15720            }) else {
15721                return;
15722            };
15723
15724            let rows = Self::runnable_rows(
15725                project,
15726                display_snapshot,
15727                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15728                new_rows,
15729                cx.clone(),
15730            )
15731            .await;
15732            editor
15733                .update(cx, |editor, _| {
15734                    editor.clear_tasks();
15735                    for (key, mut value) in rows {
15736                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15737                            value.templates.extend(lsp_tasks.templates);
15738                        }
15739
15740                        editor.insert_tasks(key, value);
15741                    }
15742                    for (key, value) in lsp_tasks_by_rows {
15743                        editor.insert_tasks(key, value);
15744                    }
15745                })
15746                .ok();
15747        })
15748    }
15749    fn fetch_runnable_ranges(
15750        snapshot: &DisplaySnapshot,
15751        range: Range<Anchor>,
15752    ) -> Vec<language::RunnableRange> {
15753        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15754    }
15755
15756    fn runnable_rows(
15757        project: Entity<Project>,
15758        snapshot: DisplaySnapshot,
15759        prefer_lsp: bool,
15760        runnable_ranges: Vec<RunnableRange>,
15761        cx: AsyncWindowContext,
15762    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15763        cx.spawn(async move |cx| {
15764            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15765            for mut runnable in runnable_ranges {
15766                let Some(tasks) = cx
15767                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15768                    .ok()
15769                else {
15770                    continue;
15771                };
15772                let mut tasks = tasks.await;
15773
15774                if prefer_lsp {
15775                    tasks.retain(|(task_kind, _)| {
15776                        !matches!(task_kind, TaskSourceKind::Language { .. })
15777                    });
15778                }
15779                if tasks.is_empty() {
15780                    continue;
15781                }
15782
15783                let point = runnable
15784                    .run_range
15785                    .start
15786                    .to_point(&snapshot.buffer_snapshot());
15787                let Some(row) = snapshot
15788                    .buffer_snapshot()
15789                    .buffer_line_for_row(MultiBufferRow(point.row))
15790                    .map(|(_, range)| range.start.row)
15791                else {
15792                    continue;
15793                };
15794
15795                let context_range =
15796                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15797                runnable_rows.push((
15798                    (runnable.buffer_id, row),
15799                    RunnableTasks {
15800                        templates: tasks,
15801                        offset: snapshot
15802                            .buffer_snapshot()
15803                            .anchor_before(runnable.run_range.start),
15804                        context_range,
15805                        column: point.column,
15806                        extra_variables: runnable.extra_captures,
15807                    },
15808                ));
15809            }
15810            runnable_rows
15811        })
15812    }
15813
15814    fn templates_with_tags(
15815        project: &Entity<Project>,
15816        runnable: &mut Runnable,
15817        cx: &mut App,
15818    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15819        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15820            let (worktree_id, file) = project
15821                .buffer_for_id(runnable.buffer, cx)
15822                .and_then(|buffer| buffer.read(cx).file())
15823                .map(|file| (file.worktree_id(cx), file.clone()))
15824                .unzip();
15825
15826            (
15827                project.task_store().read(cx).task_inventory().cloned(),
15828                worktree_id,
15829                file,
15830            )
15831        });
15832
15833        let tags = mem::take(&mut runnable.tags);
15834        let language = runnable.language.clone();
15835        cx.spawn(async move |cx| {
15836            let mut templates_with_tags = Vec::new();
15837            if let Some(inventory) = inventory {
15838                for RunnableTag(tag) in tags {
15839                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15840                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15841                    }) else {
15842                        return templates_with_tags;
15843                    };
15844                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15845                        move |(_, template)| {
15846                            template.tags.iter().any(|source_tag| source_tag == &tag)
15847                        },
15848                    ));
15849                }
15850            }
15851            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15852
15853            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15854                // Strongest source wins; if we have worktree tag binding, prefer that to
15855                // global and language bindings;
15856                // if we have a global binding, prefer that to language binding.
15857                let first_mismatch = templates_with_tags
15858                    .iter()
15859                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15860                if let Some(index) = first_mismatch {
15861                    templates_with_tags.truncate(index);
15862                }
15863            }
15864
15865            templates_with_tags
15866        })
15867    }
15868
15869    pub fn move_to_enclosing_bracket(
15870        &mut self,
15871        _: &MoveToEnclosingBracket,
15872        window: &mut Window,
15873        cx: &mut Context<Self>,
15874    ) {
15875        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15876        self.change_selections(Default::default(), window, cx, |s| {
15877            s.move_offsets_with(|snapshot, selection| {
15878                let Some(enclosing_bracket_ranges) =
15879                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15880                else {
15881                    return;
15882                };
15883
15884                let mut best_length = usize::MAX;
15885                let mut best_inside = false;
15886                let mut best_in_bracket_range = false;
15887                let mut best_destination = None;
15888                for (open, close) in enclosing_bracket_ranges {
15889                    let close = close.to_inclusive();
15890                    let length = close.end() - open.start;
15891                    let inside = selection.start >= open.end && selection.end <= *close.start();
15892                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15893                        || close.contains(&selection.head());
15894
15895                    // If best is next to a bracket and current isn't, skip
15896                    if !in_bracket_range && best_in_bracket_range {
15897                        continue;
15898                    }
15899
15900                    // Prefer smaller lengths unless best is inside and current isn't
15901                    if length > best_length && (best_inside || !inside) {
15902                        continue;
15903                    }
15904
15905                    best_length = length;
15906                    best_inside = inside;
15907                    best_in_bracket_range = in_bracket_range;
15908                    best_destination = Some(
15909                        if close.contains(&selection.start) && close.contains(&selection.end) {
15910                            if inside { open.end } else { open.start }
15911                        } else if inside {
15912                            *close.start()
15913                        } else {
15914                            *close.end()
15915                        },
15916                    );
15917                }
15918
15919                if let Some(destination) = best_destination {
15920                    selection.collapse_to(destination, SelectionGoal::None);
15921                }
15922            })
15923        });
15924    }
15925
15926    pub fn undo_selection(
15927        &mut self,
15928        _: &UndoSelection,
15929        window: &mut Window,
15930        cx: &mut Context<Self>,
15931    ) {
15932        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15933        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15934            self.selection_history.mode = SelectionHistoryMode::Undoing;
15935            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15936                this.end_selection(window, cx);
15937                this.change_selections(
15938                    SelectionEffects::scroll(Autoscroll::newest()),
15939                    window,
15940                    cx,
15941                    |s| s.select_anchors(entry.selections.to_vec()),
15942                );
15943            });
15944            self.selection_history.mode = SelectionHistoryMode::Normal;
15945
15946            self.select_next_state = entry.select_next_state;
15947            self.select_prev_state = entry.select_prev_state;
15948            self.add_selections_state = entry.add_selections_state;
15949        }
15950    }
15951
15952    pub fn redo_selection(
15953        &mut self,
15954        _: &RedoSelection,
15955        window: &mut Window,
15956        cx: &mut Context<Self>,
15957    ) {
15958        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15959        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15960            self.selection_history.mode = SelectionHistoryMode::Redoing;
15961            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15962                this.end_selection(window, cx);
15963                this.change_selections(
15964                    SelectionEffects::scroll(Autoscroll::newest()),
15965                    window,
15966                    cx,
15967                    |s| s.select_anchors(entry.selections.to_vec()),
15968                );
15969            });
15970            self.selection_history.mode = SelectionHistoryMode::Normal;
15971
15972            self.select_next_state = entry.select_next_state;
15973            self.select_prev_state = entry.select_prev_state;
15974            self.add_selections_state = entry.add_selections_state;
15975        }
15976    }
15977
15978    pub fn expand_excerpts(
15979        &mut self,
15980        action: &ExpandExcerpts,
15981        _: &mut Window,
15982        cx: &mut Context<Self>,
15983    ) {
15984        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15985    }
15986
15987    pub fn expand_excerpts_down(
15988        &mut self,
15989        action: &ExpandExcerptsDown,
15990        _: &mut Window,
15991        cx: &mut Context<Self>,
15992    ) {
15993        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15994    }
15995
15996    pub fn expand_excerpts_up(
15997        &mut self,
15998        action: &ExpandExcerptsUp,
15999        _: &mut Window,
16000        cx: &mut Context<Self>,
16001    ) {
16002        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16003    }
16004
16005    pub fn expand_excerpts_for_direction(
16006        &mut self,
16007        lines: u32,
16008        direction: ExpandExcerptDirection,
16009
16010        cx: &mut Context<Self>,
16011    ) {
16012        let selections = self.selections.disjoint_anchors_arc();
16013
16014        let lines = if lines == 0 {
16015            EditorSettings::get_global(cx).expand_excerpt_lines
16016        } else {
16017            lines
16018        };
16019
16020        self.buffer.update(cx, |buffer, cx| {
16021            let snapshot = buffer.snapshot(cx);
16022            let mut excerpt_ids = selections
16023                .iter()
16024                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16025                .collect::<Vec<_>>();
16026            excerpt_ids.sort();
16027            excerpt_ids.dedup();
16028            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16029        })
16030    }
16031
16032    pub fn expand_excerpt(
16033        &mut self,
16034        excerpt: ExcerptId,
16035        direction: ExpandExcerptDirection,
16036        window: &mut Window,
16037        cx: &mut Context<Self>,
16038    ) {
16039        let current_scroll_position = self.scroll_position(cx);
16040        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16041        let mut should_scroll_up = false;
16042
16043        if direction == ExpandExcerptDirection::Down {
16044            let multi_buffer = self.buffer.read(cx);
16045            let snapshot = multi_buffer.snapshot(cx);
16046            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16047                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16048                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16049            {
16050                let buffer_snapshot = buffer.read(cx).snapshot();
16051                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16052                let last_row = buffer_snapshot.max_point().row;
16053                let lines_below = last_row.saturating_sub(excerpt_end_row);
16054                should_scroll_up = lines_below >= lines_to_expand;
16055            }
16056        }
16057
16058        self.buffer.update(cx, |buffer, cx| {
16059            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16060        });
16061
16062        if should_scroll_up {
16063            let new_scroll_position =
16064                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
16065            self.set_scroll_position(new_scroll_position, window, cx);
16066        }
16067    }
16068
16069    pub fn go_to_singleton_buffer_point(
16070        &mut self,
16071        point: Point,
16072        window: &mut Window,
16073        cx: &mut Context<Self>,
16074    ) {
16075        self.go_to_singleton_buffer_range(point..point, window, cx);
16076    }
16077
16078    pub fn go_to_singleton_buffer_range(
16079        &mut self,
16080        range: Range<Point>,
16081        window: &mut Window,
16082        cx: &mut Context<Self>,
16083    ) {
16084        let multibuffer = self.buffer().read(cx);
16085        let Some(buffer) = multibuffer.as_singleton() else {
16086            return;
16087        };
16088        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16089            return;
16090        };
16091        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16092            return;
16093        };
16094        self.change_selections(
16095            SelectionEffects::default().nav_history(true),
16096            window,
16097            cx,
16098            |s| s.select_anchor_ranges([start..end]),
16099        );
16100    }
16101
16102    pub fn go_to_diagnostic(
16103        &mut self,
16104        action: &GoToDiagnostic,
16105        window: &mut Window,
16106        cx: &mut Context<Self>,
16107    ) {
16108        if !self.diagnostics_enabled() {
16109            return;
16110        }
16111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16112        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16113    }
16114
16115    pub fn go_to_prev_diagnostic(
16116        &mut self,
16117        action: &GoToPreviousDiagnostic,
16118        window: &mut Window,
16119        cx: &mut Context<Self>,
16120    ) {
16121        if !self.diagnostics_enabled() {
16122            return;
16123        }
16124        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16125        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16126    }
16127
16128    pub fn go_to_diagnostic_impl(
16129        &mut self,
16130        direction: Direction,
16131        severity: GoToDiagnosticSeverityFilter,
16132        window: &mut Window,
16133        cx: &mut Context<Self>,
16134    ) {
16135        let buffer = self.buffer.read(cx).snapshot(cx);
16136        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16137
16138        let mut active_group_id = None;
16139        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16140            && active_group.active_range.start.to_offset(&buffer) == selection.start
16141        {
16142            active_group_id = Some(active_group.group_id);
16143        }
16144
16145        fn filtered<'a>(
16146            snapshot: EditorSnapshot,
16147            severity: GoToDiagnosticSeverityFilter,
16148            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16149        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16150            diagnostics
16151                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16152                .filter(|entry| entry.range.start != entry.range.end)
16153                .filter(|entry| !entry.diagnostic.is_unnecessary)
16154                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16155        }
16156
16157        let snapshot = self.snapshot(window, cx);
16158        let before = filtered(
16159            snapshot.clone(),
16160            severity,
16161            buffer
16162                .diagnostics_in_range(0..selection.start)
16163                .filter(|entry| entry.range.start <= selection.start),
16164        );
16165        let after = filtered(
16166            snapshot,
16167            severity,
16168            buffer
16169                .diagnostics_in_range(selection.start..buffer.len())
16170                .filter(|entry| entry.range.start >= selection.start),
16171        );
16172
16173        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16174        if direction == Direction::Prev {
16175            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16176            {
16177                for diagnostic in prev_diagnostics.into_iter().rev() {
16178                    if diagnostic.range.start != selection.start
16179                        || active_group_id
16180                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16181                    {
16182                        found = Some(diagnostic);
16183                        break 'outer;
16184                    }
16185                }
16186            }
16187        } else {
16188            for diagnostic in after.chain(before) {
16189                if diagnostic.range.start != selection.start
16190                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16191                {
16192                    found = Some(diagnostic);
16193                    break;
16194                }
16195            }
16196        }
16197        let Some(next_diagnostic) = found else {
16198            return;
16199        };
16200
16201        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16202        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16203            return;
16204        };
16205        self.change_selections(Default::default(), window, cx, |s| {
16206            s.select_ranges(vec![
16207                next_diagnostic.range.start..next_diagnostic.range.start,
16208            ])
16209        });
16210        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16211        self.refresh_edit_prediction(false, true, window, cx);
16212    }
16213
16214    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16215        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16216        let snapshot = self.snapshot(window, cx);
16217        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16218        self.go_to_hunk_before_or_after_position(
16219            &snapshot,
16220            selection.head(),
16221            Direction::Next,
16222            window,
16223            cx,
16224        );
16225    }
16226
16227    pub fn go_to_hunk_before_or_after_position(
16228        &mut self,
16229        snapshot: &EditorSnapshot,
16230        position: Point,
16231        direction: Direction,
16232        window: &mut Window,
16233        cx: &mut Context<Editor>,
16234    ) {
16235        let row = if direction == Direction::Next {
16236            self.hunk_after_position(snapshot, position)
16237                .map(|hunk| hunk.row_range.start)
16238        } else {
16239            self.hunk_before_position(snapshot, position)
16240        };
16241
16242        if let Some(row) = row {
16243            let destination = Point::new(row.0, 0);
16244            let autoscroll = Autoscroll::center();
16245
16246            self.unfold_ranges(&[destination..destination], false, false, cx);
16247            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16248                s.select_ranges([destination..destination]);
16249            });
16250        }
16251    }
16252
16253    fn hunk_after_position(
16254        &mut self,
16255        snapshot: &EditorSnapshot,
16256        position: Point,
16257    ) -> Option<MultiBufferDiffHunk> {
16258        snapshot
16259            .buffer_snapshot()
16260            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16261            .find(|hunk| hunk.row_range.start.0 > position.row)
16262            .or_else(|| {
16263                snapshot
16264                    .buffer_snapshot()
16265                    .diff_hunks_in_range(Point::zero()..position)
16266                    .find(|hunk| hunk.row_range.end.0 < position.row)
16267            })
16268    }
16269
16270    fn go_to_prev_hunk(
16271        &mut self,
16272        _: &GoToPreviousHunk,
16273        window: &mut Window,
16274        cx: &mut Context<Self>,
16275    ) {
16276        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16277        let snapshot = self.snapshot(window, cx);
16278        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16279        self.go_to_hunk_before_or_after_position(
16280            &snapshot,
16281            selection.head(),
16282            Direction::Prev,
16283            window,
16284            cx,
16285        );
16286    }
16287
16288    fn hunk_before_position(
16289        &mut self,
16290        snapshot: &EditorSnapshot,
16291        position: Point,
16292    ) -> Option<MultiBufferRow> {
16293        snapshot
16294            .buffer_snapshot()
16295            .diff_hunk_before(position)
16296            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16297    }
16298
16299    fn go_to_next_change(
16300        &mut self,
16301        _: &GoToNextChange,
16302        window: &mut Window,
16303        cx: &mut Context<Self>,
16304    ) {
16305        if let Some(selections) = self
16306            .change_list
16307            .next_change(1, Direction::Next)
16308            .map(|s| s.to_vec())
16309        {
16310            self.change_selections(Default::default(), window, cx, |s| {
16311                let map = s.display_map();
16312                s.select_display_ranges(selections.iter().map(|a| {
16313                    let point = a.to_display_point(&map);
16314                    point..point
16315                }))
16316            })
16317        }
16318    }
16319
16320    fn go_to_previous_change(
16321        &mut self,
16322        _: &GoToPreviousChange,
16323        window: &mut Window,
16324        cx: &mut Context<Self>,
16325    ) {
16326        if let Some(selections) = self
16327            .change_list
16328            .next_change(1, Direction::Prev)
16329            .map(|s| s.to_vec())
16330        {
16331            self.change_selections(Default::default(), window, cx, |s| {
16332                let map = s.display_map();
16333                s.select_display_ranges(selections.iter().map(|a| {
16334                    let point = a.to_display_point(&map);
16335                    point..point
16336                }))
16337            })
16338        }
16339    }
16340
16341    pub fn go_to_next_document_highlight(
16342        &mut self,
16343        _: &GoToNextDocumentHighlight,
16344        window: &mut Window,
16345        cx: &mut Context<Self>,
16346    ) {
16347        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16348    }
16349
16350    pub fn go_to_prev_document_highlight(
16351        &mut self,
16352        _: &GoToPreviousDocumentHighlight,
16353        window: &mut Window,
16354        cx: &mut Context<Self>,
16355    ) {
16356        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16357    }
16358
16359    pub fn go_to_document_highlight_before_or_after_position(
16360        &mut self,
16361        direction: Direction,
16362        window: &mut Window,
16363        cx: &mut Context<Editor>,
16364    ) {
16365        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16366        let snapshot = self.snapshot(window, cx);
16367        let buffer = &snapshot.buffer_snapshot();
16368        let position = self
16369            .selections
16370            .newest::<Point>(&snapshot.display_snapshot)
16371            .head();
16372        let anchor_position = buffer.anchor_after(position);
16373
16374        // Get all document highlights (both read and write)
16375        let mut all_highlights = Vec::new();
16376
16377        if let Some((_, read_highlights)) = self
16378            .background_highlights
16379            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16380        {
16381            all_highlights.extend(read_highlights.iter());
16382        }
16383
16384        if let Some((_, write_highlights)) = self
16385            .background_highlights
16386            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16387        {
16388            all_highlights.extend(write_highlights.iter());
16389        }
16390
16391        if all_highlights.is_empty() {
16392            return;
16393        }
16394
16395        // Sort highlights by position
16396        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16397
16398        let target_highlight = match direction {
16399            Direction::Next => {
16400                // Find the first highlight after the current position
16401                all_highlights
16402                    .iter()
16403                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16404            }
16405            Direction::Prev => {
16406                // Find the last highlight before the current position
16407                all_highlights
16408                    .iter()
16409                    .rev()
16410                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16411            }
16412        };
16413
16414        if let Some(highlight) = target_highlight {
16415            let destination = highlight.start.to_point(buffer);
16416            let autoscroll = Autoscroll::center();
16417
16418            self.unfold_ranges(&[destination..destination], false, false, cx);
16419            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16420                s.select_ranges([destination..destination]);
16421            });
16422        }
16423    }
16424
16425    fn go_to_line<T: 'static>(
16426        &mut self,
16427        position: Anchor,
16428        highlight_color: Option<Hsla>,
16429        window: &mut Window,
16430        cx: &mut Context<Self>,
16431    ) {
16432        let snapshot = self.snapshot(window, cx).display_snapshot;
16433        let position = position.to_point(&snapshot.buffer_snapshot());
16434        let start = snapshot
16435            .buffer_snapshot()
16436            .clip_point(Point::new(position.row, 0), Bias::Left);
16437        let end = start + Point::new(1, 0);
16438        let start = snapshot.buffer_snapshot().anchor_before(start);
16439        let end = snapshot.buffer_snapshot().anchor_before(end);
16440
16441        self.highlight_rows::<T>(
16442            start..end,
16443            highlight_color
16444                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16445            Default::default(),
16446            cx,
16447        );
16448
16449        if self.buffer.read(cx).is_singleton() {
16450            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16451        }
16452    }
16453
16454    pub fn go_to_definition(
16455        &mut self,
16456        _: &GoToDefinition,
16457        window: &mut Window,
16458        cx: &mut Context<Self>,
16459    ) -> Task<Result<Navigated>> {
16460        let definition =
16461            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16462        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16463        cx.spawn_in(window, async move |editor, cx| {
16464            if definition.await? == Navigated::Yes {
16465                return Ok(Navigated::Yes);
16466            }
16467            match fallback_strategy {
16468                GoToDefinitionFallback::None => Ok(Navigated::No),
16469                GoToDefinitionFallback::FindAllReferences => {
16470                    match editor.update_in(cx, |editor, window, cx| {
16471                        editor.find_all_references(&FindAllReferences, window, cx)
16472                    })? {
16473                        Some(references) => references.await,
16474                        None => Ok(Navigated::No),
16475                    }
16476                }
16477            }
16478        })
16479    }
16480
16481    pub fn go_to_declaration(
16482        &mut self,
16483        _: &GoToDeclaration,
16484        window: &mut Window,
16485        cx: &mut Context<Self>,
16486    ) -> Task<Result<Navigated>> {
16487        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16488    }
16489
16490    pub fn go_to_declaration_split(
16491        &mut self,
16492        _: &GoToDeclaration,
16493        window: &mut Window,
16494        cx: &mut Context<Self>,
16495    ) -> Task<Result<Navigated>> {
16496        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16497    }
16498
16499    pub fn go_to_implementation(
16500        &mut self,
16501        _: &GoToImplementation,
16502        window: &mut Window,
16503        cx: &mut Context<Self>,
16504    ) -> Task<Result<Navigated>> {
16505        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16506    }
16507
16508    pub fn go_to_implementation_split(
16509        &mut self,
16510        _: &GoToImplementationSplit,
16511        window: &mut Window,
16512        cx: &mut Context<Self>,
16513    ) -> Task<Result<Navigated>> {
16514        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16515    }
16516
16517    pub fn go_to_type_definition(
16518        &mut self,
16519        _: &GoToTypeDefinition,
16520        window: &mut Window,
16521        cx: &mut Context<Self>,
16522    ) -> Task<Result<Navigated>> {
16523        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16524    }
16525
16526    pub fn go_to_definition_split(
16527        &mut self,
16528        _: &GoToDefinitionSplit,
16529        window: &mut Window,
16530        cx: &mut Context<Self>,
16531    ) -> Task<Result<Navigated>> {
16532        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16533    }
16534
16535    pub fn go_to_type_definition_split(
16536        &mut self,
16537        _: &GoToTypeDefinitionSplit,
16538        window: &mut Window,
16539        cx: &mut Context<Self>,
16540    ) -> Task<Result<Navigated>> {
16541        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16542    }
16543
16544    fn go_to_definition_of_kind(
16545        &mut self,
16546        kind: GotoDefinitionKind,
16547        split: bool,
16548        window: &mut Window,
16549        cx: &mut Context<Self>,
16550    ) -> Task<Result<Navigated>> {
16551        let Some(provider) = self.semantics_provider.clone() else {
16552            return Task::ready(Ok(Navigated::No));
16553        };
16554        let head = self
16555            .selections
16556            .newest::<usize>(&self.display_snapshot(cx))
16557            .head();
16558        let buffer = self.buffer.read(cx);
16559        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16560            return Task::ready(Ok(Navigated::No));
16561        };
16562        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16563            return Task::ready(Ok(Navigated::No));
16564        };
16565
16566        cx.spawn_in(window, async move |editor, cx| {
16567            let Some(definitions) = definitions.await? else {
16568                return Ok(Navigated::No);
16569            };
16570            let navigated = editor
16571                .update_in(cx, |editor, window, cx| {
16572                    editor.navigate_to_hover_links(
16573                        Some(kind),
16574                        definitions
16575                            .into_iter()
16576                            .filter(|location| {
16577                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16578                            })
16579                            .map(HoverLink::Text)
16580                            .collect::<Vec<_>>(),
16581                        split,
16582                        window,
16583                        cx,
16584                    )
16585                })?
16586                .await?;
16587            anyhow::Ok(navigated)
16588        })
16589    }
16590
16591    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16592        let selection = self.selections.newest_anchor();
16593        let head = selection.head();
16594        let tail = selection.tail();
16595
16596        let Some((buffer, start_position)) =
16597            self.buffer.read(cx).text_anchor_for_position(head, cx)
16598        else {
16599            return;
16600        };
16601
16602        let end_position = if head != tail {
16603            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16604                return;
16605            };
16606            Some(pos)
16607        } else {
16608            None
16609        };
16610
16611        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16612            let url = if let Some(end_pos) = end_position {
16613                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16614            } else {
16615                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16616            };
16617
16618            if let Some(url) = url {
16619                cx.update(|window, cx| {
16620                    if parse_zed_link(&url, cx).is_some() {
16621                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16622                    } else {
16623                        cx.open_url(&url);
16624                    }
16625                })?;
16626            }
16627
16628            anyhow::Ok(())
16629        });
16630
16631        url_finder.detach();
16632    }
16633
16634    pub fn open_selected_filename(
16635        &mut self,
16636        _: &OpenSelectedFilename,
16637        window: &mut Window,
16638        cx: &mut Context<Self>,
16639    ) {
16640        let Some(workspace) = self.workspace() else {
16641            return;
16642        };
16643
16644        let position = self.selections.newest_anchor().head();
16645
16646        let Some((buffer, buffer_position)) =
16647            self.buffer.read(cx).text_anchor_for_position(position, cx)
16648        else {
16649            return;
16650        };
16651
16652        let project = self.project.clone();
16653
16654        cx.spawn_in(window, async move |_, cx| {
16655            let result = find_file(&buffer, project, buffer_position, cx).await;
16656
16657            if let Some((_, path)) = result {
16658                workspace
16659                    .update_in(cx, |workspace, window, cx| {
16660                        workspace.open_resolved_path(path, window, cx)
16661                    })?
16662                    .await?;
16663            }
16664            anyhow::Ok(())
16665        })
16666        .detach();
16667    }
16668
16669    pub(crate) fn navigate_to_hover_links(
16670        &mut self,
16671        kind: Option<GotoDefinitionKind>,
16672        definitions: Vec<HoverLink>,
16673        split: bool,
16674        window: &mut Window,
16675        cx: &mut Context<Editor>,
16676    ) -> Task<Result<Navigated>> {
16677        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16678        let mut first_url_or_file = None;
16679        let definitions: Vec<_> = definitions
16680            .into_iter()
16681            .filter_map(|def| match def {
16682                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16683                HoverLink::InlayHint(lsp_location, server_id) => {
16684                    let computation =
16685                        self.compute_target_location(lsp_location, server_id, window, cx);
16686                    Some(cx.background_spawn(computation))
16687                }
16688                HoverLink::Url(url) => {
16689                    first_url_or_file = Some(Either::Left(url));
16690                    None
16691                }
16692                HoverLink::File(path) => {
16693                    first_url_or_file = Some(Either::Right(path));
16694                    None
16695                }
16696            })
16697            .collect();
16698
16699        let workspace = self.workspace();
16700
16701        cx.spawn_in(window, async move |editor, cx| {
16702            let locations: Vec<Location> = future::join_all(definitions)
16703                .await
16704                .into_iter()
16705                .filter_map(|location| location.transpose())
16706                .collect::<Result<_>>()
16707                .context("location tasks")?;
16708            let mut locations = cx.update(|_, cx| {
16709                locations
16710                    .into_iter()
16711                    .map(|location| {
16712                        let buffer = location.buffer.read(cx);
16713                        (location.buffer, location.range.to_point(buffer))
16714                    })
16715                    .into_group_map()
16716            })?;
16717            let mut num_locations = 0;
16718            for ranges in locations.values_mut() {
16719                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16720                ranges.dedup();
16721                num_locations += ranges.len();
16722            }
16723
16724            if num_locations > 1 {
16725                let Some(workspace) = workspace else {
16726                    return Ok(Navigated::No);
16727                };
16728
16729                let tab_kind = match kind {
16730                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16731                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16732                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16733                    Some(GotoDefinitionKind::Type) => "Types",
16734                };
16735                let title = editor
16736                    .update_in(cx, |_, _, cx| {
16737                        let target = locations
16738                            .iter()
16739                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16740                            .map(|(buffer, location)| {
16741                                buffer
16742                                    .read(cx)
16743                                    .text_for_range(location.clone())
16744                                    .collect::<String>()
16745                            })
16746                            .filter(|text| !text.contains('\n'))
16747                            .unique()
16748                            .take(3)
16749                            .join(", ");
16750                        if target.is_empty() {
16751                            tab_kind.to_owned()
16752                        } else {
16753                            format!("{tab_kind} for {target}")
16754                        }
16755                    })
16756                    .context("buffer title")?;
16757
16758                let opened = workspace
16759                    .update_in(cx, |workspace, window, cx| {
16760                        Self::open_locations_in_multibuffer(
16761                            workspace,
16762                            locations,
16763                            title,
16764                            split,
16765                            MultibufferSelectionMode::First,
16766                            window,
16767                            cx,
16768                        )
16769                    })
16770                    .is_ok();
16771
16772                anyhow::Ok(Navigated::from_bool(opened))
16773            } else if num_locations == 0 {
16774                // If there is one url or file, open it directly
16775                match first_url_or_file {
16776                    Some(Either::Left(url)) => {
16777                        cx.update(|_, cx| cx.open_url(&url))?;
16778                        Ok(Navigated::Yes)
16779                    }
16780                    Some(Either::Right(path)) => {
16781                        let Some(workspace) = workspace else {
16782                            return Ok(Navigated::No);
16783                        };
16784
16785                        workspace
16786                            .update_in(cx, |workspace, window, cx| {
16787                                workspace.open_resolved_path(path, window, cx)
16788                            })?
16789                            .await?;
16790                        Ok(Navigated::Yes)
16791                    }
16792                    None => Ok(Navigated::No),
16793                }
16794            } else {
16795                let Some(workspace) = workspace else {
16796                    return Ok(Navigated::No);
16797                };
16798
16799                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16800                let target_range = target_ranges.first().unwrap().clone();
16801
16802                editor.update_in(cx, |editor, window, cx| {
16803                    let range = target_range.to_point(target_buffer.read(cx));
16804                    let range = editor.range_for_match(&range);
16805                    let range = collapse_multiline_range(range);
16806
16807                    if !split
16808                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16809                    {
16810                        editor.go_to_singleton_buffer_range(range, window, cx);
16811                    } else {
16812                        let pane = workspace.read(cx).active_pane().clone();
16813                        window.defer(cx, move |window, cx| {
16814                            let target_editor: Entity<Self> =
16815                                workspace.update(cx, |workspace, cx| {
16816                                    let pane = if split {
16817                                        workspace.adjacent_pane(window, cx)
16818                                    } else {
16819                                        workspace.active_pane().clone()
16820                                    };
16821
16822                                    workspace.open_project_item(
16823                                        pane,
16824                                        target_buffer.clone(),
16825                                        true,
16826                                        true,
16827                                        window,
16828                                        cx,
16829                                    )
16830                                });
16831                            target_editor.update(cx, |target_editor, cx| {
16832                                // When selecting a definition in a different buffer, disable the nav history
16833                                // to avoid creating a history entry at the previous cursor location.
16834                                pane.update(cx, |pane, _| pane.disable_history());
16835                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16836                                pane.update(cx, |pane, _| pane.enable_history());
16837                            });
16838                        });
16839                    }
16840                    Navigated::Yes
16841                })
16842            }
16843        })
16844    }
16845
16846    fn compute_target_location(
16847        &self,
16848        lsp_location: lsp::Location,
16849        server_id: LanguageServerId,
16850        window: &mut Window,
16851        cx: &mut Context<Self>,
16852    ) -> Task<anyhow::Result<Option<Location>>> {
16853        let Some(project) = self.project.clone() else {
16854            return Task::ready(Ok(None));
16855        };
16856
16857        cx.spawn_in(window, async move |editor, cx| {
16858            let location_task = editor.update(cx, |_, cx| {
16859                project.update(cx, |project, cx| {
16860                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16861                })
16862            })?;
16863            let location = Some({
16864                let target_buffer_handle = location_task.await.context("open local buffer")?;
16865                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16866                    let target_start = target_buffer
16867                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16868                    let target_end = target_buffer
16869                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16870                    target_buffer.anchor_after(target_start)
16871                        ..target_buffer.anchor_before(target_end)
16872                })?;
16873                Location {
16874                    buffer: target_buffer_handle,
16875                    range,
16876                }
16877            });
16878            Ok(location)
16879        })
16880    }
16881
16882    pub fn find_all_references(
16883        &mut self,
16884        _: &FindAllReferences,
16885        window: &mut Window,
16886        cx: &mut Context<Self>,
16887    ) -> Option<Task<Result<Navigated>>> {
16888        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16889        let multi_buffer = self.buffer.read(cx);
16890        let head = selection.head();
16891
16892        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16893        let head_anchor = multi_buffer_snapshot.anchor_at(
16894            head,
16895            if head < selection.tail() {
16896                Bias::Right
16897            } else {
16898                Bias::Left
16899            },
16900        );
16901
16902        match self
16903            .find_all_references_task_sources
16904            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16905        {
16906            Ok(_) => {
16907                log::info!(
16908                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16909                );
16910                return None;
16911            }
16912            Err(i) => {
16913                self.find_all_references_task_sources.insert(i, head_anchor);
16914            }
16915        }
16916
16917        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16918        let workspace = self.workspace()?;
16919        let project = workspace.read(cx).project().clone();
16920        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16921        Some(cx.spawn_in(window, async move |editor, cx| {
16922            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16923                if let Ok(i) = editor
16924                    .find_all_references_task_sources
16925                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16926                {
16927                    editor.find_all_references_task_sources.remove(i);
16928                }
16929            });
16930
16931            let Some(locations) = references.await? else {
16932                return anyhow::Ok(Navigated::No);
16933            };
16934            let mut locations = cx.update(|_, cx| {
16935                locations
16936                    .into_iter()
16937                    .map(|location| {
16938                        let buffer = location.buffer.read(cx);
16939                        (location.buffer, location.range.to_point(buffer))
16940                    })
16941                    .into_group_map()
16942            })?;
16943            if locations.is_empty() {
16944                return anyhow::Ok(Navigated::No);
16945            }
16946            for ranges in locations.values_mut() {
16947                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16948                ranges.dedup();
16949            }
16950
16951            workspace.update_in(cx, |workspace, window, cx| {
16952                let target = locations
16953                    .iter()
16954                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16955                    .map(|(buffer, location)| {
16956                        buffer
16957                            .read(cx)
16958                            .text_for_range(location.clone())
16959                            .collect::<String>()
16960                    })
16961                    .filter(|text| !text.contains('\n'))
16962                    .unique()
16963                    .take(3)
16964                    .join(", ");
16965                let title = if target.is_empty() {
16966                    "References".to_owned()
16967                } else {
16968                    format!("References to {target}")
16969                };
16970                Self::open_locations_in_multibuffer(
16971                    workspace,
16972                    locations,
16973                    title,
16974                    false,
16975                    MultibufferSelectionMode::First,
16976                    window,
16977                    cx,
16978                );
16979                Navigated::Yes
16980            })
16981        }))
16982    }
16983
16984    /// Opens a multibuffer with the given project locations in it
16985    pub fn open_locations_in_multibuffer(
16986        workspace: &mut Workspace,
16987        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16988        title: String,
16989        split: bool,
16990        multibuffer_selection_mode: MultibufferSelectionMode,
16991        window: &mut Window,
16992        cx: &mut Context<Workspace>,
16993    ) {
16994        if locations.is_empty() {
16995            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16996            return;
16997        }
16998
16999        let capability = workspace.project().read(cx).capability();
17000        let mut ranges = <Vec<Range<Anchor>>>::new();
17001
17002        // a key to find existing multibuffer editors with the same set of locations
17003        // to prevent us from opening more and more multibuffer tabs for searches and the like
17004        let mut key = (title.clone(), vec![]);
17005        let excerpt_buffer = cx.new(|cx| {
17006            let key = &mut key.1;
17007            let mut multibuffer = MultiBuffer::new(capability);
17008            for (buffer, mut ranges_for_buffer) in locations {
17009                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17010                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17011                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17012                    PathKey::for_buffer(&buffer, cx),
17013                    buffer.clone(),
17014                    ranges_for_buffer,
17015                    multibuffer_context_lines(cx),
17016                    cx,
17017                );
17018                ranges.extend(new_ranges)
17019            }
17020
17021            multibuffer.with_title(title)
17022        });
17023        let existing = workspace.active_pane().update(cx, |pane, cx| {
17024            pane.items()
17025                .filter_map(|item| item.downcast::<Editor>())
17026                .find(|editor| {
17027                    editor
17028                        .read(cx)
17029                        .lookup_key
17030                        .as_ref()
17031                        .and_then(|it| {
17032                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17033                        })
17034                        .is_some_and(|it| *it == key)
17035                })
17036        });
17037        let editor = existing.unwrap_or_else(|| {
17038            cx.new(|cx| {
17039                let mut editor = Editor::for_multibuffer(
17040                    excerpt_buffer,
17041                    Some(workspace.project().clone()),
17042                    window,
17043                    cx,
17044                );
17045                editor.lookup_key = Some(Box::new(key));
17046                editor
17047            })
17048        });
17049        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17050            MultibufferSelectionMode::First => {
17051                if let Some(first_range) = ranges.first() {
17052                    editor.change_selections(
17053                        SelectionEffects::no_scroll(),
17054                        window,
17055                        cx,
17056                        |selections| {
17057                            selections.clear_disjoint();
17058                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17059                        },
17060                    );
17061                }
17062                editor.highlight_background::<Self>(
17063                    &ranges,
17064                    |theme| theme.colors().editor_highlighted_line_background,
17065                    cx,
17066                );
17067            }
17068            MultibufferSelectionMode::All => {
17069                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17070                    selections.clear_disjoint();
17071                    selections.select_anchor_ranges(ranges);
17072                });
17073            }
17074        });
17075
17076        let item = Box::new(editor);
17077        let item_id = item.item_id();
17078
17079        if split {
17080            let pane = workspace.adjacent_pane(window, cx);
17081            workspace.add_item(pane, item, None, true, true, window, cx);
17082        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17083            let (preview_item_id, preview_item_idx) =
17084                workspace.active_pane().read_with(cx, |pane, _| {
17085                    (pane.preview_item_id(), pane.preview_item_idx())
17086                });
17087
17088            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17089
17090            if let Some(preview_item_id) = preview_item_id {
17091                workspace.active_pane().update(cx, |pane, cx| {
17092                    pane.remove_item(preview_item_id, false, false, window, cx);
17093                });
17094            }
17095        } else {
17096            workspace.add_item_to_active_pane(item, None, true, window, cx);
17097        }
17098        workspace.active_pane().update(cx, |pane, cx| {
17099            pane.set_preview_item_id(Some(item_id), cx);
17100        });
17101    }
17102
17103    pub fn rename(
17104        &mut self,
17105        _: &Rename,
17106        window: &mut Window,
17107        cx: &mut Context<Self>,
17108    ) -> Option<Task<Result<()>>> {
17109        use language::ToOffset as _;
17110
17111        let provider = self.semantics_provider.clone()?;
17112        let selection = self.selections.newest_anchor().clone();
17113        let (cursor_buffer, cursor_buffer_position) = self
17114            .buffer
17115            .read(cx)
17116            .text_anchor_for_position(selection.head(), cx)?;
17117        let (tail_buffer, cursor_buffer_position_end) = self
17118            .buffer
17119            .read(cx)
17120            .text_anchor_for_position(selection.tail(), cx)?;
17121        if tail_buffer != cursor_buffer {
17122            return None;
17123        }
17124
17125        let snapshot = cursor_buffer.read(cx).snapshot();
17126        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17127        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17128        let prepare_rename = provider
17129            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17130            .unwrap_or_else(|| Task::ready(Ok(None)));
17131        drop(snapshot);
17132
17133        Some(cx.spawn_in(window, async move |this, cx| {
17134            let rename_range = if let Some(range) = prepare_rename.await? {
17135                Some(range)
17136            } else {
17137                this.update(cx, |this, cx| {
17138                    let buffer = this.buffer.read(cx).snapshot(cx);
17139                    let mut buffer_highlights = this
17140                        .document_highlights_for_position(selection.head(), &buffer)
17141                        .filter(|highlight| {
17142                            highlight.start.excerpt_id == selection.head().excerpt_id
17143                                && highlight.end.excerpt_id == selection.head().excerpt_id
17144                        });
17145                    buffer_highlights
17146                        .next()
17147                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17148                })?
17149            };
17150            if let Some(rename_range) = rename_range {
17151                this.update_in(cx, |this, window, cx| {
17152                    let snapshot = cursor_buffer.read(cx).snapshot();
17153                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17154                    let cursor_offset_in_rename_range =
17155                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17156                    let cursor_offset_in_rename_range_end =
17157                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17158
17159                    this.take_rename(false, window, cx);
17160                    let buffer = this.buffer.read(cx).read(cx);
17161                    let cursor_offset = selection.head().to_offset(&buffer);
17162                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17163                    let rename_end = rename_start + rename_buffer_range.len();
17164                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17165                    let mut old_highlight_id = None;
17166                    let old_name: Arc<str> = buffer
17167                        .chunks(rename_start..rename_end, true)
17168                        .map(|chunk| {
17169                            if old_highlight_id.is_none() {
17170                                old_highlight_id = chunk.syntax_highlight_id;
17171                            }
17172                            chunk.text
17173                        })
17174                        .collect::<String>()
17175                        .into();
17176
17177                    drop(buffer);
17178
17179                    // Position the selection in the rename editor so that it matches the current selection.
17180                    this.show_local_selections = false;
17181                    let rename_editor = cx.new(|cx| {
17182                        let mut editor = Editor::single_line(window, cx);
17183                        editor.buffer.update(cx, |buffer, cx| {
17184                            buffer.edit([(0..0, old_name.clone())], None, cx)
17185                        });
17186                        let rename_selection_range = match cursor_offset_in_rename_range
17187                            .cmp(&cursor_offset_in_rename_range_end)
17188                        {
17189                            Ordering::Equal => {
17190                                editor.select_all(&SelectAll, window, cx);
17191                                return editor;
17192                            }
17193                            Ordering::Less => {
17194                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17195                            }
17196                            Ordering::Greater => {
17197                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17198                            }
17199                        };
17200                        if rename_selection_range.end > old_name.len() {
17201                            editor.select_all(&SelectAll, window, cx);
17202                        } else {
17203                            editor.change_selections(Default::default(), window, cx, |s| {
17204                                s.select_ranges([rename_selection_range]);
17205                            });
17206                        }
17207                        editor
17208                    });
17209                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17210                        if e == &EditorEvent::Focused {
17211                            cx.emit(EditorEvent::FocusedIn)
17212                        }
17213                    })
17214                    .detach();
17215
17216                    let write_highlights =
17217                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17218                    let read_highlights =
17219                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17220                    let ranges = write_highlights
17221                        .iter()
17222                        .flat_map(|(_, ranges)| ranges.iter())
17223                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17224                        .cloned()
17225                        .collect();
17226
17227                    this.highlight_text::<Rename>(
17228                        ranges,
17229                        HighlightStyle {
17230                            fade_out: Some(0.6),
17231                            ..Default::default()
17232                        },
17233                        cx,
17234                    );
17235                    let rename_focus_handle = rename_editor.focus_handle(cx);
17236                    window.focus(&rename_focus_handle);
17237                    let block_id = this.insert_blocks(
17238                        [BlockProperties {
17239                            style: BlockStyle::Flex,
17240                            placement: BlockPlacement::Below(range.start),
17241                            height: Some(1),
17242                            render: Arc::new({
17243                                let rename_editor = rename_editor.clone();
17244                                move |cx: &mut BlockContext| {
17245                                    let mut text_style = cx.editor_style.text.clone();
17246                                    if let Some(highlight_style) = old_highlight_id
17247                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17248                                    {
17249                                        text_style = text_style.highlight(highlight_style);
17250                                    }
17251                                    div()
17252                                        .block_mouse_except_scroll()
17253                                        .pl(cx.anchor_x)
17254                                        .child(EditorElement::new(
17255                                            &rename_editor,
17256                                            EditorStyle {
17257                                                background: cx.theme().system().transparent,
17258                                                local_player: cx.editor_style.local_player,
17259                                                text: text_style,
17260                                                scrollbar_width: cx.editor_style.scrollbar_width,
17261                                                syntax: cx.editor_style.syntax.clone(),
17262                                                status: cx.editor_style.status.clone(),
17263                                                inlay_hints_style: HighlightStyle {
17264                                                    font_weight: Some(FontWeight::BOLD),
17265                                                    ..make_inlay_hints_style(cx.app)
17266                                                },
17267                                                edit_prediction_styles: make_suggestion_styles(
17268                                                    cx.app,
17269                                                ),
17270                                                ..EditorStyle::default()
17271                                            },
17272                                        ))
17273                                        .into_any_element()
17274                                }
17275                            }),
17276                            priority: 0,
17277                        }],
17278                        Some(Autoscroll::fit()),
17279                        cx,
17280                    )[0];
17281                    this.pending_rename = Some(RenameState {
17282                        range,
17283                        old_name,
17284                        editor: rename_editor,
17285                        block_id,
17286                    });
17287                })?;
17288            }
17289
17290            Ok(())
17291        }))
17292    }
17293
17294    pub fn confirm_rename(
17295        &mut self,
17296        _: &ConfirmRename,
17297        window: &mut Window,
17298        cx: &mut Context<Self>,
17299    ) -> Option<Task<Result<()>>> {
17300        let rename = self.take_rename(false, window, cx)?;
17301        let workspace = self.workspace()?.downgrade();
17302        let (buffer, start) = self
17303            .buffer
17304            .read(cx)
17305            .text_anchor_for_position(rename.range.start, cx)?;
17306        let (end_buffer, _) = self
17307            .buffer
17308            .read(cx)
17309            .text_anchor_for_position(rename.range.end, cx)?;
17310        if buffer != end_buffer {
17311            return None;
17312        }
17313
17314        let old_name = rename.old_name;
17315        let new_name = rename.editor.read(cx).text(cx);
17316
17317        let rename = self.semantics_provider.as_ref()?.perform_rename(
17318            &buffer,
17319            start,
17320            new_name.clone(),
17321            cx,
17322        )?;
17323
17324        Some(cx.spawn_in(window, async move |editor, cx| {
17325            let project_transaction = rename.await?;
17326            Self::open_project_transaction(
17327                &editor,
17328                workspace,
17329                project_transaction,
17330                format!("Rename: {}{}", old_name, new_name),
17331                cx,
17332            )
17333            .await?;
17334
17335            editor.update(cx, |editor, cx| {
17336                editor.refresh_document_highlights(cx);
17337            })?;
17338            Ok(())
17339        }))
17340    }
17341
17342    fn take_rename(
17343        &mut self,
17344        moving_cursor: bool,
17345        window: &mut Window,
17346        cx: &mut Context<Self>,
17347    ) -> Option<RenameState> {
17348        let rename = self.pending_rename.take()?;
17349        if rename.editor.focus_handle(cx).is_focused(window) {
17350            window.focus(&self.focus_handle);
17351        }
17352
17353        self.remove_blocks(
17354            [rename.block_id].into_iter().collect(),
17355            Some(Autoscroll::fit()),
17356            cx,
17357        );
17358        self.clear_highlights::<Rename>(cx);
17359        self.show_local_selections = true;
17360
17361        if moving_cursor {
17362            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17363                editor
17364                    .selections
17365                    .newest::<usize>(&editor.display_snapshot(cx))
17366                    .head()
17367            });
17368
17369            // Update the selection to match the position of the selection inside
17370            // the rename editor.
17371            let snapshot = self.buffer.read(cx).read(cx);
17372            let rename_range = rename.range.to_offset(&snapshot);
17373            let cursor_in_editor = snapshot
17374                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17375                .min(rename_range.end);
17376            drop(snapshot);
17377
17378            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17379                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17380            });
17381        } else {
17382            self.refresh_document_highlights(cx);
17383        }
17384
17385        Some(rename)
17386    }
17387
17388    pub fn pending_rename(&self) -> Option<&RenameState> {
17389        self.pending_rename.as_ref()
17390    }
17391
17392    fn format(
17393        &mut self,
17394        _: &Format,
17395        window: &mut Window,
17396        cx: &mut Context<Self>,
17397    ) -> Option<Task<Result<()>>> {
17398        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17399
17400        let project = match &self.project {
17401            Some(project) => project.clone(),
17402            None => return None,
17403        };
17404
17405        Some(self.perform_format(
17406            project,
17407            FormatTrigger::Manual,
17408            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17409            window,
17410            cx,
17411        ))
17412    }
17413
17414    fn format_selections(
17415        &mut self,
17416        _: &FormatSelections,
17417        window: &mut Window,
17418        cx: &mut Context<Self>,
17419    ) -> Option<Task<Result<()>>> {
17420        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17421
17422        let project = match &self.project {
17423            Some(project) => project.clone(),
17424            None => return None,
17425        };
17426
17427        let ranges = self
17428            .selections
17429            .all_adjusted(&self.display_snapshot(cx))
17430            .into_iter()
17431            .map(|selection| selection.range())
17432            .collect_vec();
17433
17434        Some(self.perform_format(
17435            project,
17436            FormatTrigger::Manual,
17437            FormatTarget::Ranges(ranges),
17438            window,
17439            cx,
17440        ))
17441    }
17442
17443    fn perform_format(
17444        &mut self,
17445        project: Entity<Project>,
17446        trigger: FormatTrigger,
17447        target: FormatTarget,
17448        window: &mut Window,
17449        cx: &mut Context<Self>,
17450    ) -> Task<Result<()>> {
17451        let buffer = self.buffer.clone();
17452        let (buffers, target) = match target {
17453            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17454            FormatTarget::Ranges(selection_ranges) => {
17455                let multi_buffer = buffer.read(cx);
17456                let snapshot = multi_buffer.read(cx);
17457                let mut buffers = HashSet::default();
17458                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17459                    BTreeMap::new();
17460                for selection_range in selection_ranges {
17461                    for (buffer, buffer_range, _) in
17462                        snapshot.range_to_buffer_ranges(selection_range)
17463                    {
17464                        let buffer_id = buffer.remote_id();
17465                        let start = buffer.anchor_before(buffer_range.start);
17466                        let end = buffer.anchor_after(buffer_range.end);
17467                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17468                        buffer_id_to_ranges
17469                            .entry(buffer_id)
17470                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17471                            .or_insert_with(|| vec![start..end]);
17472                    }
17473                }
17474                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17475            }
17476        };
17477
17478        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17479        let selections_prev = transaction_id_prev
17480            .and_then(|transaction_id_prev| {
17481                // default to selections as they were after the last edit, if we have them,
17482                // instead of how they are now.
17483                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17484                // will take you back to where you made the last edit, instead of staying where you scrolled
17485                self.selection_history
17486                    .transaction(transaction_id_prev)
17487                    .map(|t| t.0.clone())
17488            })
17489            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17490
17491        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17492        let format = project.update(cx, |project, cx| {
17493            project.format(buffers, target, true, trigger, cx)
17494        });
17495
17496        cx.spawn_in(window, async move |editor, cx| {
17497            let transaction = futures::select_biased! {
17498                transaction = format.log_err().fuse() => transaction,
17499                () = timeout => {
17500                    log::warn!("timed out waiting for formatting");
17501                    None
17502                }
17503            };
17504
17505            buffer
17506                .update(cx, |buffer, cx| {
17507                    if let Some(transaction) = transaction
17508                        && !buffer.is_singleton()
17509                    {
17510                        buffer.push_transaction(&transaction.0, cx);
17511                    }
17512                    cx.notify();
17513                })
17514                .ok();
17515
17516            if let Some(transaction_id_now) =
17517                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17518            {
17519                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17520                if has_new_transaction {
17521                    _ = editor.update(cx, |editor, _| {
17522                        editor
17523                            .selection_history
17524                            .insert_transaction(transaction_id_now, selections_prev);
17525                    });
17526                }
17527            }
17528
17529            Ok(())
17530        })
17531    }
17532
17533    fn organize_imports(
17534        &mut self,
17535        _: &OrganizeImports,
17536        window: &mut Window,
17537        cx: &mut Context<Self>,
17538    ) -> Option<Task<Result<()>>> {
17539        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17540        let project = match &self.project {
17541            Some(project) => project.clone(),
17542            None => return None,
17543        };
17544        Some(self.perform_code_action_kind(
17545            project,
17546            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17547            window,
17548            cx,
17549        ))
17550    }
17551
17552    fn perform_code_action_kind(
17553        &mut self,
17554        project: Entity<Project>,
17555        kind: CodeActionKind,
17556        window: &mut Window,
17557        cx: &mut Context<Self>,
17558    ) -> Task<Result<()>> {
17559        let buffer = self.buffer.clone();
17560        let buffers = buffer.read(cx).all_buffers();
17561        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17562        let apply_action = project.update(cx, |project, cx| {
17563            project.apply_code_action_kind(buffers, kind, true, cx)
17564        });
17565        cx.spawn_in(window, async move |_, cx| {
17566            let transaction = futures::select_biased! {
17567                () = timeout => {
17568                    log::warn!("timed out waiting for executing code action");
17569                    None
17570                }
17571                transaction = apply_action.log_err().fuse() => transaction,
17572            };
17573            buffer
17574                .update(cx, |buffer, cx| {
17575                    // check if we need this
17576                    if let Some(transaction) = transaction
17577                        && !buffer.is_singleton()
17578                    {
17579                        buffer.push_transaction(&transaction.0, cx);
17580                    }
17581                    cx.notify();
17582                })
17583                .ok();
17584            Ok(())
17585        })
17586    }
17587
17588    pub fn restart_language_server(
17589        &mut self,
17590        _: &RestartLanguageServer,
17591        _: &mut Window,
17592        cx: &mut Context<Self>,
17593    ) {
17594        if let Some(project) = self.project.clone() {
17595            self.buffer.update(cx, |multi_buffer, cx| {
17596                project.update(cx, |project, cx| {
17597                    project.restart_language_servers_for_buffers(
17598                        multi_buffer.all_buffers().into_iter().collect(),
17599                        HashSet::default(),
17600                        cx,
17601                    );
17602                });
17603            })
17604        }
17605    }
17606
17607    pub fn stop_language_server(
17608        &mut self,
17609        _: &StopLanguageServer,
17610        _: &mut Window,
17611        cx: &mut Context<Self>,
17612    ) {
17613        if let Some(project) = self.project.clone() {
17614            self.buffer.update(cx, |multi_buffer, cx| {
17615                project.update(cx, |project, cx| {
17616                    project.stop_language_servers_for_buffers(
17617                        multi_buffer.all_buffers().into_iter().collect(),
17618                        HashSet::default(),
17619                        cx,
17620                    );
17621                    cx.emit(project::Event::RefreshInlayHints);
17622                });
17623            });
17624        }
17625    }
17626
17627    fn cancel_language_server_work(
17628        workspace: &mut Workspace,
17629        _: &actions::CancelLanguageServerWork,
17630        _: &mut Window,
17631        cx: &mut Context<Workspace>,
17632    ) {
17633        let project = workspace.project();
17634        let buffers = workspace
17635            .active_item(cx)
17636            .and_then(|item| item.act_as::<Editor>(cx))
17637            .map_or(HashSet::default(), |editor| {
17638                editor.read(cx).buffer.read(cx).all_buffers()
17639            });
17640        project.update(cx, |project, cx| {
17641            project.cancel_language_server_work_for_buffers(buffers, cx);
17642        });
17643    }
17644
17645    fn show_character_palette(
17646        &mut self,
17647        _: &ShowCharacterPalette,
17648        window: &mut Window,
17649        _: &mut Context<Self>,
17650    ) {
17651        window.show_character_palette();
17652    }
17653
17654    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17655        if !self.diagnostics_enabled() {
17656            return;
17657        }
17658
17659        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17660            let buffer = self.buffer.read(cx).snapshot(cx);
17661            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17662            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17663            let is_valid = buffer
17664                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17665                .any(|entry| {
17666                    entry.diagnostic.is_primary
17667                        && !entry.range.is_empty()
17668                        && entry.range.start == primary_range_start
17669                        && entry.diagnostic.message == active_diagnostics.active_message
17670                });
17671
17672            if !is_valid {
17673                self.dismiss_diagnostics(cx);
17674            }
17675        }
17676    }
17677
17678    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17679        match &self.active_diagnostics {
17680            ActiveDiagnostic::Group(group) => Some(group),
17681            _ => None,
17682        }
17683    }
17684
17685    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17686        if !self.diagnostics_enabled() {
17687            return;
17688        }
17689        self.dismiss_diagnostics(cx);
17690        self.active_diagnostics = ActiveDiagnostic::All;
17691    }
17692
17693    fn activate_diagnostics(
17694        &mut self,
17695        buffer_id: BufferId,
17696        diagnostic: DiagnosticEntryRef<'_, usize>,
17697        window: &mut Window,
17698        cx: &mut Context<Self>,
17699    ) {
17700        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17701            return;
17702        }
17703        self.dismiss_diagnostics(cx);
17704        let snapshot = self.snapshot(window, cx);
17705        let buffer = self.buffer.read(cx).snapshot(cx);
17706        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17707            return;
17708        };
17709
17710        let diagnostic_group = buffer
17711            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17712            .collect::<Vec<_>>();
17713
17714        let blocks =
17715            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17716
17717        let blocks = self.display_map.update(cx, |display_map, cx| {
17718            display_map.insert_blocks(blocks, cx).into_iter().collect()
17719        });
17720        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17721            active_range: buffer.anchor_before(diagnostic.range.start)
17722                ..buffer.anchor_after(diagnostic.range.end),
17723            active_message: diagnostic.diagnostic.message.clone(),
17724            group_id: diagnostic.diagnostic.group_id,
17725            blocks,
17726        });
17727        cx.notify();
17728    }
17729
17730    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17731        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17732            return;
17733        };
17734
17735        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17736        if let ActiveDiagnostic::Group(group) = prev {
17737            self.display_map.update(cx, |display_map, cx| {
17738                display_map.remove_blocks(group.blocks, cx);
17739            });
17740            cx.notify();
17741        }
17742    }
17743
17744    /// Disable inline diagnostics rendering for this editor.
17745    pub fn disable_inline_diagnostics(&mut self) {
17746        self.inline_diagnostics_enabled = false;
17747        self.inline_diagnostics_update = Task::ready(());
17748        self.inline_diagnostics.clear();
17749    }
17750
17751    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17752        self.diagnostics_enabled = false;
17753        self.dismiss_diagnostics(cx);
17754        self.inline_diagnostics_update = Task::ready(());
17755        self.inline_diagnostics.clear();
17756    }
17757
17758    pub fn disable_word_completions(&mut self) {
17759        self.word_completions_enabled = false;
17760    }
17761
17762    pub fn diagnostics_enabled(&self) -> bool {
17763        self.diagnostics_enabled && self.mode.is_full()
17764    }
17765
17766    pub fn inline_diagnostics_enabled(&self) -> bool {
17767        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17768    }
17769
17770    pub fn show_inline_diagnostics(&self) -> bool {
17771        self.show_inline_diagnostics
17772    }
17773
17774    pub fn toggle_inline_diagnostics(
17775        &mut self,
17776        _: &ToggleInlineDiagnostics,
17777        window: &mut Window,
17778        cx: &mut Context<Editor>,
17779    ) {
17780        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17781        self.refresh_inline_diagnostics(false, window, cx);
17782    }
17783
17784    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17785        self.diagnostics_max_severity = severity;
17786        self.display_map.update(cx, |display_map, _| {
17787            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17788        });
17789    }
17790
17791    pub fn toggle_diagnostics(
17792        &mut self,
17793        _: &ToggleDiagnostics,
17794        window: &mut Window,
17795        cx: &mut Context<Editor>,
17796    ) {
17797        if !self.diagnostics_enabled() {
17798            return;
17799        }
17800
17801        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17802            EditorSettings::get_global(cx)
17803                .diagnostics_max_severity
17804                .filter(|severity| severity != &DiagnosticSeverity::Off)
17805                .unwrap_or(DiagnosticSeverity::Hint)
17806        } else {
17807            DiagnosticSeverity::Off
17808        };
17809        self.set_max_diagnostics_severity(new_severity, cx);
17810        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17811            self.active_diagnostics = ActiveDiagnostic::None;
17812            self.inline_diagnostics_update = Task::ready(());
17813            self.inline_diagnostics.clear();
17814        } else {
17815            self.refresh_inline_diagnostics(false, window, cx);
17816        }
17817
17818        cx.notify();
17819    }
17820
17821    pub fn toggle_minimap(
17822        &mut self,
17823        _: &ToggleMinimap,
17824        window: &mut Window,
17825        cx: &mut Context<Editor>,
17826    ) {
17827        if self.supports_minimap(cx) {
17828            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17829        }
17830    }
17831
17832    fn refresh_inline_diagnostics(
17833        &mut self,
17834        debounce: bool,
17835        window: &mut Window,
17836        cx: &mut Context<Self>,
17837    ) {
17838        let max_severity = ProjectSettings::get_global(cx)
17839            .diagnostics
17840            .inline
17841            .max_severity
17842            .unwrap_or(self.diagnostics_max_severity);
17843
17844        if !self.inline_diagnostics_enabled()
17845            || !self.show_inline_diagnostics
17846            || max_severity == DiagnosticSeverity::Off
17847        {
17848            self.inline_diagnostics_update = Task::ready(());
17849            self.inline_diagnostics.clear();
17850            return;
17851        }
17852
17853        let debounce_ms = ProjectSettings::get_global(cx)
17854            .diagnostics
17855            .inline
17856            .update_debounce_ms;
17857        let debounce = if debounce && debounce_ms > 0 {
17858            Some(Duration::from_millis(debounce_ms))
17859        } else {
17860            None
17861        };
17862        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17863            if let Some(debounce) = debounce {
17864                cx.background_executor().timer(debounce).await;
17865            }
17866            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17867                editor
17868                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17869                    .ok()
17870            }) else {
17871                return;
17872            };
17873
17874            let new_inline_diagnostics = cx
17875                .background_spawn(async move {
17876                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17877                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17878                        let message = diagnostic_entry
17879                            .diagnostic
17880                            .message
17881                            .split_once('\n')
17882                            .map(|(line, _)| line)
17883                            .map(SharedString::new)
17884                            .unwrap_or_else(|| {
17885                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17886                            });
17887                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17888                        let (Ok(i) | Err(i)) = inline_diagnostics
17889                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17890                        inline_diagnostics.insert(
17891                            i,
17892                            (
17893                                start_anchor,
17894                                InlineDiagnostic {
17895                                    message,
17896                                    group_id: diagnostic_entry.diagnostic.group_id,
17897                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17898                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17899                                    severity: diagnostic_entry.diagnostic.severity,
17900                                },
17901                            ),
17902                        );
17903                    }
17904                    inline_diagnostics
17905                })
17906                .await;
17907
17908            editor
17909                .update(cx, |editor, cx| {
17910                    editor.inline_diagnostics = new_inline_diagnostics;
17911                    cx.notify();
17912                })
17913                .ok();
17914        });
17915    }
17916
17917    fn pull_diagnostics(
17918        &mut self,
17919        buffer_id: Option<BufferId>,
17920        window: &Window,
17921        cx: &mut Context<Self>,
17922    ) -> Option<()> {
17923        if self.ignore_lsp_data() {
17924            return None;
17925        }
17926        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17927            .diagnostics
17928            .lsp_pull_diagnostics;
17929        if !pull_diagnostics_settings.enabled {
17930            return None;
17931        }
17932        let project = self.project()?.downgrade();
17933        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17934        let mut buffers = self.buffer.read(cx).all_buffers();
17935        buffers.retain(|buffer| {
17936            let buffer_id_to_retain = buffer.read(cx).remote_id();
17937            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17938                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17939        });
17940        if buffers.is_empty() {
17941            self.pull_diagnostics_task = Task::ready(());
17942            return None;
17943        }
17944
17945        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17946            cx.background_executor().timer(debounce).await;
17947
17948            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17949                buffers
17950                    .into_iter()
17951                    .filter_map(|buffer| {
17952                        project
17953                            .update(cx, |project, cx| {
17954                                project.lsp_store().update(cx, |lsp_store, cx| {
17955                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17956                                })
17957                            })
17958                            .ok()
17959                    })
17960                    .collect::<FuturesUnordered<_>>()
17961            }) else {
17962                return;
17963            };
17964
17965            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17966                match pull_task {
17967                    Ok(()) => {
17968                        if editor
17969                            .update_in(cx, |editor, window, cx| {
17970                                editor.update_diagnostics_state(window, cx);
17971                            })
17972                            .is_err()
17973                        {
17974                            return;
17975                        }
17976                    }
17977                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17978                }
17979            }
17980        });
17981
17982        Some(())
17983    }
17984
17985    pub fn set_selections_from_remote(
17986        &mut self,
17987        selections: Vec<Selection<Anchor>>,
17988        pending_selection: Option<Selection<Anchor>>,
17989        window: &mut Window,
17990        cx: &mut Context<Self>,
17991    ) {
17992        let old_cursor_position = self.selections.newest_anchor().head();
17993        self.selections.change_with(cx, |s| {
17994            s.select_anchors(selections);
17995            if let Some(pending_selection) = pending_selection {
17996                s.set_pending(pending_selection, SelectMode::Character);
17997            } else {
17998                s.clear_pending();
17999            }
18000        });
18001        self.selections_did_change(
18002            false,
18003            &old_cursor_position,
18004            SelectionEffects::default(),
18005            window,
18006            cx,
18007        );
18008    }
18009
18010    pub fn transact(
18011        &mut self,
18012        window: &mut Window,
18013        cx: &mut Context<Self>,
18014        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18015    ) -> Option<TransactionId> {
18016        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18017            this.start_transaction_at(Instant::now(), window, cx);
18018            update(this, window, cx);
18019            this.end_transaction_at(Instant::now(), cx)
18020        })
18021    }
18022
18023    pub fn start_transaction_at(
18024        &mut self,
18025        now: Instant,
18026        window: &mut Window,
18027        cx: &mut Context<Self>,
18028    ) -> Option<TransactionId> {
18029        self.end_selection(window, cx);
18030        if let Some(tx_id) = self
18031            .buffer
18032            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18033        {
18034            self.selection_history
18035                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18036            cx.emit(EditorEvent::TransactionBegun {
18037                transaction_id: tx_id,
18038            });
18039            Some(tx_id)
18040        } else {
18041            None
18042        }
18043    }
18044
18045    pub fn end_transaction_at(
18046        &mut self,
18047        now: Instant,
18048        cx: &mut Context<Self>,
18049    ) -> Option<TransactionId> {
18050        if let Some(transaction_id) = self
18051            .buffer
18052            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18053        {
18054            if let Some((_, end_selections)) =
18055                self.selection_history.transaction_mut(transaction_id)
18056            {
18057                *end_selections = Some(self.selections.disjoint_anchors_arc());
18058            } else {
18059                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18060            }
18061
18062            cx.emit(EditorEvent::Edited { transaction_id });
18063            Some(transaction_id)
18064        } else {
18065            None
18066        }
18067    }
18068
18069    pub fn modify_transaction_selection_history(
18070        &mut self,
18071        transaction_id: TransactionId,
18072        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18073    ) -> bool {
18074        self.selection_history
18075            .transaction_mut(transaction_id)
18076            .map(modify)
18077            .is_some()
18078    }
18079
18080    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18081        if self.selection_mark_mode {
18082            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18083                s.move_with(|_, sel| {
18084                    sel.collapse_to(sel.head(), SelectionGoal::None);
18085                });
18086            })
18087        }
18088        self.selection_mark_mode = true;
18089        cx.notify();
18090    }
18091
18092    pub fn swap_selection_ends(
18093        &mut self,
18094        _: &actions::SwapSelectionEnds,
18095        window: &mut Window,
18096        cx: &mut Context<Self>,
18097    ) {
18098        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18099            s.move_with(|_, sel| {
18100                if sel.start != sel.end {
18101                    sel.reversed = !sel.reversed
18102                }
18103            });
18104        });
18105        self.request_autoscroll(Autoscroll::newest(), cx);
18106        cx.notify();
18107    }
18108
18109    pub fn toggle_focus(
18110        workspace: &mut Workspace,
18111        _: &actions::ToggleFocus,
18112        window: &mut Window,
18113        cx: &mut Context<Workspace>,
18114    ) {
18115        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18116            return;
18117        };
18118        workspace.activate_item(&item, true, true, window, cx);
18119    }
18120
18121    pub fn toggle_fold(
18122        &mut self,
18123        _: &actions::ToggleFold,
18124        window: &mut Window,
18125        cx: &mut Context<Self>,
18126    ) {
18127        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18128            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18129            let selection = self.selections.newest::<Point>(&display_map);
18130
18131            let range = if selection.is_empty() {
18132                let point = selection.head().to_display_point(&display_map);
18133                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18134                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18135                    .to_point(&display_map);
18136                start..end
18137            } else {
18138                selection.range()
18139            };
18140            if display_map.folds_in_range(range).next().is_some() {
18141                self.unfold_lines(&Default::default(), window, cx)
18142            } else {
18143                self.fold(&Default::default(), window, cx)
18144            }
18145        } else {
18146            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18147            let buffer_ids: HashSet<_> = self
18148                .selections
18149                .disjoint_anchor_ranges()
18150                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18151                .collect();
18152
18153            let should_unfold = buffer_ids
18154                .iter()
18155                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18156
18157            for buffer_id in buffer_ids {
18158                if should_unfold {
18159                    self.unfold_buffer(buffer_id, cx);
18160                } else {
18161                    self.fold_buffer(buffer_id, cx);
18162                }
18163            }
18164        }
18165    }
18166
18167    pub fn toggle_fold_recursive(
18168        &mut self,
18169        _: &actions::ToggleFoldRecursive,
18170        window: &mut Window,
18171        cx: &mut Context<Self>,
18172    ) {
18173        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18174
18175        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18176        let range = if selection.is_empty() {
18177            let point = selection.head().to_display_point(&display_map);
18178            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18179            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18180                .to_point(&display_map);
18181            start..end
18182        } else {
18183            selection.range()
18184        };
18185        if display_map.folds_in_range(range).next().is_some() {
18186            self.unfold_recursive(&Default::default(), window, cx)
18187        } else {
18188            self.fold_recursive(&Default::default(), window, cx)
18189        }
18190    }
18191
18192    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18193        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18194            let mut to_fold = Vec::new();
18195            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18196            let selections = self.selections.all_adjusted(&display_map);
18197
18198            for selection in selections {
18199                let range = selection.range().sorted();
18200                let buffer_start_row = range.start.row;
18201
18202                if range.start.row != range.end.row {
18203                    let mut found = false;
18204                    let mut row = range.start.row;
18205                    while row <= range.end.row {
18206                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18207                        {
18208                            found = true;
18209                            row = crease.range().end.row + 1;
18210                            to_fold.push(crease);
18211                        } else {
18212                            row += 1
18213                        }
18214                    }
18215                    if found {
18216                        continue;
18217                    }
18218                }
18219
18220                for row in (0..=range.start.row).rev() {
18221                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18222                        && crease.range().end.row >= buffer_start_row
18223                    {
18224                        to_fold.push(crease);
18225                        if row <= range.start.row {
18226                            break;
18227                        }
18228                    }
18229                }
18230            }
18231
18232            self.fold_creases(to_fold, true, window, cx);
18233        } else {
18234            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18235            let buffer_ids = self
18236                .selections
18237                .disjoint_anchor_ranges()
18238                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18239                .collect::<HashSet<_>>();
18240            for buffer_id in buffer_ids {
18241                self.fold_buffer(buffer_id, cx);
18242            }
18243        }
18244    }
18245
18246    pub fn toggle_fold_all(
18247        &mut self,
18248        _: &actions::ToggleFoldAll,
18249        window: &mut Window,
18250        cx: &mut Context<Self>,
18251    ) {
18252        if self.buffer.read(cx).is_singleton() {
18253            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18254            let has_folds = display_map
18255                .folds_in_range(0..display_map.buffer_snapshot().len())
18256                .next()
18257                .is_some();
18258
18259            if has_folds {
18260                self.unfold_all(&actions::UnfoldAll, window, cx);
18261            } else {
18262                self.fold_all(&actions::FoldAll, window, cx);
18263            }
18264        } else {
18265            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18266            let should_unfold = buffer_ids
18267                .iter()
18268                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18269
18270            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18271                editor
18272                    .update_in(cx, |editor, _, cx| {
18273                        for buffer_id in buffer_ids {
18274                            if should_unfold {
18275                                editor.unfold_buffer(buffer_id, cx);
18276                            } else {
18277                                editor.fold_buffer(buffer_id, cx);
18278                            }
18279                        }
18280                    })
18281                    .ok();
18282            });
18283        }
18284    }
18285
18286    fn fold_at_level(
18287        &mut self,
18288        fold_at: &FoldAtLevel,
18289        window: &mut Window,
18290        cx: &mut Context<Self>,
18291    ) {
18292        if !self.buffer.read(cx).is_singleton() {
18293            return;
18294        }
18295
18296        let fold_at_level = fold_at.0;
18297        let snapshot = self.buffer.read(cx).snapshot(cx);
18298        let mut to_fold = Vec::new();
18299        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18300
18301        let row_ranges_to_keep: Vec<Range<u32>> = self
18302            .selections
18303            .all::<Point>(&self.display_snapshot(cx))
18304            .into_iter()
18305            .map(|sel| sel.start.row..sel.end.row)
18306            .collect();
18307
18308        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18309            while start_row < end_row {
18310                match self
18311                    .snapshot(window, cx)
18312                    .crease_for_buffer_row(MultiBufferRow(start_row))
18313                {
18314                    Some(crease) => {
18315                        let nested_start_row = crease.range().start.row + 1;
18316                        let nested_end_row = crease.range().end.row;
18317
18318                        if current_level < fold_at_level {
18319                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18320                        } else if current_level == fold_at_level {
18321                            // Fold iff there is no selection completely contained within the fold region
18322                            if !row_ranges_to_keep.iter().any(|selection| {
18323                                selection.end >= nested_start_row
18324                                    && selection.start <= nested_end_row
18325                            }) {
18326                                to_fold.push(crease);
18327                            }
18328                        }
18329
18330                        start_row = nested_end_row + 1;
18331                    }
18332                    None => start_row += 1,
18333                }
18334            }
18335        }
18336
18337        self.fold_creases(to_fold, true, window, cx);
18338    }
18339
18340    pub fn fold_at_level_1(
18341        &mut self,
18342        _: &actions::FoldAtLevel1,
18343        window: &mut Window,
18344        cx: &mut Context<Self>,
18345    ) {
18346        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18347    }
18348
18349    pub fn fold_at_level_2(
18350        &mut self,
18351        _: &actions::FoldAtLevel2,
18352        window: &mut Window,
18353        cx: &mut Context<Self>,
18354    ) {
18355        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18356    }
18357
18358    pub fn fold_at_level_3(
18359        &mut self,
18360        _: &actions::FoldAtLevel3,
18361        window: &mut Window,
18362        cx: &mut Context<Self>,
18363    ) {
18364        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18365    }
18366
18367    pub fn fold_at_level_4(
18368        &mut self,
18369        _: &actions::FoldAtLevel4,
18370        window: &mut Window,
18371        cx: &mut Context<Self>,
18372    ) {
18373        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18374    }
18375
18376    pub fn fold_at_level_5(
18377        &mut self,
18378        _: &actions::FoldAtLevel5,
18379        window: &mut Window,
18380        cx: &mut Context<Self>,
18381    ) {
18382        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18383    }
18384
18385    pub fn fold_at_level_6(
18386        &mut self,
18387        _: &actions::FoldAtLevel6,
18388        window: &mut Window,
18389        cx: &mut Context<Self>,
18390    ) {
18391        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18392    }
18393
18394    pub fn fold_at_level_7(
18395        &mut self,
18396        _: &actions::FoldAtLevel7,
18397        window: &mut Window,
18398        cx: &mut Context<Self>,
18399    ) {
18400        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18401    }
18402
18403    pub fn fold_at_level_8(
18404        &mut self,
18405        _: &actions::FoldAtLevel8,
18406        window: &mut Window,
18407        cx: &mut Context<Self>,
18408    ) {
18409        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18410    }
18411
18412    pub fn fold_at_level_9(
18413        &mut self,
18414        _: &actions::FoldAtLevel9,
18415        window: &mut Window,
18416        cx: &mut Context<Self>,
18417    ) {
18418        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18419    }
18420
18421    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18422        if self.buffer.read(cx).is_singleton() {
18423            let mut fold_ranges = Vec::new();
18424            let snapshot = self.buffer.read(cx).snapshot(cx);
18425
18426            for row in 0..snapshot.max_row().0 {
18427                if let Some(foldable_range) = self
18428                    .snapshot(window, cx)
18429                    .crease_for_buffer_row(MultiBufferRow(row))
18430                {
18431                    fold_ranges.push(foldable_range);
18432                }
18433            }
18434
18435            self.fold_creases(fold_ranges, true, window, cx);
18436        } else {
18437            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18438                editor
18439                    .update_in(cx, |editor, _, cx| {
18440                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18441                            editor.fold_buffer(buffer_id, cx);
18442                        }
18443                    })
18444                    .ok();
18445            });
18446        }
18447    }
18448
18449    pub fn fold_function_bodies(
18450        &mut self,
18451        _: &actions::FoldFunctionBodies,
18452        window: &mut Window,
18453        cx: &mut Context<Self>,
18454    ) {
18455        let snapshot = self.buffer.read(cx).snapshot(cx);
18456
18457        let ranges = snapshot
18458            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18459            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18460            .collect::<Vec<_>>();
18461
18462        let creases = ranges
18463            .into_iter()
18464            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18465            .collect();
18466
18467        self.fold_creases(creases, true, window, cx);
18468    }
18469
18470    pub fn fold_recursive(
18471        &mut self,
18472        _: &actions::FoldRecursive,
18473        window: &mut Window,
18474        cx: &mut Context<Self>,
18475    ) {
18476        let mut to_fold = Vec::new();
18477        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18478        let selections = self.selections.all_adjusted(&display_map);
18479
18480        for selection in selections {
18481            let range = selection.range().sorted();
18482            let buffer_start_row = range.start.row;
18483
18484            if range.start.row != range.end.row {
18485                let mut found = false;
18486                for row in range.start.row..=range.end.row {
18487                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18488                        found = true;
18489                        to_fold.push(crease);
18490                    }
18491                }
18492                if found {
18493                    continue;
18494                }
18495            }
18496
18497            for row in (0..=range.start.row).rev() {
18498                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18499                    if crease.range().end.row >= buffer_start_row {
18500                        to_fold.push(crease);
18501                    } else {
18502                        break;
18503                    }
18504                }
18505            }
18506        }
18507
18508        self.fold_creases(to_fold, true, window, cx);
18509    }
18510
18511    pub fn fold_at(
18512        &mut self,
18513        buffer_row: MultiBufferRow,
18514        window: &mut Window,
18515        cx: &mut Context<Self>,
18516    ) {
18517        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18518
18519        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18520            let autoscroll = self
18521                .selections
18522                .all::<Point>(&display_map)
18523                .iter()
18524                .any(|selection| crease.range().overlaps(&selection.range()));
18525
18526            self.fold_creases(vec![crease], autoscroll, window, cx);
18527        }
18528    }
18529
18530    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18531        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18532            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18533            let buffer = display_map.buffer_snapshot();
18534            let selections = self.selections.all::<Point>(&display_map);
18535            let ranges = selections
18536                .iter()
18537                .map(|s| {
18538                    let range = s.display_range(&display_map).sorted();
18539                    let mut start = range.start.to_point(&display_map);
18540                    let mut end = range.end.to_point(&display_map);
18541                    start.column = 0;
18542                    end.column = buffer.line_len(MultiBufferRow(end.row));
18543                    start..end
18544                })
18545                .collect::<Vec<_>>();
18546
18547            self.unfold_ranges(&ranges, true, true, cx);
18548        } else {
18549            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18550            let buffer_ids = self
18551                .selections
18552                .disjoint_anchor_ranges()
18553                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18554                .collect::<HashSet<_>>();
18555            for buffer_id in buffer_ids {
18556                self.unfold_buffer(buffer_id, cx);
18557            }
18558        }
18559    }
18560
18561    pub fn unfold_recursive(
18562        &mut self,
18563        _: &UnfoldRecursive,
18564        _window: &mut Window,
18565        cx: &mut Context<Self>,
18566    ) {
18567        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18568        let selections = self.selections.all::<Point>(&display_map);
18569        let ranges = selections
18570            .iter()
18571            .map(|s| {
18572                let mut range = s.display_range(&display_map).sorted();
18573                *range.start.column_mut() = 0;
18574                *range.end.column_mut() = display_map.line_len(range.end.row());
18575                let start = range.start.to_point(&display_map);
18576                let end = range.end.to_point(&display_map);
18577                start..end
18578            })
18579            .collect::<Vec<_>>();
18580
18581        self.unfold_ranges(&ranges, true, true, cx);
18582    }
18583
18584    pub fn unfold_at(
18585        &mut self,
18586        buffer_row: MultiBufferRow,
18587        _window: &mut Window,
18588        cx: &mut Context<Self>,
18589    ) {
18590        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18591
18592        let intersection_range = Point::new(buffer_row.0, 0)
18593            ..Point::new(
18594                buffer_row.0,
18595                display_map.buffer_snapshot().line_len(buffer_row),
18596            );
18597
18598        let autoscroll = self
18599            .selections
18600            .all::<Point>(&display_map)
18601            .iter()
18602            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18603
18604        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18605    }
18606
18607    pub fn unfold_all(
18608        &mut self,
18609        _: &actions::UnfoldAll,
18610        _window: &mut Window,
18611        cx: &mut Context<Self>,
18612    ) {
18613        if self.buffer.read(cx).is_singleton() {
18614            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18615            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18616        } else {
18617            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18618                editor
18619                    .update(cx, |editor, cx| {
18620                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18621                            editor.unfold_buffer(buffer_id, cx);
18622                        }
18623                    })
18624                    .ok();
18625            });
18626        }
18627    }
18628
18629    pub fn fold_selected_ranges(
18630        &mut self,
18631        _: &FoldSelectedRanges,
18632        window: &mut Window,
18633        cx: &mut Context<Self>,
18634    ) {
18635        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18636        let selections = self.selections.all_adjusted(&display_map);
18637        let ranges = selections
18638            .into_iter()
18639            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18640            .collect::<Vec<_>>();
18641        self.fold_creases(ranges, true, window, cx);
18642    }
18643
18644    pub fn fold_ranges<T: ToOffset + Clone>(
18645        &mut self,
18646        ranges: Vec<Range<T>>,
18647        auto_scroll: bool,
18648        window: &mut Window,
18649        cx: &mut Context<Self>,
18650    ) {
18651        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18652        let ranges = ranges
18653            .into_iter()
18654            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18655            .collect::<Vec<_>>();
18656        self.fold_creases(ranges, auto_scroll, window, cx);
18657    }
18658
18659    pub fn fold_creases<T: ToOffset + Clone>(
18660        &mut self,
18661        creases: Vec<Crease<T>>,
18662        auto_scroll: bool,
18663        _window: &mut Window,
18664        cx: &mut Context<Self>,
18665    ) {
18666        if creases.is_empty() {
18667            return;
18668        }
18669
18670        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18671
18672        if auto_scroll {
18673            self.request_autoscroll(Autoscroll::fit(), cx);
18674        }
18675
18676        cx.notify();
18677
18678        self.scrollbar_marker_state.dirty = true;
18679        self.folds_did_change(cx);
18680    }
18681
18682    /// Removes any folds whose ranges intersect any of the given ranges.
18683    pub fn unfold_ranges<T: ToOffset + Clone>(
18684        &mut self,
18685        ranges: &[Range<T>],
18686        inclusive: bool,
18687        auto_scroll: bool,
18688        cx: &mut Context<Self>,
18689    ) {
18690        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18691            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18692        });
18693        self.folds_did_change(cx);
18694    }
18695
18696    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18697        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18698            return;
18699        }
18700        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18701        self.display_map.update(cx, |display_map, cx| {
18702            display_map.fold_buffers([buffer_id], cx)
18703        });
18704        cx.emit(EditorEvent::BufferFoldToggled {
18705            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18706            folded: true,
18707        });
18708        cx.notify();
18709    }
18710
18711    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18712        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18713            return;
18714        }
18715        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18716        self.display_map.update(cx, |display_map, cx| {
18717            display_map.unfold_buffers([buffer_id], cx);
18718        });
18719        cx.emit(EditorEvent::BufferFoldToggled {
18720            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18721            folded: false,
18722        });
18723        cx.notify();
18724    }
18725
18726    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18727        self.display_map.read(cx).is_buffer_folded(buffer)
18728    }
18729
18730    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18731        self.display_map.read(cx).folded_buffers()
18732    }
18733
18734    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18735        self.display_map.update(cx, |display_map, cx| {
18736            display_map.disable_header_for_buffer(buffer_id, cx);
18737        });
18738        cx.notify();
18739    }
18740
18741    /// Removes any folds with the given ranges.
18742    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18743        &mut self,
18744        ranges: &[Range<T>],
18745        type_id: TypeId,
18746        auto_scroll: bool,
18747        cx: &mut Context<Self>,
18748    ) {
18749        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18750            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18751        });
18752        self.folds_did_change(cx);
18753    }
18754
18755    fn remove_folds_with<T: ToOffset + Clone>(
18756        &mut self,
18757        ranges: &[Range<T>],
18758        auto_scroll: bool,
18759        cx: &mut Context<Self>,
18760        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18761    ) {
18762        if ranges.is_empty() {
18763            return;
18764        }
18765
18766        let mut buffers_affected = HashSet::default();
18767        let multi_buffer = self.buffer().read(cx);
18768        for range in ranges {
18769            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18770                buffers_affected.insert(buffer.read(cx).remote_id());
18771            };
18772        }
18773
18774        self.display_map.update(cx, update);
18775
18776        if auto_scroll {
18777            self.request_autoscroll(Autoscroll::fit(), cx);
18778        }
18779
18780        cx.notify();
18781        self.scrollbar_marker_state.dirty = true;
18782        self.active_indent_guides_state.dirty = true;
18783    }
18784
18785    pub fn update_renderer_widths(
18786        &mut self,
18787        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18788        cx: &mut Context<Self>,
18789    ) -> bool {
18790        self.display_map
18791            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18792    }
18793
18794    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18795        self.display_map.read(cx).fold_placeholder.clone()
18796    }
18797
18798    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18799        self.buffer.update(cx, |buffer, cx| {
18800            buffer.set_all_diff_hunks_expanded(cx);
18801        });
18802    }
18803
18804    pub fn expand_all_diff_hunks(
18805        &mut self,
18806        _: &ExpandAllDiffHunks,
18807        _window: &mut Window,
18808        cx: &mut Context<Self>,
18809    ) {
18810        self.buffer.update(cx, |buffer, cx| {
18811            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18812        });
18813    }
18814
18815    pub fn collapse_all_diff_hunks(
18816        &mut self,
18817        _: &CollapseAllDiffHunks,
18818        _window: &mut Window,
18819        cx: &mut Context<Self>,
18820    ) {
18821        self.buffer.update(cx, |buffer, cx| {
18822            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18823        });
18824    }
18825
18826    pub fn toggle_selected_diff_hunks(
18827        &mut self,
18828        _: &ToggleSelectedDiffHunks,
18829        _window: &mut Window,
18830        cx: &mut Context<Self>,
18831    ) {
18832        let ranges: Vec<_> = self
18833            .selections
18834            .disjoint_anchors()
18835            .iter()
18836            .map(|s| s.range())
18837            .collect();
18838        self.toggle_diff_hunks_in_ranges(ranges, cx);
18839    }
18840
18841    pub fn diff_hunks_in_ranges<'a>(
18842        &'a self,
18843        ranges: &'a [Range<Anchor>],
18844        buffer: &'a MultiBufferSnapshot,
18845    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18846        ranges.iter().flat_map(move |range| {
18847            let end_excerpt_id = range.end.excerpt_id;
18848            let range = range.to_point(buffer);
18849            let mut peek_end = range.end;
18850            if range.end.row < buffer.max_row().0 {
18851                peek_end = Point::new(range.end.row + 1, 0);
18852            }
18853            buffer
18854                .diff_hunks_in_range(range.start..peek_end)
18855                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18856        })
18857    }
18858
18859    pub fn has_stageable_diff_hunks_in_ranges(
18860        &self,
18861        ranges: &[Range<Anchor>],
18862        snapshot: &MultiBufferSnapshot,
18863    ) -> bool {
18864        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18865        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18866    }
18867
18868    pub fn toggle_staged_selected_diff_hunks(
18869        &mut self,
18870        _: &::git::ToggleStaged,
18871        _: &mut Window,
18872        cx: &mut Context<Self>,
18873    ) {
18874        let snapshot = self.buffer.read(cx).snapshot(cx);
18875        let ranges: Vec<_> = self
18876            .selections
18877            .disjoint_anchors()
18878            .iter()
18879            .map(|s| s.range())
18880            .collect();
18881        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18882        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18883    }
18884
18885    pub fn set_render_diff_hunk_controls(
18886        &mut self,
18887        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18888        cx: &mut Context<Self>,
18889    ) {
18890        self.render_diff_hunk_controls = render_diff_hunk_controls;
18891        cx.notify();
18892    }
18893
18894    pub fn stage_and_next(
18895        &mut self,
18896        _: &::git::StageAndNext,
18897        window: &mut Window,
18898        cx: &mut Context<Self>,
18899    ) {
18900        self.do_stage_or_unstage_and_next(true, window, cx);
18901    }
18902
18903    pub fn unstage_and_next(
18904        &mut self,
18905        _: &::git::UnstageAndNext,
18906        window: &mut Window,
18907        cx: &mut Context<Self>,
18908    ) {
18909        self.do_stage_or_unstage_and_next(false, window, cx);
18910    }
18911
18912    pub fn stage_or_unstage_diff_hunks(
18913        &mut self,
18914        stage: bool,
18915        ranges: Vec<Range<Anchor>>,
18916        cx: &mut Context<Self>,
18917    ) {
18918        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18919        cx.spawn(async move |this, cx| {
18920            task.await?;
18921            this.update(cx, |this, cx| {
18922                let snapshot = this.buffer.read(cx).snapshot(cx);
18923                let chunk_by = this
18924                    .diff_hunks_in_ranges(&ranges, &snapshot)
18925                    .chunk_by(|hunk| hunk.buffer_id);
18926                for (buffer_id, hunks) in &chunk_by {
18927                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18928                }
18929            })
18930        })
18931        .detach_and_log_err(cx);
18932    }
18933
18934    fn save_buffers_for_ranges_if_needed(
18935        &mut self,
18936        ranges: &[Range<Anchor>],
18937        cx: &mut Context<Editor>,
18938    ) -> Task<Result<()>> {
18939        let multibuffer = self.buffer.read(cx);
18940        let snapshot = multibuffer.read(cx);
18941        let buffer_ids: HashSet<_> = ranges
18942            .iter()
18943            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18944            .collect();
18945        drop(snapshot);
18946
18947        let mut buffers = HashSet::default();
18948        for buffer_id in buffer_ids {
18949            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18950                let buffer = buffer_entity.read(cx);
18951                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18952                {
18953                    buffers.insert(buffer_entity);
18954                }
18955            }
18956        }
18957
18958        if let Some(project) = &self.project {
18959            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18960        } else {
18961            Task::ready(Ok(()))
18962        }
18963    }
18964
18965    fn do_stage_or_unstage_and_next(
18966        &mut self,
18967        stage: bool,
18968        window: &mut Window,
18969        cx: &mut Context<Self>,
18970    ) {
18971        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18972
18973        if ranges.iter().any(|range| range.start != range.end) {
18974            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18975            return;
18976        }
18977
18978        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18979        let snapshot = self.snapshot(window, cx);
18980        let position = self
18981            .selections
18982            .newest::<Point>(&snapshot.display_snapshot)
18983            .head();
18984        let mut row = snapshot
18985            .buffer_snapshot()
18986            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18987            .find(|hunk| hunk.row_range.start.0 > position.row)
18988            .map(|hunk| hunk.row_range.start);
18989
18990        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18991        // Outside of the project diff editor, wrap around to the beginning.
18992        if !all_diff_hunks_expanded {
18993            row = row.or_else(|| {
18994                snapshot
18995                    .buffer_snapshot()
18996                    .diff_hunks_in_range(Point::zero()..position)
18997                    .find(|hunk| hunk.row_range.end.0 < position.row)
18998                    .map(|hunk| hunk.row_range.start)
18999            });
19000        }
19001
19002        if let Some(row) = row {
19003            let destination = Point::new(row.0, 0);
19004            let autoscroll = Autoscroll::center();
19005
19006            self.unfold_ranges(&[destination..destination], false, false, cx);
19007            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19008                s.select_ranges([destination..destination]);
19009            });
19010        }
19011    }
19012
19013    fn do_stage_or_unstage(
19014        &self,
19015        stage: bool,
19016        buffer_id: BufferId,
19017        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19018        cx: &mut App,
19019    ) -> Option<()> {
19020        let project = self.project()?;
19021        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19022        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19023        let buffer_snapshot = buffer.read(cx).snapshot();
19024        let file_exists = buffer_snapshot
19025            .file()
19026            .is_some_and(|file| file.disk_state().exists());
19027        diff.update(cx, |diff, cx| {
19028            diff.stage_or_unstage_hunks(
19029                stage,
19030                &hunks
19031                    .map(|hunk| buffer_diff::DiffHunk {
19032                        buffer_range: hunk.buffer_range,
19033                        diff_base_byte_range: hunk.diff_base_byte_range,
19034                        secondary_status: hunk.secondary_status,
19035                        range: Point::zero()..Point::zero(), // unused
19036                    })
19037                    .collect::<Vec<_>>(),
19038                &buffer_snapshot,
19039                file_exists,
19040                cx,
19041            )
19042        });
19043        None
19044    }
19045
19046    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19047        let ranges: Vec<_> = self
19048            .selections
19049            .disjoint_anchors()
19050            .iter()
19051            .map(|s| s.range())
19052            .collect();
19053        self.buffer
19054            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19055    }
19056
19057    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19058        self.buffer.update(cx, |buffer, cx| {
19059            let ranges = vec![Anchor::min()..Anchor::max()];
19060            if !buffer.all_diff_hunks_expanded()
19061                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19062            {
19063                buffer.collapse_diff_hunks(ranges, cx);
19064                true
19065            } else {
19066                false
19067            }
19068        })
19069    }
19070
19071    fn toggle_diff_hunks_in_ranges(
19072        &mut self,
19073        ranges: Vec<Range<Anchor>>,
19074        cx: &mut Context<Editor>,
19075    ) {
19076        self.buffer.update(cx, |buffer, cx| {
19077            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19078            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19079        })
19080    }
19081
19082    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19083        self.buffer.update(cx, |buffer, cx| {
19084            let snapshot = buffer.snapshot(cx);
19085            let excerpt_id = range.end.excerpt_id;
19086            let point_range = range.to_point(&snapshot);
19087            let expand = !buffer.single_hunk_is_expanded(range, cx);
19088            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19089        })
19090    }
19091
19092    pub(crate) fn apply_all_diff_hunks(
19093        &mut self,
19094        _: &ApplyAllDiffHunks,
19095        window: &mut Window,
19096        cx: &mut Context<Self>,
19097    ) {
19098        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19099
19100        let buffers = self.buffer.read(cx).all_buffers();
19101        for branch_buffer in buffers {
19102            branch_buffer.update(cx, |branch_buffer, cx| {
19103                branch_buffer.merge_into_base(Vec::new(), cx);
19104            });
19105        }
19106
19107        if let Some(project) = self.project.clone() {
19108            self.save(
19109                SaveOptions {
19110                    format: true,
19111                    autosave: false,
19112                },
19113                project,
19114                window,
19115                cx,
19116            )
19117            .detach_and_log_err(cx);
19118        }
19119    }
19120
19121    pub(crate) fn apply_selected_diff_hunks(
19122        &mut self,
19123        _: &ApplyDiffHunk,
19124        window: &mut Window,
19125        cx: &mut Context<Self>,
19126    ) {
19127        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19128        let snapshot = self.snapshot(window, cx);
19129        let hunks = snapshot.hunks_for_ranges(
19130            self.selections
19131                .all(&snapshot.display_snapshot)
19132                .into_iter()
19133                .map(|selection| selection.range()),
19134        );
19135        let mut ranges_by_buffer = HashMap::default();
19136        self.transact(window, cx, |editor, _window, cx| {
19137            for hunk in hunks {
19138                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19139                    ranges_by_buffer
19140                        .entry(buffer.clone())
19141                        .or_insert_with(Vec::new)
19142                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19143                }
19144            }
19145
19146            for (buffer, ranges) in ranges_by_buffer {
19147                buffer.update(cx, |buffer, cx| {
19148                    buffer.merge_into_base(ranges, cx);
19149                });
19150            }
19151        });
19152
19153        if let Some(project) = self.project.clone() {
19154            self.save(
19155                SaveOptions {
19156                    format: true,
19157                    autosave: false,
19158                },
19159                project,
19160                window,
19161                cx,
19162            )
19163            .detach_and_log_err(cx);
19164        }
19165    }
19166
19167    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19168        if hovered != self.gutter_hovered {
19169            self.gutter_hovered = hovered;
19170            cx.notify();
19171        }
19172    }
19173
19174    pub fn insert_blocks(
19175        &mut self,
19176        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19177        autoscroll: Option<Autoscroll>,
19178        cx: &mut Context<Self>,
19179    ) -> Vec<CustomBlockId> {
19180        let blocks = self
19181            .display_map
19182            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19183        if let Some(autoscroll) = autoscroll {
19184            self.request_autoscroll(autoscroll, cx);
19185        }
19186        cx.notify();
19187        blocks
19188    }
19189
19190    pub fn resize_blocks(
19191        &mut self,
19192        heights: HashMap<CustomBlockId, u32>,
19193        autoscroll: Option<Autoscroll>,
19194        cx: &mut Context<Self>,
19195    ) {
19196        self.display_map
19197            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19198        if let Some(autoscroll) = autoscroll {
19199            self.request_autoscroll(autoscroll, cx);
19200        }
19201        cx.notify();
19202    }
19203
19204    pub fn replace_blocks(
19205        &mut self,
19206        renderers: HashMap<CustomBlockId, RenderBlock>,
19207        autoscroll: Option<Autoscroll>,
19208        cx: &mut Context<Self>,
19209    ) {
19210        self.display_map
19211            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19212        if let Some(autoscroll) = autoscroll {
19213            self.request_autoscroll(autoscroll, cx);
19214        }
19215        cx.notify();
19216    }
19217
19218    pub fn remove_blocks(
19219        &mut self,
19220        block_ids: HashSet<CustomBlockId>,
19221        autoscroll: Option<Autoscroll>,
19222        cx: &mut Context<Self>,
19223    ) {
19224        self.display_map.update(cx, |display_map, cx| {
19225            display_map.remove_blocks(block_ids, cx)
19226        });
19227        if let Some(autoscroll) = autoscroll {
19228            self.request_autoscroll(autoscroll, cx);
19229        }
19230        cx.notify();
19231    }
19232
19233    pub fn row_for_block(
19234        &self,
19235        block_id: CustomBlockId,
19236        cx: &mut Context<Self>,
19237    ) -> Option<DisplayRow> {
19238        self.display_map
19239            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19240    }
19241
19242    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19243        self.focused_block = Some(focused_block);
19244    }
19245
19246    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19247        self.focused_block.take()
19248    }
19249
19250    pub fn insert_creases(
19251        &mut self,
19252        creases: impl IntoIterator<Item = Crease<Anchor>>,
19253        cx: &mut Context<Self>,
19254    ) -> Vec<CreaseId> {
19255        self.display_map
19256            .update(cx, |map, cx| map.insert_creases(creases, cx))
19257    }
19258
19259    pub fn remove_creases(
19260        &mut self,
19261        ids: impl IntoIterator<Item = CreaseId>,
19262        cx: &mut Context<Self>,
19263    ) -> Vec<(CreaseId, Range<Anchor>)> {
19264        self.display_map
19265            .update(cx, |map, cx| map.remove_creases(ids, cx))
19266    }
19267
19268    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19269        self.display_map
19270            .update(cx, |map, cx| map.snapshot(cx))
19271            .longest_row()
19272    }
19273
19274    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19275        self.display_map
19276            .update(cx, |map, cx| map.snapshot(cx))
19277            .max_point()
19278    }
19279
19280    pub fn text(&self, cx: &App) -> String {
19281        self.buffer.read(cx).read(cx).text()
19282    }
19283
19284    pub fn is_empty(&self, cx: &App) -> bool {
19285        self.buffer.read(cx).read(cx).is_empty()
19286    }
19287
19288    pub fn text_option(&self, cx: &App) -> Option<String> {
19289        let text = self.text(cx);
19290        let text = text.trim();
19291
19292        if text.is_empty() {
19293            return None;
19294        }
19295
19296        Some(text.to_string())
19297    }
19298
19299    pub fn set_text(
19300        &mut self,
19301        text: impl Into<Arc<str>>,
19302        window: &mut Window,
19303        cx: &mut Context<Self>,
19304    ) {
19305        self.transact(window, cx, |this, _, cx| {
19306            this.buffer
19307                .read(cx)
19308                .as_singleton()
19309                .expect("you can only call set_text on editors for singleton buffers")
19310                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19311        });
19312    }
19313
19314    pub fn display_text(&self, cx: &mut App) -> String {
19315        self.display_map
19316            .update(cx, |map, cx| map.snapshot(cx))
19317            .text()
19318    }
19319
19320    fn create_minimap(
19321        &self,
19322        minimap_settings: MinimapSettings,
19323        window: &mut Window,
19324        cx: &mut Context<Self>,
19325    ) -> Option<Entity<Self>> {
19326        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19327            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19328    }
19329
19330    fn initialize_new_minimap(
19331        &self,
19332        minimap_settings: MinimapSettings,
19333        window: &mut Window,
19334        cx: &mut Context<Self>,
19335    ) -> Entity<Self> {
19336        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19337
19338        let mut minimap = Editor::new_internal(
19339            EditorMode::Minimap {
19340                parent: cx.weak_entity(),
19341            },
19342            self.buffer.clone(),
19343            None,
19344            Some(self.display_map.clone()),
19345            window,
19346            cx,
19347        );
19348        minimap.scroll_manager.clone_state(&self.scroll_manager);
19349        minimap.set_text_style_refinement(TextStyleRefinement {
19350            font_size: Some(MINIMAP_FONT_SIZE),
19351            font_weight: Some(MINIMAP_FONT_WEIGHT),
19352            ..Default::default()
19353        });
19354        minimap.update_minimap_configuration(minimap_settings, cx);
19355        cx.new(|_| minimap)
19356    }
19357
19358    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19359        let current_line_highlight = minimap_settings
19360            .current_line_highlight
19361            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19362        self.set_current_line_highlight(Some(current_line_highlight));
19363    }
19364
19365    pub fn minimap(&self) -> Option<&Entity<Self>> {
19366        self.minimap
19367            .as_ref()
19368            .filter(|_| self.minimap_visibility.visible())
19369    }
19370
19371    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19372        let mut wrap_guides = smallvec![];
19373
19374        if self.show_wrap_guides == Some(false) {
19375            return wrap_guides;
19376        }
19377
19378        let settings = self.buffer.read(cx).language_settings(cx);
19379        if settings.show_wrap_guides {
19380            match self.soft_wrap_mode(cx) {
19381                SoftWrap::Column(soft_wrap) => {
19382                    wrap_guides.push((soft_wrap as usize, true));
19383                }
19384                SoftWrap::Bounded(soft_wrap) => {
19385                    wrap_guides.push((soft_wrap as usize, true));
19386                }
19387                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19388            }
19389            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19390        }
19391
19392        wrap_guides
19393    }
19394
19395    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19396        let settings = self.buffer.read(cx).language_settings(cx);
19397        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19398        match mode {
19399            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19400                SoftWrap::None
19401            }
19402            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19403            language_settings::SoftWrap::PreferredLineLength => {
19404                SoftWrap::Column(settings.preferred_line_length)
19405            }
19406            language_settings::SoftWrap::Bounded => {
19407                SoftWrap::Bounded(settings.preferred_line_length)
19408            }
19409        }
19410    }
19411
19412    pub fn set_soft_wrap_mode(
19413        &mut self,
19414        mode: language_settings::SoftWrap,
19415
19416        cx: &mut Context<Self>,
19417    ) {
19418        self.soft_wrap_mode_override = Some(mode);
19419        cx.notify();
19420    }
19421
19422    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19423        self.hard_wrap = hard_wrap;
19424        cx.notify();
19425    }
19426
19427    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19428        self.text_style_refinement = Some(style);
19429    }
19430
19431    /// called by the Element so we know what style we were most recently rendered with.
19432    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19433        // We intentionally do not inform the display map about the minimap style
19434        // so that wrapping is not recalculated and stays consistent for the editor
19435        // and its linked minimap.
19436        if !self.mode.is_minimap() {
19437            let font = style.text.font();
19438            let font_size = style.text.font_size.to_pixels(window.rem_size());
19439            let display_map = self
19440                .placeholder_display_map
19441                .as_ref()
19442                .filter(|_| self.is_empty(cx))
19443                .unwrap_or(&self.display_map);
19444
19445            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19446        }
19447        self.style = Some(style);
19448    }
19449
19450    pub fn style(&self) -> Option<&EditorStyle> {
19451        self.style.as_ref()
19452    }
19453
19454    // Called by the element. This method is not designed to be called outside of the editor
19455    // element's layout code because it does not notify when rewrapping is computed synchronously.
19456    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19457        if self.is_empty(cx) {
19458            self.placeholder_display_map
19459                .as_ref()
19460                .map_or(false, |display_map| {
19461                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19462                })
19463        } else {
19464            self.display_map
19465                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19466        }
19467    }
19468
19469    pub fn set_soft_wrap(&mut self) {
19470        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19471    }
19472
19473    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19474        if self.soft_wrap_mode_override.is_some() {
19475            self.soft_wrap_mode_override.take();
19476        } else {
19477            let soft_wrap = match self.soft_wrap_mode(cx) {
19478                SoftWrap::GitDiff => return,
19479                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19480                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19481                    language_settings::SoftWrap::None
19482                }
19483            };
19484            self.soft_wrap_mode_override = Some(soft_wrap);
19485        }
19486        cx.notify();
19487    }
19488
19489    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19490        let Some(workspace) = self.workspace() else {
19491            return;
19492        };
19493        let fs = workspace.read(cx).app_state().fs.clone();
19494        let current_show = TabBarSettings::get_global(cx).show;
19495        update_settings_file(fs, cx, move |setting, _| {
19496            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19497        });
19498    }
19499
19500    pub fn toggle_indent_guides(
19501        &mut self,
19502        _: &ToggleIndentGuides,
19503        _: &mut Window,
19504        cx: &mut Context<Self>,
19505    ) {
19506        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19507            self.buffer
19508                .read(cx)
19509                .language_settings(cx)
19510                .indent_guides
19511                .enabled
19512        });
19513        self.show_indent_guides = Some(!currently_enabled);
19514        cx.notify();
19515    }
19516
19517    fn should_show_indent_guides(&self) -> Option<bool> {
19518        self.show_indent_guides
19519    }
19520
19521    pub fn toggle_line_numbers(
19522        &mut self,
19523        _: &ToggleLineNumbers,
19524        _: &mut Window,
19525        cx: &mut Context<Self>,
19526    ) {
19527        let mut editor_settings = EditorSettings::get_global(cx).clone();
19528        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19529        EditorSettings::override_global(editor_settings, cx);
19530    }
19531
19532    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19533        if let Some(show_line_numbers) = self.show_line_numbers {
19534            return show_line_numbers;
19535        }
19536        EditorSettings::get_global(cx).gutter.line_numbers
19537    }
19538
19539    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19540        self.use_relative_line_numbers
19541            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19542    }
19543
19544    pub fn toggle_relative_line_numbers(
19545        &mut self,
19546        _: &ToggleRelativeLineNumbers,
19547        _: &mut Window,
19548        cx: &mut Context<Self>,
19549    ) {
19550        let is_relative = self.should_use_relative_line_numbers(cx);
19551        self.set_relative_line_number(Some(!is_relative), cx)
19552    }
19553
19554    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19555        self.use_relative_line_numbers = is_relative;
19556        cx.notify();
19557    }
19558
19559    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19560        self.show_gutter = show_gutter;
19561        cx.notify();
19562    }
19563
19564    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19565        self.show_scrollbars = ScrollbarAxes {
19566            horizontal: show,
19567            vertical: show,
19568        };
19569        cx.notify();
19570    }
19571
19572    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19573        self.show_scrollbars.vertical = show;
19574        cx.notify();
19575    }
19576
19577    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19578        self.show_scrollbars.horizontal = show;
19579        cx.notify();
19580    }
19581
19582    pub fn set_minimap_visibility(
19583        &mut self,
19584        minimap_visibility: MinimapVisibility,
19585        window: &mut Window,
19586        cx: &mut Context<Self>,
19587    ) {
19588        if self.minimap_visibility != minimap_visibility {
19589            if minimap_visibility.visible() && self.minimap.is_none() {
19590                let minimap_settings = EditorSettings::get_global(cx).minimap;
19591                self.minimap =
19592                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19593            }
19594            self.minimap_visibility = minimap_visibility;
19595            cx.notify();
19596        }
19597    }
19598
19599    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19600        self.set_show_scrollbars(false, cx);
19601        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19602    }
19603
19604    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19605        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19606    }
19607
19608    /// Normally the text in full mode and auto height editors is padded on the
19609    /// left side by roughly half a character width for improved hit testing.
19610    ///
19611    /// Use this method to disable this for cases where this is not wanted (e.g.
19612    /// if you want to align the editor text with some other text above or below)
19613    /// or if you want to add this padding to single-line editors.
19614    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19615        self.offset_content = offset_content;
19616        cx.notify();
19617    }
19618
19619    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19620        self.show_line_numbers = Some(show_line_numbers);
19621        cx.notify();
19622    }
19623
19624    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19625        self.disable_expand_excerpt_buttons = true;
19626        cx.notify();
19627    }
19628
19629    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19630        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19631        cx.notify();
19632    }
19633
19634    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19635        self.show_code_actions = Some(show_code_actions);
19636        cx.notify();
19637    }
19638
19639    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19640        self.show_runnables = Some(show_runnables);
19641        cx.notify();
19642    }
19643
19644    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19645        self.show_breakpoints = Some(show_breakpoints);
19646        cx.notify();
19647    }
19648
19649    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19650        if self.display_map.read(cx).masked != masked {
19651            self.display_map.update(cx, |map, _| map.masked = masked);
19652        }
19653        cx.notify()
19654    }
19655
19656    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19657        self.show_wrap_guides = Some(show_wrap_guides);
19658        cx.notify();
19659    }
19660
19661    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19662        self.show_indent_guides = Some(show_indent_guides);
19663        cx.notify();
19664    }
19665
19666    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19667        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19668            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19669                && let Some(dir) = file.abs_path(cx).parent()
19670            {
19671                return Some(dir.to_owned());
19672            }
19673        }
19674
19675        None
19676    }
19677
19678    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19679        self.active_excerpt(cx)?
19680            .1
19681            .read(cx)
19682            .file()
19683            .and_then(|f| f.as_local())
19684    }
19685
19686    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19687        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19688            let buffer = buffer.read(cx);
19689            if let Some(project_path) = buffer.project_path(cx) {
19690                let project = self.project()?.read(cx);
19691                project.absolute_path(&project_path, cx)
19692            } else {
19693                buffer
19694                    .file()
19695                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19696            }
19697        })
19698    }
19699
19700    pub fn reveal_in_finder(
19701        &mut self,
19702        _: &RevealInFileManager,
19703        _window: &mut Window,
19704        cx: &mut Context<Self>,
19705    ) {
19706        if let Some(target) = self.target_file(cx) {
19707            cx.reveal_path(&target.abs_path(cx));
19708        }
19709    }
19710
19711    pub fn copy_path(
19712        &mut self,
19713        _: &zed_actions::workspace::CopyPath,
19714        _window: &mut Window,
19715        cx: &mut Context<Self>,
19716    ) {
19717        if let Some(path) = self.target_file_abs_path(cx)
19718            && let Some(path) = path.to_str()
19719        {
19720            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19721        } else {
19722            cx.propagate();
19723        }
19724    }
19725
19726    pub fn copy_relative_path(
19727        &mut self,
19728        _: &zed_actions::workspace::CopyRelativePath,
19729        _window: &mut Window,
19730        cx: &mut Context<Self>,
19731    ) {
19732        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19733            let project = self.project()?.read(cx);
19734            let path = buffer.read(cx).file()?.path();
19735            let path = path.display(project.path_style(cx));
19736            Some(path)
19737        }) {
19738            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19739        } else {
19740            cx.propagate();
19741        }
19742    }
19743
19744    /// Returns the project path for the editor's buffer, if any buffer is
19745    /// opened in the editor.
19746    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19747        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19748            buffer.read(cx).project_path(cx)
19749        } else {
19750            None
19751        }
19752    }
19753
19754    // Returns true if the editor handled a go-to-line request
19755    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19756        maybe!({
19757            let breakpoint_store = self.breakpoint_store.as_ref()?;
19758
19759            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19760            else {
19761                self.clear_row_highlights::<ActiveDebugLine>();
19762                return None;
19763            };
19764
19765            let position = active_stack_frame.position;
19766            let buffer_id = position.buffer_id?;
19767            let snapshot = self
19768                .project
19769                .as_ref()?
19770                .read(cx)
19771                .buffer_for_id(buffer_id, cx)?
19772                .read(cx)
19773                .snapshot();
19774
19775            let mut handled = false;
19776            for (id, ExcerptRange { context, .. }) in
19777                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19778            {
19779                if context.start.cmp(&position, &snapshot).is_ge()
19780                    || context.end.cmp(&position, &snapshot).is_lt()
19781                {
19782                    continue;
19783                }
19784                let snapshot = self.buffer.read(cx).snapshot(cx);
19785                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19786
19787                handled = true;
19788                self.clear_row_highlights::<ActiveDebugLine>();
19789
19790                self.go_to_line::<ActiveDebugLine>(
19791                    multibuffer_anchor,
19792                    Some(cx.theme().colors().editor_debugger_active_line_background),
19793                    window,
19794                    cx,
19795                );
19796
19797                cx.notify();
19798            }
19799
19800            handled.then_some(())
19801        })
19802        .is_some()
19803    }
19804
19805    pub fn copy_file_name_without_extension(
19806        &mut self,
19807        _: &CopyFileNameWithoutExtension,
19808        _: &mut Window,
19809        cx: &mut Context<Self>,
19810    ) {
19811        if let Some(file) = self.target_file(cx)
19812            && let Some(file_stem) = file.path().file_stem()
19813        {
19814            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19815        }
19816    }
19817
19818    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19819        if let Some(file) = self.target_file(cx)
19820            && let Some(name) = file.path().file_name()
19821        {
19822            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19823        }
19824    }
19825
19826    pub fn toggle_git_blame(
19827        &mut self,
19828        _: &::git::Blame,
19829        window: &mut Window,
19830        cx: &mut Context<Self>,
19831    ) {
19832        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19833
19834        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19835            self.start_git_blame(true, window, cx);
19836        }
19837
19838        cx.notify();
19839    }
19840
19841    pub fn toggle_git_blame_inline(
19842        &mut self,
19843        _: &ToggleGitBlameInline,
19844        window: &mut Window,
19845        cx: &mut Context<Self>,
19846    ) {
19847        self.toggle_git_blame_inline_internal(true, window, cx);
19848        cx.notify();
19849    }
19850
19851    pub fn open_git_blame_commit(
19852        &mut self,
19853        _: &OpenGitBlameCommit,
19854        window: &mut Window,
19855        cx: &mut Context<Self>,
19856    ) {
19857        self.open_git_blame_commit_internal(window, cx);
19858    }
19859
19860    fn open_git_blame_commit_internal(
19861        &mut self,
19862        window: &mut Window,
19863        cx: &mut Context<Self>,
19864    ) -> Option<()> {
19865        let blame = self.blame.as_ref()?;
19866        let snapshot = self.snapshot(window, cx);
19867        let cursor = self
19868            .selections
19869            .newest::<Point>(&snapshot.display_snapshot)
19870            .head();
19871        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19872        let (_, blame_entry) = blame
19873            .update(cx, |blame, cx| {
19874                blame
19875                    .blame_for_rows(
19876                        &[RowInfo {
19877                            buffer_id: Some(buffer.remote_id()),
19878                            buffer_row: Some(point.row),
19879                            ..Default::default()
19880                        }],
19881                        cx,
19882                    )
19883                    .next()
19884            })
19885            .flatten()?;
19886        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19887        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19888        let workspace = self.workspace()?.downgrade();
19889        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19890        None
19891    }
19892
19893    pub fn git_blame_inline_enabled(&self) -> bool {
19894        self.git_blame_inline_enabled
19895    }
19896
19897    pub fn toggle_selection_menu(
19898        &mut self,
19899        _: &ToggleSelectionMenu,
19900        _: &mut Window,
19901        cx: &mut Context<Self>,
19902    ) {
19903        self.show_selection_menu = self
19904            .show_selection_menu
19905            .map(|show_selections_menu| !show_selections_menu)
19906            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19907
19908        cx.notify();
19909    }
19910
19911    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19912        self.show_selection_menu
19913            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19914    }
19915
19916    fn start_git_blame(
19917        &mut self,
19918        user_triggered: bool,
19919        window: &mut Window,
19920        cx: &mut Context<Self>,
19921    ) {
19922        if let Some(project) = self.project() {
19923            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19924                && buffer.read(cx).file().is_none()
19925            {
19926                return;
19927            }
19928
19929            let focused = self.focus_handle(cx).contains_focused(window, cx);
19930
19931            let project = project.clone();
19932            let blame = cx
19933                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19934            self.blame_subscription =
19935                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19936            self.blame = Some(blame);
19937        }
19938    }
19939
19940    fn toggle_git_blame_inline_internal(
19941        &mut self,
19942        user_triggered: bool,
19943        window: &mut Window,
19944        cx: &mut Context<Self>,
19945    ) {
19946        if self.git_blame_inline_enabled {
19947            self.git_blame_inline_enabled = false;
19948            self.show_git_blame_inline = false;
19949            self.show_git_blame_inline_delay_task.take();
19950        } else {
19951            self.git_blame_inline_enabled = true;
19952            self.start_git_blame_inline(user_triggered, window, cx);
19953        }
19954
19955        cx.notify();
19956    }
19957
19958    fn start_git_blame_inline(
19959        &mut self,
19960        user_triggered: bool,
19961        window: &mut Window,
19962        cx: &mut Context<Self>,
19963    ) {
19964        self.start_git_blame(user_triggered, window, cx);
19965
19966        if ProjectSettings::get_global(cx)
19967            .git
19968            .inline_blame_delay()
19969            .is_some()
19970        {
19971            self.start_inline_blame_timer(window, cx);
19972        } else {
19973            self.show_git_blame_inline = true
19974        }
19975    }
19976
19977    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19978        self.blame.as_ref()
19979    }
19980
19981    pub fn show_git_blame_gutter(&self) -> bool {
19982        self.show_git_blame_gutter
19983    }
19984
19985    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19986        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19987    }
19988
19989    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19990        self.show_git_blame_inline
19991            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19992            && !self.newest_selection_head_on_empty_line(cx)
19993            && self.has_blame_entries(cx)
19994    }
19995
19996    fn has_blame_entries(&self, cx: &App) -> bool {
19997        self.blame()
19998            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19999    }
20000
20001    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20002        let cursor_anchor = self.selections.newest_anchor().head();
20003
20004        let snapshot = self.buffer.read(cx).snapshot(cx);
20005        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20006
20007        snapshot.line_len(buffer_row) == 0
20008    }
20009
20010    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20011        let buffer_and_selection = maybe!({
20012            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20013            let selection_range = selection.range();
20014
20015            let multi_buffer = self.buffer().read(cx);
20016            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20017            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20018
20019            let (buffer, range, _) = if selection.reversed {
20020                buffer_ranges.first()
20021            } else {
20022                buffer_ranges.last()
20023            }?;
20024
20025            let selection = text::ToPoint::to_point(&range.start, buffer).row
20026                ..text::ToPoint::to_point(&range.end, buffer).row;
20027            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20028        });
20029
20030        let Some((buffer, selection)) = buffer_and_selection else {
20031            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20032        };
20033
20034        let Some(project) = self.project() else {
20035            return Task::ready(Err(anyhow!("editor does not have project")));
20036        };
20037
20038        project.update(cx, |project, cx| {
20039            project.get_permalink_to_line(&buffer, selection, cx)
20040        })
20041    }
20042
20043    pub fn copy_permalink_to_line(
20044        &mut self,
20045        _: &CopyPermalinkToLine,
20046        window: &mut Window,
20047        cx: &mut Context<Self>,
20048    ) {
20049        let permalink_task = self.get_permalink_to_line(cx);
20050        let workspace = self.workspace();
20051
20052        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20053            Ok(permalink) => {
20054                cx.update(|_, cx| {
20055                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20056                })
20057                .ok();
20058            }
20059            Err(err) => {
20060                let message = format!("Failed to copy permalink: {err}");
20061
20062                anyhow::Result::<()>::Err(err).log_err();
20063
20064                if let Some(workspace) = workspace {
20065                    workspace
20066                        .update_in(cx, |workspace, _, cx| {
20067                            struct CopyPermalinkToLine;
20068
20069                            workspace.show_toast(
20070                                Toast::new(
20071                                    NotificationId::unique::<CopyPermalinkToLine>(),
20072                                    message,
20073                                ),
20074                                cx,
20075                            )
20076                        })
20077                        .ok();
20078                }
20079            }
20080        })
20081        .detach();
20082    }
20083
20084    pub fn copy_file_location(
20085        &mut self,
20086        _: &CopyFileLocation,
20087        _: &mut Window,
20088        cx: &mut Context<Self>,
20089    ) {
20090        let selection = self
20091            .selections
20092            .newest::<Point>(&self.display_snapshot(cx))
20093            .start
20094            .row
20095            + 1;
20096        if let Some(file) = self.target_file(cx) {
20097            let path = file.path().display(file.path_style(cx));
20098            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20099        }
20100    }
20101
20102    pub fn open_permalink_to_line(
20103        &mut self,
20104        _: &OpenPermalinkToLine,
20105        window: &mut Window,
20106        cx: &mut Context<Self>,
20107    ) {
20108        let permalink_task = self.get_permalink_to_line(cx);
20109        let workspace = self.workspace();
20110
20111        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20112            Ok(permalink) => {
20113                cx.update(|_, cx| {
20114                    cx.open_url(permalink.as_ref());
20115                })
20116                .ok();
20117            }
20118            Err(err) => {
20119                let message = format!("Failed to open permalink: {err}");
20120
20121                anyhow::Result::<()>::Err(err).log_err();
20122
20123                if let Some(workspace) = workspace {
20124                    workspace
20125                        .update(cx, |workspace, cx| {
20126                            struct OpenPermalinkToLine;
20127
20128                            workspace.show_toast(
20129                                Toast::new(
20130                                    NotificationId::unique::<OpenPermalinkToLine>(),
20131                                    message,
20132                                ),
20133                                cx,
20134                            )
20135                        })
20136                        .ok();
20137                }
20138            }
20139        })
20140        .detach();
20141    }
20142
20143    pub fn insert_uuid_v4(
20144        &mut self,
20145        _: &InsertUuidV4,
20146        window: &mut Window,
20147        cx: &mut Context<Self>,
20148    ) {
20149        self.insert_uuid(UuidVersion::V4, window, cx);
20150    }
20151
20152    pub fn insert_uuid_v7(
20153        &mut self,
20154        _: &InsertUuidV7,
20155        window: &mut Window,
20156        cx: &mut Context<Self>,
20157    ) {
20158        self.insert_uuid(UuidVersion::V7, window, cx);
20159    }
20160
20161    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20162        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20163        self.transact(window, cx, |this, window, cx| {
20164            let edits = this
20165                .selections
20166                .all::<Point>(&this.display_snapshot(cx))
20167                .into_iter()
20168                .map(|selection| {
20169                    let uuid = match version {
20170                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20171                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20172                    };
20173
20174                    (selection.range(), uuid.to_string())
20175                });
20176            this.edit(edits, cx);
20177            this.refresh_edit_prediction(true, false, window, cx);
20178        });
20179    }
20180
20181    pub fn open_selections_in_multibuffer(
20182        &mut self,
20183        _: &OpenSelectionsInMultibuffer,
20184        window: &mut Window,
20185        cx: &mut Context<Self>,
20186    ) {
20187        let multibuffer = self.buffer.read(cx);
20188
20189        let Some(buffer) = multibuffer.as_singleton() else {
20190            return;
20191        };
20192
20193        let Some(workspace) = self.workspace() else {
20194            return;
20195        };
20196
20197        let title = multibuffer.title(cx).to_string();
20198
20199        let locations = self
20200            .selections
20201            .all_anchors(cx)
20202            .iter()
20203            .map(|selection| {
20204                (
20205                    buffer.clone(),
20206                    (selection.start.text_anchor..selection.end.text_anchor)
20207                        .to_point(buffer.read(cx)),
20208                )
20209            })
20210            .into_group_map();
20211
20212        cx.spawn_in(window, async move |_, cx| {
20213            workspace.update_in(cx, |workspace, window, cx| {
20214                Self::open_locations_in_multibuffer(
20215                    workspace,
20216                    locations,
20217                    format!("Selections for '{title}'"),
20218                    false,
20219                    MultibufferSelectionMode::All,
20220                    window,
20221                    cx,
20222                );
20223            })
20224        })
20225        .detach();
20226    }
20227
20228    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20229    /// last highlight added will be used.
20230    ///
20231    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20232    pub fn highlight_rows<T: 'static>(
20233        &mut self,
20234        range: Range<Anchor>,
20235        color: Hsla,
20236        options: RowHighlightOptions,
20237        cx: &mut Context<Self>,
20238    ) {
20239        let snapshot = self.buffer().read(cx).snapshot(cx);
20240        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20241        let ix = row_highlights.binary_search_by(|highlight| {
20242            Ordering::Equal
20243                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20244                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20245        });
20246
20247        if let Err(mut ix) = ix {
20248            let index = post_inc(&mut self.highlight_order);
20249
20250            // If this range intersects with the preceding highlight, then merge it with
20251            // the preceding highlight. Otherwise insert a new highlight.
20252            let mut merged = false;
20253            if ix > 0 {
20254                let prev_highlight = &mut row_highlights[ix - 1];
20255                if prev_highlight
20256                    .range
20257                    .end
20258                    .cmp(&range.start, &snapshot)
20259                    .is_ge()
20260                {
20261                    ix -= 1;
20262                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20263                        prev_highlight.range.end = range.end;
20264                    }
20265                    merged = true;
20266                    prev_highlight.index = index;
20267                    prev_highlight.color = color;
20268                    prev_highlight.options = options;
20269                }
20270            }
20271
20272            if !merged {
20273                row_highlights.insert(
20274                    ix,
20275                    RowHighlight {
20276                        range,
20277                        index,
20278                        color,
20279                        options,
20280                        type_id: TypeId::of::<T>(),
20281                    },
20282                );
20283            }
20284
20285            // If any of the following highlights intersect with this one, merge them.
20286            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20287                let highlight = &row_highlights[ix];
20288                if next_highlight
20289                    .range
20290                    .start
20291                    .cmp(&highlight.range.end, &snapshot)
20292                    .is_le()
20293                {
20294                    if next_highlight
20295                        .range
20296                        .end
20297                        .cmp(&highlight.range.end, &snapshot)
20298                        .is_gt()
20299                    {
20300                        row_highlights[ix].range.end = next_highlight.range.end;
20301                    }
20302                    row_highlights.remove(ix + 1);
20303                } else {
20304                    break;
20305                }
20306            }
20307        }
20308    }
20309
20310    /// Remove any highlighted row ranges of the given type that intersect the
20311    /// given ranges.
20312    pub fn remove_highlighted_rows<T: 'static>(
20313        &mut self,
20314        ranges_to_remove: Vec<Range<Anchor>>,
20315        cx: &mut Context<Self>,
20316    ) {
20317        let snapshot = self.buffer().read(cx).snapshot(cx);
20318        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20319        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20320        row_highlights.retain(|highlight| {
20321            while let Some(range_to_remove) = ranges_to_remove.peek() {
20322                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20323                    Ordering::Less | Ordering::Equal => {
20324                        ranges_to_remove.next();
20325                    }
20326                    Ordering::Greater => {
20327                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20328                            Ordering::Less | Ordering::Equal => {
20329                                return false;
20330                            }
20331                            Ordering::Greater => break,
20332                        }
20333                    }
20334                }
20335            }
20336
20337            true
20338        })
20339    }
20340
20341    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20342    pub fn clear_row_highlights<T: 'static>(&mut self) {
20343        self.highlighted_rows.remove(&TypeId::of::<T>());
20344    }
20345
20346    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20347    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20348        self.highlighted_rows
20349            .get(&TypeId::of::<T>())
20350            .map_or(&[] as &[_], |vec| vec.as_slice())
20351            .iter()
20352            .map(|highlight| (highlight.range.clone(), highlight.color))
20353    }
20354
20355    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20356    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20357    /// Allows to ignore certain kinds of highlights.
20358    pub fn highlighted_display_rows(
20359        &self,
20360        window: &mut Window,
20361        cx: &mut App,
20362    ) -> BTreeMap<DisplayRow, LineHighlight> {
20363        let snapshot = self.snapshot(window, cx);
20364        let mut used_highlight_orders = HashMap::default();
20365        self.highlighted_rows
20366            .iter()
20367            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20368            .fold(
20369                BTreeMap::<DisplayRow, LineHighlight>::new(),
20370                |mut unique_rows, highlight| {
20371                    let start = highlight.range.start.to_display_point(&snapshot);
20372                    let end = highlight.range.end.to_display_point(&snapshot);
20373                    let start_row = start.row().0;
20374                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20375                        && end.column() == 0
20376                    {
20377                        end.row().0.saturating_sub(1)
20378                    } else {
20379                        end.row().0
20380                    };
20381                    for row in start_row..=end_row {
20382                        let used_index =
20383                            used_highlight_orders.entry(row).or_insert(highlight.index);
20384                        if highlight.index >= *used_index {
20385                            *used_index = highlight.index;
20386                            unique_rows.insert(
20387                                DisplayRow(row),
20388                                LineHighlight {
20389                                    include_gutter: highlight.options.include_gutter,
20390                                    border: None,
20391                                    background: highlight.color.into(),
20392                                    type_id: Some(highlight.type_id),
20393                                },
20394                            );
20395                        }
20396                    }
20397                    unique_rows
20398                },
20399            )
20400    }
20401
20402    pub fn highlighted_display_row_for_autoscroll(
20403        &self,
20404        snapshot: &DisplaySnapshot,
20405    ) -> Option<DisplayRow> {
20406        self.highlighted_rows
20407            .values()
20408            .flat_map(|highlighted_rows| highlighted_rows.iter())
20409            .filter_map(|highlight| {
20410                if highlight.options.autoscroll {
20411                    Some(highlight.range.start.to_display_point(snapshot).row())
20412                } else {
20413                    None
20414                }
20415            })
20416            .min()
20417    }
20418
20419    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20420        self.highlight_background::<SearchWithinRange>(
20421            ranges,
20422            |colors| colors.colors().editor_document_highlight_read_background,
20423            cx,
20424        )
20425    }
20426
20427    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20428        self.breadcrumb_header = Some(new_header);
20429    }
20430
20431    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20432        self.clear_background_highlights::<SearchWithinRange>(cx);
20433    }
20434
20435    pub fn highlight_background<T: 'static>(
20436        &mut self,
20437        ranges: &[Range<Anchor>],
20438        color_fetcher: fn(&Theme) -> Hsla,
20439        cx: &mut Context<Self>,
20440    ) {
20441        self.background_highlights.insert(
20442            HighlightKey::Type(TypeId::of::<T>()),
20443            (color_fetcher, Arc::from(ranges)),
20444        );
20445        self.scrollbar_marker_state.dirty = true;
20446        cx.notify();
20447    }
20448
20449    pub fn highlight_background_key<T: 'static>(
20450        &mut self,
20451        key: usize,
20452        ranges: &[Range<Anchor>],
20453        color_fetcher: fn(&Theme) -> Hsla,
20454        cx: &mut Context<Self>,
20455    ) {
20456        self.background_highlights.insert(
20457            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20458            (color_fetcher, Arc::from(ranges)),
20459        );
20460        self.scrollbar_marker_state.dirty = true;
20461        cx.notify();
20462    }
20463
20464    pub fn clear_background_highlights<T: 'static>(
20465        &mut self,
20466        cx: &mut Context<Self>,
20467    ) -> Option<BackgroundHighlight> {
20468        let text_highlights = self
20469            .background_highlights
20470            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20471        if !text_highlights.1.is_empty() {
20472            self.scrollbar_marker_state.dirty = true;
20473            cx.notify();
20474        }
20475        Some(text_highlights)
20476    }
20477
20478    pub fn highlight_gutter<T: 'static>(
20479        &mut self,
20480        ranges: impl Into<Vec<Range<Anchor>>>,
20481        color_fetcher: fn(&App) -> Hsla,
20482        cx: &mut Context<Self>,
20483    ) {
20484        self.gutter_highlights
20485            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20486        cx.notify();
20487    }
20488
20489    pub fn clear_gutter_highlights<T: 'static>(
20490        &mut self,
20491        cx: &mut Context<Self>,
20492    ) -> Option<GutterHighlight> {
20493        cx.notify();
20494        self.gutter_highlights.remove(&TypeId::of::<T>())
20495    }
20496
20497    pub fn insert_gutter_highlight<T: 'static>(
20498        &mut self,
20499        range: Range<Anchor>,
20500        color_fetcher: fn(&App) -> Hsla,
20501        cx: &mut Context<Self>,
20502    ) {
20503        let snapshot = self.buffer().read(cx).snapshot(cx);
20504        let mut highlights = self
20505            .gutter_highlights
20506            .remove(&TypeId::of::<T>())
20507            .map(|(_, highlights)| highlights)
20508            .unwrap_or_default();
20509        let ix = highlights.binary_search_by(|highlight| {
20510            Ordering::Equal
20511                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20512                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20513        });
20514        if let Err(ix) = ix {
20515            highlights.insert(ix, range);
20516        }
20517        self.gutter_highlights
20518            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20519    }
20520
20521    pub fn remove_gutter_highlights<T: 'static>(
20522        &mut self,
20523        ranges_to_remove: Vec<Range<Anchor>>,
20524        cx: &mut Context<Self>,
20525    ) {
20526        let snapshot = self.buffer().read(cx).snapshot(cx);
20527        let Some((color_fetcher, mut gutter_highlights)) =
20528            self.gutter_highlights.remove(&TypeId::of::<T>())
20529        else {
20530            return;
20531        };
20532        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20533        gutter_highlights.retain(|highlight| {
20534            while let Some(range_to_remove) = ranges_to_remove.peek() {
20535                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20536                    Ordering::Less | Ordering::Equal => {
20537                        ranges_to_remove.next();
20538                    }
20539                    Ordering::Greater => {
20540                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20541                            Ordering::Less | Ordering::Equal => {
20542                                return false;
20543                            }
20544                            Ordering::Greater => break,
20545                        }
20546                    }
20547                }
20548            }
20549
20550            true
20551        });
20552        self.gutter_highlights
20553            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20554    }
20555
20556    #[cfg(feature = "test-support")]
20557    pub fn all_text_highlights(
20558        &self,
20559        window: &mut Window,
20560        cx: &mut Context<Self>,
20561    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20562        let snapshot = self.snapshot(window, cx);
20563        self.display_map.update(cx, |display_map, _| {
20564            display_map
20565                .all_text_highlights()
20566                .map(|highlight| {
20567                    let (style, ranges) = highlight.as_ref();
20568                    (
20569                        *style,
20570                        ranges
20571                            .iter()
20572                            .map(|range| range.clone().to_display_points(&snapshot))
20573                            .collect(),
20574                    )
20575                })
20576                .collect()
20577        })
20578    }
20579
20580    #[cfg(feature = "test-support")]
20581    pub fn all_text_background_highlights(
20582        &self,
20583        window: &mut Window,
20584        cx: &mut Context<Self>,
20585    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20586        let snapshot = self.snapshot(window, cx);
20587        let buffer = &snapshot.buffer_snapshot();
20588        let start = buffer.anchor_before(0);
20589        let end = buffer.anchor_after(buffer.len());
20590        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20591    }
20592
20593    #[cfg(any(test, feature = "test-support"))]
20594    pub fn sorted_background_highlights_in_range(
20595        &self,
20596        search_range: Range<Anchor>,
20597        display_snapshot: &DisplaySnapshot,
20598        theme: &Theme,
20599    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20600        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20601        res.sort_by(|a, b| {
20602            a.0.start
20603                .cmp(&b.0.start)
20604                .then_with(|| a.0.end.cmp(&b.0.end))
20605                .then_with(|| a.1.cmp(&b.1))
20606        });
20607        res
20608    }
20609
20610    #[cfg(feature = "test-support")]
20611    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20612        let snapshot = self.buffer().read(cx).snapshot(cx);
20613
20614        let highlights = self
20615            .background_highlights
20616            .get(&HighlightKey::Type(TypeId::of::<
20617                items::BufferSearchHighlights,
20618            >()));
20619
20620        if let Some((_color, ranges)) = highlights {
20621            ranges
20622                .iter()
20623                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20624                .collect_vec()
20625        } else {
20626            vec![]
20627        }
20628    }
20629
20630    fn document_highlights_for_position<'a>(
20631        &'a self,
20632        position: Anchor,
20633        buffer: &'a MultiBufferSnapshot,
20634    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20635        let read_highlights = self
20636            .background_highlights
20637            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20638            .map(|h| &h.1);
20639        let write_highlights = self
20640            .background_highlights
20641            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20642            .map(|h| &h.1);
20643        let left_position = position.bias_left(buffer);
20644        let right_position = position.bias_right(buffer);
20645        read_highlights
20646            .into_iter()
20647            .chain(write_highlights)
20648            .flat_map(move |ranges| {
20649                let start_ix = match ranges.binary_search_by(|probe| {
20650                    let cmp = probe.end.cmp(&left_position, buffer);
20651                    if cmp.is_ge() {
20652                        Ordering::Greater
20653                    } else {
20654                        Ordering::Less
20655                    }
20656                }) {
20657                    Ok(i) | Err(i) => i,
20658                };
20659
20660                ranges[start_ix..]
20661                    .iter()
20662                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20663            })
20664    }
20665
20666    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20667        self.background_highlights
20668            .get(&HighlightKey::Type(TypeId::of::<T>()))
20669            .is_some_and(|(_, highlights)| !highlights.is_empty())
20670    }
20671
20672    /// Returns all background highlights for a given range.
20673    ///
20674    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20675    pub fn background_highlights_in_range(
20676        &self,
20677        search_range: Range<Anchor>,
20678        display_snapshot: &DisplaySnapshot,
20679        theme: &Theme,
20680    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20681        let mut results = Vec::new();
20682        for (color_fetcher, ranges) in self.background_highlights.values() {
20683            let color = color_fetcher(theme);
20684            let start_ix = match ranges.binary_search_by(|probe| {
20685                let cmp = probe
20686                    .end
20687                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20688                if cmp.is_gt() {
20689                    Ordering::Greater
20690                } else {
20691                    Ordering::Less
20692                }
20693            }) {
20694                Ok(i) | Err(i) => i,
20695            };
20696            for range in &ranges[start_ix..] {
20697                if range
20698                    .start
20699                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20700                    .is_ge()
20701                {
20702                    break;
20703                }
20704
20705                let start = range.start.to_display_point(display_snapshot);
20706                let end = range.end.to_display_point(display_snapshot);
20707                results.push((start..end, color))
20708            }
20709        }
20710        results
20711    }
20712
20713    pub fn gutter_highlights_in_range(
20714        &self,
20715        search_range: Range<Anchor>,
20716        display_snapshot: &DisplaySnapshot,
20717        cx: &App,
20718    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20719        let mut results = Vec::new();
20720        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20721            let color = color_fetcher(cx);
20722            let start_ix = match ranges.binary_search_by(|probe| {
20723                let cmp = probe
20724                    .end
20725                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20726                if cmp.is_gt() {
20727                    Ordering::Greater
20728                } else {
20729                    Ordering::Less
20730                }
20731            }) {
20732                Ok(i) | Err(i) => i,
20733            };
20734            for range in &ranges[start_ix..] {
20735                if range
20736                    .start
20737                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20738                    .is_ge()
20739                {
20740                    break;
20741                }
20742
20743                let start = range.start.to_display_point(display_snapshot);
20744                let end = range.end.to_display_point(display_snapshot);
20745                results.push((start..end, color))
20746            }
20747        }
20748        results
20749    }
20750
20751    /// Get the text ranges corresponding to the redaction query
20752    pub fn redacted_ranges(
20753        &self,
20754        search_range: Range<Anchor>,
20755        display_snapshot: &DisplaySnapshot,
20756        cx: &App,
20757    ) -> Vec<Range<DisplayPoint>> {
20758        display_snapshot
20759            .buffer_snapshot()
20760            .redacted_ranges(search_range, |file| {
20761                if let Some(file) = file {
20762                    file.is_private()
20763                        && EditorSettings::get(
20764                            Some(SettingsLocation {
20765                                worktree_id: file.worktree_id(cx),
20766                                path: file.path().as_ref(),
20767                            }),
20768                            cx,
20769                        )
20770                        .redact_private_values
20771                } else {
20772                    false
20773                }
20774            })
20775            .map(|range| {
20776                range.start.to_display_point(display_snapshot)
20777                    ..range.end.to_display_point(display_snapshot)
20778            })
20779            .collect()
20780    }
20781
20782    pub fn highlight_text_key<T: 'static>(
20783        &mut self,
20784        key: usize,
20785        ranges: Vec<Range<Anchor>>,
20786        style: HighlightStyle,
20787        cx: &mut Context<Self>,
20788    ) {
20789        self.display_map.update(cx, |map, _| {
20790            map.highlight_text(
20791                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20792                ranges,
20793                style,
20794            );
20795        });
20796        cx.notify();
20797    }
20798
20799    pub fn highlight_text<T: 'static>(
20800        &mut self,
20801        ranges: Vec<Range<Anchor>>,
20802        style: HighlightStyle,
20803        cx: &mut Context<Self>,
20804    ) {
20805        self.display_map.update(cx, |map, _| {
20806            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20807        });
20808        cx.notify();
20809    }
20810
20811    pub(crate) fn highlight_inlays<T: 'static>(
20812        &mut self,
20813        highlights: Vec<InlayHighlight>,
20814        style: HighlightStyle,
20815        cx: &mut Context<Self>,
20816    ) {
20817        self.display_map.update(cx, |map, _| {
20818            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20819        });
20820        cx.notify();
20821    }
20822
20823    pub fn text_highlights<'a, T: 'static>(
20824        &'a self,
20825        cx: &'a App,
20826    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20827        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20828    }
20829
20830    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20831        let cleared = self
20832            .display_map
20833            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20834        if cleared {
20835            cx.notify();
20836        }
20837    }
20838
20839    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20840        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20841            && self.focus_handle.is_focused(window)
20842    }
20843
20844    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20845        self.show_cursor_when_unfocused = is_enabled;
20846        cx.notify();
20847    }
20848
20849    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20850        cx.notify();
20851    }
20852
20853    fn on_debug_session_event(
20854        &mut self,
20855        _session: Entity<Session>,
20856        event: &SessionEvent,
20857        cx: &mut Context<Self>,
20858    ) {
20859        if let SessionEvent::InvalidateInlineValue = event {
20860            self.refresh_inline_values(cx);
20861        }
20862    }
20863
20864    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20865        let Some(project) = self.project.clone() else {
20866            return;
20867        };
20868
20869        if !self.inline_value_cache.enabled {
20870            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20871            self.splice_inlays(&inlays, Vec::new(), cx);
20872            return;
20873        }
20874
20875        let current_execution_position = self
20876            .highlighted_rows
20877            .get(&TypeId::of::<ActiveDebugLine>())
20878            .and_then(|lines| lines.last().map(|line| line.range.end));
20879
20880        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20881            let inline_values = editor
20882                .update(cx, |editor, cx| {
20883                    let Some(current_execution_position) = current_execution_position else {
20884                        return Some(Task::ready(Ok(Vec::new())));
20885                    };
20886
20887                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20888                        let snapshot = buffer.snapshot(cx);
20889
20890                        let excerpt = snapshot.excerpt_containing(
20891                            current_execution_position..current_execution_position,
20892                        )?;
20893
20894                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20895                    })?;
20896
20897                    let range =
20898                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20899
20900                    project.inline_values(buffer, range, cx)
20901                })
20902                .ok()
20903                .flatten()?
20904                .await
20905                .context("refreshing debugger inlays")
20906                .log_err()?;
20907
20908            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20909
20910            for (buffer_id, inline_value) in inline_values
20911                .into_iter()
20912                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20913            {
20914                buffer_inline_values
20915                    .entry(buffer_id)
20916                    .or_default()
20917                    .push(inline_value);
20918            }
20919
20920            editor
20921                .update(cx, |editor, cx| {
20922                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20923                    let mut new_inlays = Vec::default();
20924
20925                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20926                        let buffer_id = buffer_snapshot.remote_id();
20927                        buffer_inline_values
20928                            .get(&buffer_id)
20929                            .into_iter()
20930                            .flatten()
20931                            .for_each(|hint| {
20932                                let inlay = Inlay::debugger(
20933                                    post_inc(&mut editor.next_inlay_id),
20934                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20935                                    hint.text(),
20936                                );
20937                                if !inlay.text().chars().contains(&'\n') {
20938                                    new_inlays.push(inlay);
20939                                }
20940                            });
20941                    }
20942
20943                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20944                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20945
20946                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20947                })
20948                .ok()?;
20949            Some(())
20950        });
20951    }
20952
20953    fn on_buffer_event(
20954        &mut self,
20955        multibuffer: &Entity<MultiBuffer>,
20956        event: &multi_buffer::Event,
20957        window: &mut Window,
20958        cx: &mut Context<Self>,
20959    ) {
20960        match event {
20961            multi_buffer::Event::Edited { edited_buffer } => {
20962                self.scrollbar_marker_state.dirty = true;
20963                self.active_indent_guides_state.dirty = true;
20964                self.refresh_active_diagnostics(cx);
20965                self.refresh_code_actions(window, cx);
20966                self.refresh_selected_text_highlights(true, window, cx);
20967                self.refresh_single_line_folds(window, cx);
20968                refresh_matching_bracket_highlights(self, cx);
20969                if self.has_active_edit_prediction() {
20970                    self.update_visible_edit_prediction(window, cx);
20971                }
20972
20973                if let Some(edited_buffer) = edited_buffer {
20974                    if edited_buffer.read(cx).file().is_none() {
20975                        cx.emit(EditorEvent::TitleChanged);
20976                    }
20977
20978                    let buffer_id = edited_buffer.read(cx).remote_id();
20979                    if let Some(project) = self.project.clone() {
20980                        self.register_buffer(buffer_id, cx);
20981                        self.update_lsp_data(Some(buffer_id), window, cx);
20982                        #[allow(clippy::mutable_key_type)]
20983                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20984                            multibuffer
20985                                .all_buffers()
20986                                .into_iter()
20987                                .filter_map(|buffer| {
20988                                    buffer.update(cx, |buffer, cx| {
20989                                        let language = buffer.language()?;
20990                                        let should_discard = project.update(cx, |project, cx| {
20991                                            project.is_local()
20992                                                && !project.has_language_servers_for(buffer, cx)
20993                                        });
20994                                        should_discard.not().then_some(language.clone())
20995                                    })
20996                                })
20997                                .collect::<HashSet<_>>()
20998                        });
20999                        if !languages_affected.is_empty() {
21000                            self.refresh_inlay_hints(
21001                                InlayHintRefreshReason::BufferEdited(languages_affected),
21002                                cx,
21003                            );
21004                        }
21005                    }
21006                }
21007
21008                cx.emit(EditorEvent::BufferEdited);
21009                cx.emit(SearchEvent::MatchesInvalidated);
21010
21011                let Some(project) = &self.project else { return };
21012                let (telemetry, is_via_ssh) = {
21013                    let project = project.read(cx);
21014                    let telemetry = project.client().telemetry().clone();
21015                    let is_via_ssh = project.is_via_remote_server();
21016                    (telemetry, is_via_ssh)
21017                };
21018                telemetry.log_edit_event("editor", is_via_ssh);
21019            }
21020            multi_buffer::Event::ExcerptsAdded {
21021                buffer,
21022                predecessor,
21023                excerpts,
21024            } => {
21025                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21026                let buffer_id = buffer.read(cx).remote_id();
21027                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21028                    && let Some(project) = &self.project
21029                {
21030                    update_uncommitted_diff_for_buffer(
21031                        cx.entity(),
21032                        project,
21033                        [buffer.clone()],
21034                        self.buffer.clone(),
21035                        cx,
21036                    )
21037                    .detach();
21038                }
21039                self.update_lsp_data(Some(buffer_id), window, cx);
21040                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21041                cx.emit(EditorEvent::ExcerptsAdded {
21042                    buffer: buffer.clone(),
21043                    predecessor: *predecessor,
21044                    excerpts: excerpts.clone(),
21045                });
21046            }
21047            multi_buffer::Event::ExcerptsRemoved {
21048                ids,
21049                removed_buffer_ids,
21050            } => {
21051                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21052                for buffer_id in removed_buffer_ids {
21053                    self.registered_buffers.remove(buffer_id);
21054                }
21055                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21056                cx.emit(EditorEvent::ExcerptsRemoved {
21057                    ids: ids.clone(),
21058                    removed_buffer_ids: removed_buffer_ids.clone(),
21059                });
21060            }
21061            multi_buffer::Event::ExcerptsEdited {
21062                excerpt_ids,
21063                buffer_ids,
21064            } => {
21065                self.display_map.update(cx, |map, cx| {
21066                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21067                });
21068                cx.emit(EditorEvent::ExcerptsEdited {
21069                    ids: excerpt_ids.clone(),
21070                });
21071            }
21072            multi_buffer::Event::ExcerptsExpanded { ids } => {
21073                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21074                self.refresh_document_highlights(cx);
21075                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21076            }
21077            multi_buffer::Event::Reparsed(buffer_id) => {
21078                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21079                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21080
21081                cx.emit(EditorEvent::Reparsed(*buffer_id));
21082            }
21083            multi_buffer::Event::DiffHunksToggled => {
21084                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21085            }
21086            multi_buffer::Event::LanguageChanged(buffer_id) => {
21087                self.registered_buffers.remove(&buffer_id);
21088                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21089                cx.emit(EditorEvent::Reparsed(*buffer_id));
21090                cx.notify();
21091            }
21092            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21093            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21094            multi_buffer::Event::FileHandleChanged
21095            | multi_buffer::Event::Reloaded
21096            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21097            multi_buffer::Event::DiagnosticsUpdated => {
21098                self.update_diagnostics_state(window, cx);
21099            }
21100            _ => {}
21101        };
21102    }
21103
21104    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21105        if !self.diagnostics_enabled() {
21106            return;
21107        }
21108        self.refresh_active_diagnostics(cx);
21109        self.refresh_inline_diagnostics(true, window, cx);
21110        self.scrollbar_marker_state.dirty = true;
21111        cx.notify();
21112    }
21113
21114    pub fn start_temporary_diff_override(&mut self) {
21115        self.load_diff_task.take();
21116        self.temporary_diff_override = true;
21117    }
21118
21119    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21120        self.temporary_diff_override = false;
21121        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21122        self.buffer.update(cx, |buffer, cx| {
21123            buffer.set_all_diff_hunks_collapsed(cx);
21124        });
21125
21126        if let Some(project) = self.project.clone() {
21127            self.load_diff_task = Some(
21128                update_uncommitted_diff_for_buffer(
21129                    cx.entity(),
21130                    &project,
21131                    self.buffer.read(cx).all_buffers(),
21132                    self.buffer.clone(),
21133                    cx,
21134                )
21135                .shared(),
21136            );
21137        }
21138    }
21139
21140    fn on_display_map_changed(
21141        &mut self,
21142        _: Entity<DisplayMap>,
21143        _: &mut Window,
21144        cx: &mut Context<Self>,
21145    ) {
21146        cx.notify();
21147    }
21148
21149    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21150        if self.diagnostics_enabled() {
21151            let new_severity = EditorSettings::get_global(cx)
21152                .diagnostics_max_severity
21153                .unwrap_or(DiagnosticSeverity::Hint);
21154            self.set_max_diagnostics_severity(new_severity, cx);
21155        }
21156        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21157        self.update_edit_prediction_settings(cx);
21158        self.refresh_edit_prediction(true, false, window, cx);
21159        self.refresh_inline_values(cx);
21160        self.refresh_inlay_hints(
21161            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21162                self.selections.newest_anchor().head(),
21163                &self.buffer.read(cx).snapshot(cx),
21164                cx,
21165            )),
21166            cx,
21167        );
21168
21169        let old_cursor_shape = self.cursor_shape;
21170        let old_show_breadcrumbs = self.show_breadcrumbs;
21171
21172        {
21173            let editor_settings = EditorSettings::get_global(cx);
21174            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21175            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21176            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21177            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21178        }
21179
21180        if old_cursor_shape != self.cursor_shape {
21181            cx.emit(EditorEvent::CursorShapeChanged);
21182        }
21183
21184        if old_show_breadcrumbs != self.show_breadcrumbs {
21185            cx.emit(EditorEvent::BreadcrumbsChanged);
21186        }
21187
21188        let project_settings = ProjectSettings::get_global(cx);
21189        self.serialize_dirty_buffers =
21190            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21191
21192        if self.mode.is_full() {
21193            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21194            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21195            if self.show_inline_diagnostics != show_inline_diagnostics {
21196                self.show_inline_diagnostics = show_inline_diagnostics;
21197                self.refresh_inline_diagnostics(false, window, cx);
21198            }
21199
21200            if self.git_blame_inline_enabled != inline_blame_enabled {
21201                self.toggle_git_blame_inline_internal(false, window, cx);
21202            }
21203
21204            let minimap_settings = EditorSettings::get_global(cx).minimap;
21205            if self.minimap_visibility != MinimapVisibility::Disabled {
21206                if self.minimap_visibility.settings_visibility()
21207                    != minimap_settings.minimap_enabled()
21208                {
21209                    self.set_minimap_visibility(
21210                        MinimapVisibility::for_mode(self.mode(), cx),
21211                        window,
21212                        cx,
21213                    );
21214                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21215                    minimap_entity.update(cx, |minimap_editor, cx| {
21216                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21217                    })
21218                }
21219            }
21220        }
21221
21222        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21223            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21224        }) {
21225            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21226                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21227            }
21228            self.refresh_colors_for_visible_range(None, window, cx);
21229        }
21230
21231        cx.notify();
21232    }
21233
21234    pub fn set_searchable(&mut self, searchable: bool) {
21235        self.searchable = searchable;
21236    }
21237
21238    pub fn searchable(&self) -> bool {
21239        self.searchable
21240    }
21241
21242    fn open_proposed_changes_editor(
21243        &mut self,
21244        _: &OpenProposedChangesEditor,
21245        window: &mut Window,
21246        cx: &mut Context<Self>,
21247    ) {
21248        let Some(workspace) = self.workspace() else {
21249            cx.propagate();
21250            return;
21251        };
21252
21253        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21254        let multi_buffer = self.buffer.read(cx);
21255        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21256        let mut new_selections_by_buffer = HashMap::default();
21257        for selection in selections {
21258            for (buffer, range, _) in
21259                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21260            {
21261                let mut range = range.to_point(buffer);
21262                range.start.column = 0;
21263                range.end.column = buffer.line_len(range.end.row);
21264                new_selections_by_buffer
21265                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21266                    .or_insert(Vec::new())
21267                    .push(range)
21268            }
21269        }
21270
21271        let proposed_changes_buffers = new_selections_by_buffer
21272            .into_iter()
21273            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21274            .collect::<Vec<_>>();
21275        let proposed_changes_editor = cx.new(|cx| {
21276            ProposedChangesEditor::new(
21277                "Proposed changes",
21278                proposed_changes_buffers,
21279                self.project.clone(),
21280                window,
21281                cx,
21282            )
21283        });
21284
21285        window.defer(cx, move |window, cx| {
21286            workspace.update(cx, |workspace, cx| {
21287                workspace.active_pane().update(cx, |pane, cx| {
21288                    pane.add_item(
21289                        Box::new(proposed_changes_editor),
21290                        true,
21291                        true,
21292                        None,
21293                        window,
21294                        cx,
21295                    );
21296                });
21297            });
21298        });
21299    }
21300
21301    pub fn open_excerpts_in_split(
21302        &mut self,
21303        _: &OpenExcerptsSplit,
21304        window: &mut Window,
21305        cx: &mut Context<Self>,
21306    ) {
21307        self.open_excerpts_common(None, true, window, cx)
21308    }
21309
21310    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21311        self.open_excerpts_common(None, false, window, cx)
21312    }
21313
21314    fn open_excerpts_common(
21315        &mut self,
21316        jump_data: Option<JumpData>,
21317        split: bool,
21318        window: &mut Window,
21319        cx: &mut Context<Self>,
21320    ) {
21321        let Some(workspace) = self.workspace() else {
21322            cx.propagate();
21323            return;
21324        };
21325
21326        if self.buffer.read(cx).is_singleton() {
21327            cx.propagate();
21328            return;
21329        }
21330
21331        let mut new_selections_by_buffer = HashMap::default();
21332        match &jump_data {
21333            Some(JumpData::MultiBufferPoint {
21334                excerpt_id,
21335                position,
21336                anchor,
21337                line_offset_from_top,
21338            }) => {
21339                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21340                if let Some(buffer) = multi_buffer_snapshot
21341                    .buffer_id_for_excerpt(*excerpt_id)
21342                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21343                {
21344                    let buffer_snapshot = buffer.read(cx).snapshot();
21345                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21346                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21347                    } else {
21348                        buffer_snapshot.clip_point(*position, Bias::Left)
21349                    };
21350                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21351                    new_selections_by_buffer.insert(
21352                        buffer,
21353                        (
21354                            vec![jump_to_offset..jump_to_offset],
21355                            Some(*line_offset_from_top),
21356                        ),
21357                    );
21358                }
21359            }
21360            Some(JumpData::MultiBufferRow {
21361                row,
21362                line_offset_from_top,
21363            }) => {
21364                let point = MultiBufferPoint::new(row.0, 0);
21365                if let Some((buffer, buffer_point, _)) =
21366                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21367                {
21368                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21369                    new_selections_by_buffer
21370                        .entry(buffer)
21371                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21372                        .0
21373                        .push(buffer_offset..buffer_offset)
21374                }
21375            }
21376            None => {
21377                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21378                let multi_buffer = self.buffer.read(cx);
21379                for selection in selections {
21380                    for (snapshot, range, _, anchor) in multi_buffer
21381                        .snapshot(cx)
21382                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21383                    {
21384                        if let Some(anchor) = anchor {
21385                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21386                            else {
21387                                continue;
21388                            };
21389                            let offset = text::ToOffset::to_offset(
21390                                &anchor.text_anchor,
21391                                &buffer_handle.read(cx).snapshot(),
21392                            );
21393                            let range = offset..offset;
21394                            new_selections_by_buffer
21395                                .entry(buffer_handle)
21396                                .or_insert((Vec::new(), None))
21397                                .0
21398                                .push(range)
21399                        } else {
21400                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21401                            else {
21402                                continue;
21403                            };
21404                            new_selections_by_buffer
21405                                .entry(buffer_handle)
21406                                .or_insert((Vec::new(), None))
21407                                .0
21408                                .push(range)
21409                        }
21410                    }
21411                }
21412            }
21413        }
21414
21415        new_selections_by_buffer
21416            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21417
21418        if new_selections_by_buffer.is_empty() {
21419            return;
21420        }
21421
21422        // We defer the pane interaction because we ourselves are a workspace item
21423        // and activating a new item causes the pane to call a method on us reentrantly,
21424        // which panics if we're on the stack.
21425        window.defer(cx, move |window, cx| {
21426            workspace.update(cx, |workspace, cx| {
21427                let pane = if split {
21428                    workspace.adjacent_pane(window, cx)
21429                } else {
21430                    workspace.active_pane().clone()
21431                };
21432
21433                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21434                    let editor = buffer
21435                        .read(cx)
21436                        .file()
21437                        .is_none()
21438                        .then(|| {
21439                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21440                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21441                            // Instead, we try to activate the existing editor in the pane first.
21442                            let (editor, pane_item_index) =
21443                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21444                                    let editor = item.downcast::<Editor>()?;
21445                                    let singleton_buffer =
21446                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21447                                    if singleton_buffer == buffer {
21448                                        Some((editor, i))
21449                                    } else {
21450                                        None
21451                                    }
21452                                })?;
21453                            pane.update(cx, |pane, cx| {
21454                                pane.activate_item(pane_item_index, true, true, window, cx)
21455                            });
21456                            Some(editor)
21457                        })
21458                        .flatten()
21459                        .unwrap_or_else(|| {
21460                            workspace.open_project_item::<Self>(
21461                                pane.clone(),
21462                                buffer,
21463                                true,
21464                                true,
21465                                window,
21466                                cx,
21467                            )
21468                        });
21469
21470                    editor.update(cx, |editor, cx| {
21471                        let autoscroll = match scroll_offset {
21472                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21473                            None => Autoscroll::newest(),
21474                        };
21475                        let nav_history = editor.nav_history.take();
21476                        editor.change_selections(
21477                            SelectionEffects::scroll(autoscroll),
21478                            window,
21479                            cx,
21480                            |s| {
21481                                s.select_ranges(ranges);
21482                            },
21483                        );
21484                        editor.nav_history = nav_history;
21485                    });
21486                }
21487            })
21488        });
21489    }
21490
21491    // For now, don't allow opening excerpts in buffers that aren't backed by
21492    // regular project files.
21493    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21494        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21495    }
21496
21497    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21498        let snapshot = self.buffer.read(cx).read(cx);
21499        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21500        Some(
21501            ranges
21502                .iter()
21503                .map(move |range| {
21504                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21505                })
21506                .collect(),
21507        )
21508    }
21509
21510    fn selection_replacement_ranges(
21511        &self,
21512        range: Range<OffsetUtf16>,
21513        cx: &mut App,
21514    ) -> Vec<Range<OffsetUtf16>> {
21515        let selections = self
21516            .selections
21517            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21518        let newest_selection = selections
21519            .iter()
21520            .max_by_key(|selection| selection.id)
21521            .unwrap();
21522        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21523        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21524        let snapshot = self.buffer.read(cx).read(cx);
21525        selections
21526            .into_iter()
21527            .map(|mut selection| {
21528                selection.start.0 =
21529                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21530                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21531                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21532                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21533            })
21534            .collect()
21535    }
21536
21537    fn report_editor_event(
21538        &self,
21539        reported_event: ReportEditorEvent,
21540        file_extension: Option<String>,
21541        cx: &App,
21542    ) {
21543        if cfg!(any(test, feature = "test-support")) {
21544            return;
21545        }
21546
21547        let Some(project) = &self.project else { return };
21548
21549        // If None, we are in a file without an extension
21550        let file = self
21551            .buffer
21552            .read(cx)
21553            .as_singleton()
21554            .and_then(|b| b.read(cx).file());
21555        let file_extension = file_extension.or(file
21556            .as_ref()
21557            .and_then(|file| Path::new(file.file_name(cx)).extension())
21558            .and_then(|e| e.to_str())
21559            .map(|a| a.to_string()));
21560
21561        let vim_mode = vim_enabled(cx);
21562
21563        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21564        let copilot_enabled = edit_predictions_provider
21565            == language::language_settings::EditPredictionProvider::Copilot;
21566        let copilot_enabled_for_language = self
21567            .buffer
21568            .read(cx)
21569            .language_settings(cx)
21570            .show_edit_predictions;
21571
21572        let project = project.read(cx);
21573        let event_type = reported_event.event_type();
21574
21575        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21576            telemetry::event!(
21577                event_type,
21578                type = if auto_saved {"autosave"} else {"manual"},
21579                file_extension,
21580                vim_mode,
21581                copilot_enabled,
21582                copilot_enabled_for_language,
21583                edit_predictions_provider,
21584                is_via_ssh = project.is_via_remote_server(),
21585            );
21586        } else {
21587            telemetry::event!(
21588                event_type,
21589                file_extension,
21590                vim_mode,
21591                copilot_enabled,
21592                copilot_enabled_for_language,
21593                edit_predictions_provider,
21594                is_via_ssh = project.is_via_remote_server(),
21595            );
21596        };
21597    }
21598
21599    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21600    /// with each line being an array of {text, highlight} objects.
21601    fn copy_highlight_json(
21602        &mut self,
21603        _: &CopyHighlightJson,
21604        window: &mut Window,
21605        cx: &mut Context<Self>,
21606    ) {
21607        #[derive(Serialize)]
21608        struct Chunk<'a> {
21609            text: String,
21610            highlight: Option<&'a str>,
21611        }
21612
21613        let snapshot = self.buffer.read(cx).snapshot(cx);
21614        let range = self
21615            .selected_text_range(false, window, cx)
21616            .and_then(|selection| {
21617                if selection.range.is_empty() {
21618                    None
21619                } else {
21620                    Some(selection.range)
21621                }
21622            })
21623            .unwrap_or_else(|| 0..snapshot.len());
21624
21625        let chunks = snapshot.chunks(range, true);
21626        let mut lines = Vec::new();
21627        let mut line: VecDeque<Chunk> = VecDeque::new();
21628
21629        let Some(style) = self.style.as_ref() else {
21630            return;
21631        };
21632
21633        for chunk in chunks {
21634            let highlight = chunk
21635                .syntax_highlight_id
21636                .and_then(|id| id.name(&style.syntax));
21637            let mut chunk_lines = chunk.text.split('\n').peekable();
21638            while let Some(text) = chunk_lines.next() {
21639                let mut merged_with_last_token = false;
21640                if let Some(last_token) = line.back_mut()
21641                    && last_token.highlight == highlight
21642                {
21643                    last_token.text.push_str(text);
21644                    merged_with_last_token = true;
21645                }
21646
21647                if !merged_with_last_token {
21648                    line.push_back(Chunk {
21649                        text: text.into(),
21650                        highlight,
21651                    });
21652                }
21653
21654                if chunk_lines.peek().is_some() {
21655                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21656                        line.pop_front();
21657                    }
21658                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21659                        line.pop_back();
21660                    }
21661
21662                    lines.push(mem::take(&mut line));
21663                }
21664            }
21665        }
21666
21667        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21668            return;
21669        };
21670        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21671    }
21672
21673    pub fn open_context_menu(
21674        &mut self,
21675        _: &OpenContextMenu,
21676        window: &mut Window,
21677        cx: &mut Context<Self>,
21678    ) {
21679        self.request_autoscroll(Autoscroll::newest(), cx);
21680        let position = self
21681            .selections
21682            .newest_display(&self.display_snapshot(cx))
21683            .start;
21684        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21685    }
21686
21687    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21688        &self.inlay_hint_cache
21689    }
21690
21691    pub fn replay_insert_event(
21692        &mut self,
21693        text: &str,
21694        relative_utf16_range: Option<Range<isize>>,
21695        window: &mut Window,
21696        cx: &mut Context<Self>,
21697    ) {
21698        if !self.input_enabled {
21699            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21700            return;
21701        }
21702        if let Some(relative_utf16_range) = relative_utf16_range {
21703            let selections = self
21704                .selections
21705                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21706            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21707                let new_ranges = selections.into_iter().map(|range| {
21708                    let start = OffsetUtf16(
21709                        range
21710                            .head()
21711                            .0
21712                            .saturating_add_signed(relative_utf16_range.start),
21713                    );
21714                    let end = OffsetUtf16(
21715                        range
21716                            .head()
21717                            .0
21718                            .saturating_add_signed(relative_utf16_range.end),
21719                    );
21720                    start..end
21721                });
21722                s.select_ranges(new_ranges);
21723            });
21724        }
21725
21726        self.handle_input(text, window, cx);
21727    }
21728
21729    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21730        let Some(provider) = self.semantics_provider.as_ref() else {
21731            return false;
21732        };
21733
21734        let mut supports = false;
21735        self.buffer().update(cx, |this, cx| {
21736            this.for_each_buffer(|buffer| {
21737                supports |= provider.supports_inlay_hints(buffer, cx);
21738            });
21739        });
21740
21741        supports
21742    }
21743
21744    pub fn is_focused(&self, window: &Window) -> bool {
21745        self.focus_handle.is_focused(window)
21746    }
21747
21748    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21749        cx.emit(EditorEvent::Focused);
21750
21751        if let Some(descendant) = self
21752            .last_focused_descendant
21753            .take()
21754            .and_then(|descendant| descendant.upgrade())
21755        {
21756            window.focus(&descendant);
21757        } else {
21758            if let Some(blame) = self.blame.as_ref() {
21759                blame.update(cx, GitBlame::focus)
21760            }
21761
21762            self.blink_manager.update(cx, BlinkManager::enable);
21763            self.show_cursor_names(window, cx);
21764            self.buffer.update(cx, |buffer, cx| {
21765                buffer.finalize_last_transaction(cx);
21766                if self.leader_id.is_none() {
21767                    buffer.set_active_selections(
21768                        &self.selections.disjoint_anchors_arc(),
21769                        self.selections.line_mode(),
21770                        self.cursor_shape,
21771                        cx,
21772                    );
21773                }
21774            });
21775        }
21776    }
21777
21778    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21779        cx.emit(EditorEvent::FocusedIn)
21780    }
21781
21782    fn handle_focus_out(
21783        &mut self,
21784        event: FocusOutEvent,
21785        _window: &mut Window,
21786        cx: &mut Context<Self>,
21787    ) {
21788        if event.blurred != self.focus_handle {
21789            self.last_focused_descendant = Some(event.blurred);
21790        }
21791        self.selection_drag_state = SelectionDragState::None;
21792        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21793    }
21794
21795    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21796        self.blink_manager.update(cx, BlinkManager::disable);
21797        self.buffer
21798            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21799
21800        if let Some(blame) = self.blame.as_ref() {
21801            blame.update(cx, GitBlame::blur)
21802        }
21803        if !self.hover_state.focused(window, cx) {
21804            hide_hover(self, cx);
21805        }
21806        if !self
21807            .context_menu
21808            .borrow()
21809            .as_ref()
21810            .is_some_and(|context_menu| context_menu.focused(window, cx))
21811        {
21812            self.hide_context_menu(window, cx);
21813        }
21814        self.take_active_edit_prediction(cx);
21815        cx.emit(EditorEvent::Blurred);
21816        cx.notify();
21817    }
21818
21819    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21820        let mut pending: String = window
21821            .pending_input_keystrokes()
21822            .into_iter()
21823            .flatten()
21824            .filter_map(|keystroke| {
21825                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21826                    keystroke.key_char.clone()
21827                } else {
21828                    None
21829                }
21830            })
21831            .collect();
21832
21833        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21834            pending = "".to_string();
21835        }
21836
21837        let existing_pending = self
21838            .text_highlights::<PendingInput>(cx)
21839            .map(|(_, ranges)| ranges.to_vec());
21840        if existing_pending.is_none() && pending.is_empty() {
21841            return;
21842        }
21843        let transaction =
21844            self.transact(window, cx, |this, window, cx| {
21845                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21846                let edits = selections
21847                    .iter()
21848                    .map(|selection| (selection.end..selection.end, pending.clone()));
21849                this.edit(edits, cx);
21850                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21851                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21852                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21853                    }));
21854                });
21855                if let Some(existing_ranges) = existing_pending {
21856                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21857                    this.edit(edits, cx);
21858                }
21859            });
21860
21861        let snapshot = self.snapshot(window, cx);
21862        let ranges = self
21863            .selections
21864            .all::<usize>(&snapshot.display_snapshot)
21865            .into_iter()
21866            .map(|selection| {
21867                snapshot.buffer_snapshot().anchor_after(selection.end)
21868                    ..snapshot
21869                        .buffer_snapshot()
21870                        .anchor_before(selection.end + pending.len())
21871            })
21872            .collect();
21873
21874        if pending.is_empty() {
21875            self.clear_highlights::<PendingInput>(cx);
21876        } else {
21877            self.highlight_text::<PendingInput>(
21878                ranges,
21879                HighlightStyle {
21880                    underline: Some(UnderlineStyle {
21881                        thickness: px(1.),
21882                        color: None,
21883                        wavy: false,
21884                    }),
21885                    ..Default::default()
21886                },
21887                cx,
21888            );
21889        }
21890
21891        self.ime_transaction = self.ime_transaction.or(transaction);
21892        if let Some(transaction) = self.ime_transaction {
21893            self.buffer.update(cx, |buffer, cx| {
21894                buffer.group_until_transaction(transaction, cx);
21895            });
21896        }
21897
21898        if self.text_highlights::<PendingInput>(cx).is_none() {
21899            self.ime_transaction.take();
21900        }
21901    }
21902
21903    pub fn register_action_renderer(
21904        &mut self,
21905        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21906    ) -> Subscription {
21907        let id = self.next_editor_action_id.post_inc();
21908        self.editor_actions
21909            .borrow_mut()
21910            .insert(id, Box::new(listener));
21911
21912        let editor_actions = self.editor_actions.clone();
21913        Subscription::new(move || {
21914            editor_actions.borrow_mut().remove(&id);
21915        })
21916    }
21917
21918    pub fn register_action<A: Action>(
21919        &mut self,
21920        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21921    ) -> Subscription {
21922        let id = self.next_editor_action_id.post_inc();
21923        let listener = Arc::new(listener);
21924        self.editor_actions.borrow_mut().insert(
21925            id,
21926            Box::new(move |_, window, _| {
21927                let listener = listener.clone();
21928                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21929                    let action = action.downcast_ref().unwrap();
21930                    if phase == DispatchPhase::Bubble {
21931                        listener(action, window, cx)
21932                    }
21933                })
21934            }),
21935        );
21936
21937        let editor_actions = self.editor_actions.clone();
21938        Subscription::new(move || {
21939            editor_actions.borrow_mut().remove(&id);
21940        })
21941    }
21942
21943    pub fn file_header_size(&self) -> u32 {
21944        FILE_HEADER_HEIGHT
21945    }
21946
21947    pub fn restore(
21948        &mut self,
21949        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21950        window: &mut Window,
21951        cx: &mut Context<Self>,
21952    ) {
21953        let workspace = self.workspace();
21954        let project = self.project();
21955        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21956            let mut tasks = Vec::new();
21957            for (buffer_id, changes) in revert_changes {
21958                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21959                    buffer.update(cx, |buffer, cx| {
21960                        buffer.edit(
21961                            changes
21962                                .into_iter()
21963                                .map(|(range, text)| (range, text.to_string())),
21964                            None,
21965                            cx,
21966                        );
21967                    });
21968
21969                    if let Some(project) =
21970                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21971                    {
21972                        project.update(cx, |project, cx| {
21973                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21974                        })
21975                    }
21976                }
21977            }
21978            tasks
21979        });
21980        cx.spawn_in(window, async move |_, cx| {
21981            for (buffer, task) in save_tasks {
21982                let result = task.await;
21983                if result.is_err() {
21984                    let Some(path) = buffer
21985                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21986                        .ok()
21987                    else {
21988                        continue;
21989                    };
21990                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21991                        let Some(task) = cx
21992                            .update_window_entity(workspace, |workspace, window, cx| {
21993                                workspace
21994                                    .open_path_preview(path, None, false, false, false, window, cx)
21995                            })
21996                            .ok()
21997                        else {
21998                            continue;
21999                        };
22000                        task.await.log_err();
22001                    }
22002                }
22003            }
22004        })
22005        .detach();
22006        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22007            selections.refresh()
22008        });
22009    }
22010
22011    pub fn to_pixel_point(
22012        &self,
22013        source: multi_buffer::Anchor,
22014        editor_snapshot: &EditorSnapshot,
22015        window: &mut Window,
22016    ) -> Option<gpui::Point<Pixels>> {
22017        let source_point = source.to_display_point(editor_snapshot);
22018        self.display_to_pixel_point(source_point, editor_snapshot, window)
22019    }
22020
22021    pub fn display_to_pixel_point(
22022        &self,
22023        source: DisplayPoint,
22024        editor_snapshot: &EditorSnapshot,
22025        window: &mut Window,
22026    ) -> Option<gpui::Point<Pixels>> {
22027        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22028        let text_layout_details = self.text_layout_details(window);
22029        let scroll_top = text_layout_details
22030            .scroll_anchor
22031            .scroll_position(editor_snapshot)
22032            .y;
22033
22034        if source.row().as_f64() < scroll_top.floor() {
22035            return None;
22036        }
22037        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22038        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22039        Some(gpui::Point::new(source_x, source_y))
22040    }
22041
22042    pub fn has_visible_completions_menu(&self) -> bool {
22043        !self.edit_prediction_preview_is_active()
22044            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22045                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22046            })
22047    }
22048
22049    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22050        if self.mode.is_minimap() {
22051            return;
22052        }
22053        self.addons
22054            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22055    }
22056
22057    pub fn unregister_addon<T: Addon>(&mut self) {
22058        self.addons.remove(&std::any::TypeId::of::<T>());
22059    }
22060
22061    pub fn addon<T: Addon>(&self) -> Option<&T> {
22062        let type_id = std::any::TypeId::of::<T>();
22063        self.addons
22064            .get(&type_id)
22065            .and_then(|item| item.to_any().downcast_ref::<T>())
22066    }
22067
22068    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22069        let type_id = std::any::TypeId::of::<T>();
22070        self.addons
22071            .get_mut(&type_id)
22072            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22073    }
22074
22075    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22076        let text_layout_details = self.text_layout_details(window);
22077        let style = &text_layout_details.editor_style;
22078        let font_id = window.text_system().resolve_font(&style.text.font());
22079        let font_size = style.text.font_size.to_pixels(window.rem_size());
22080        let line_height = style.text.line_height_in_pixels(window.rem_size());
22081        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22082        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22083
22084        CharacterDimensions {
22085            em_width,
22086            em_advance,
22087            line_height,
22088        }
22089    }
22090
22091    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22092        self.load_diff_task.clone()
22093    }
22094
22095    fn read_metadata_from_db(
22096        &mut self,
22097        item_id: u64,
22098        workspace_id: WorkspaceId,
22099        window: &mut Window,
22100        cx: &mut Context<Editor>,
22101    ) {
22102        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22103            && !self.mode.is_minimap()
22104            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22105        {
22106            let buffer_snapshot = OnceCell::new();
22107
22108            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22109                && !folds.is_empty()
22110            {
22111                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22112                self.fold_ranges(
22113                    folds
22114                        .into_iter()
22115                        .map(|(start, end)| {
22116                            snapshot.clip_offset(start, Bias::Left)
22117                                ..snapshot.clip_offset(end, Bias::Right)
22118                        })
22119                        .collect(),
22120                    false,
22121                    window,
22122                    cx,
22123                );
22124            }
22125
22126            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22127                && !selections.is_empty()
22128            {
22129                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22130                // skip adding the initial selection to selection history
22131                self.selection_history.mode = SelectionHistoryMode::Skipping;
22132                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22133                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22134                        snapshot.clip_offset(start, Bias::Left)
22135                            ..snapshot.clip_offset(end, Bias::Right)
22136                    }));
22137                });
22138                self.selection_history.mode = SelectionHistoryMode::Normal;
22139            };
22140        }
22141
22142        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22143    }
22144
22145    fn update_lsp_data(
22146        &mut self,
22147        for_buffer: Option<BufferId>,
22148        window: &mut Window,
22149        cx: &mut Context<'_, Self>,
22150    ) {
22151        self.pull_diagnostics(for_buffer, window, cx);
22152        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22153    }
22154
22155    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22156        if self.ignore_lsp_data() {
22157            return;
22158        }
22159        for (_, (visible_buffer, _, _)) in self.visible_excerpts(None, cx) {
22160            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22161        }
22162    }
22163
22164    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) -> bool {
22165        if !self.registered_buffers.contains_key(&buffer_id)
22166            && let Some(project) = self.project.as_ref()
22167        {
22168            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22169                project.update(cx, |project, cx| {
22170                    self.registered_buffers.insert(
22171                        buffer_id,
22172                        project.register_buffer_with_language_servers(&buffer, cx),
22173                    );
22174                });
22175                return true;
22176            } else {
22177                self.registered_buffers.remove(&buffer_id);
22178            }
22179        }
22180
22181        false
22182    }
22183
22184    fn ignore_lsp_data(&self) -> bool {
22185        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22186        // skip any LSP updates for it.
22187        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22188    }
22189}
22190
22191fn edit_for_markdown_paste<'a>(
22192    buffer: &MultiBufferSnapshot,
22193    range: Range<usize>,
22194    to_insert: &'a str,
22195    url: Option<url::Url>,
22196) -> (Range<usize>, Cow<'a, str>) {
22197    if url.is_none() {
22198        return (range, Cow::Borrowed(to_insert));
22199    };
22200
22201    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22202
22203    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22204        Cow::Borrowed(to_insert)
22205    } else {
22206        Cow::Owned(format!("[{old_text}]({to_insert})"))
22207    };
22208    (range, new_text)
22209}
22210
22211fn vim_enabled(cx: &App) -> bool {
22212    vim_mode_setting::VimModeSetting::try_get(cx)
22213        .map(|vim_mode| vim_mode.0)
22214        .unwrap_or(false)
22215}
22216
22217fn process_completion_for_edit(
22218    completion: &Completion,
22219    intent: CompletionIntent,
22220    buffer: &Entity<Buffer>,
22221    cursor_position: &text::Anchor,
22222    cx: &mut Context<Editor>,
22223) -> CompletionEdit {
22224    let buffer = buffer.read(cx);
22225    let buffer_snapshot = buffer.snapshot();
22226    let (snippet, new_text) = if completion.is_snippet() {
22227        let mut snippet_source = completion.new_text.clone();
22228        // Workaround for typescript language server issues so that methods don't expand within
22229        // strings and functions with type expressions. The previous point is used because the query
22230        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22231        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22232        let previous_point = if previous_point.column > 0 {
22233            cursor_position.to_previous_offset(&buffer_snapshot)
22234        } else {
22235            cursor_position.to_offset(&buffer_snapshot)
22236        };
22237        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22238            && scope.prefers_label_for_snippet_in_completion()
22239            && let Some(label) = completion.label()
22240            && matches!(
22241                completion.kind(),
22242                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22243            )
22244        {
22245            snippet_source = label;
22246        }
22247        match Snippet::parse(&snippet_source).log_err() {
22248            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22249            None => (None, completion.new_text.clone()),
22250        }
22251    } else {
22252        (None, completion.new_text.clone())
22253    };
22254
22255    let mut range_to_replace = {
22256        let replace_range = &completion.replace_range;
22257        if let CompletionSource::Lsp {
22258            insert_range: Some(insert_range),
22259            ..
22260        } = &completion.source
22261        {
22262            debug_assert_eq!(
22263                insert_range.start, replace_range.start,
22264                "insert_range and replace_range should start at the same position"
22265            );
22266            debug_assert!(
22267                insert_range
22268                    .start
22269                    .cmp(cursor_position, &buffer_snapshot)
22270                    .is_le(),
22271                "insert_range should start before or at cursor position"
22272            );
22273            debug_assert!(
22274                replace_range
22275                    .start
22276                    .cmp(cursor_position, &buffer_snapshot)
22277                    .is_le(),
22278                "replace_range should start before or at cursor position"
22279            );
22280
22281            let should_replace = match intent {
22282                CompletionIntent::CompleteWithInsert => false,
22283                CompletionIntent::CompleteWithReplace => true,
22284                CompletionIntent::Complete | CompletionIntent::Compose => {
22285                    let insert_mode =
22286                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22287                            .completions
22288                            .lsp_insert_mode;
22289                    match insert_mode {
22290                        LspInsertMode::Insert => false,
22291                        LspInsertMode::Replace => true,
22292                        LspInsertMode::ReplaceSubsequence => {
22293                            let mut text_to_replace = buffer.chars_for_range(
22294                                buffer.anchor_before(replace_range.start)
22295                                    ..buffer.anchor_after(replace_range.end),
22296                            );
22297                            let mut current_needle = text_to_replace.next();
22298                            for haystack_ch in completion.label.text.chars() {
22299                                if let Some(needle_ch) = current_needle
22300                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22301                                {
22302                                    current_needle = text_to_replace.next();
22303                                }
22304                            }
22305                            current_needle.is_none()
22306                        }
22307                        LspInsertMode::ReplaceSuffix => {
22308                            if replace_range
22309                                .end
22310                                .cmp(cursor_position, &buffer_snapshot)
22311                                .is_gt()
22312                            {
22313                                let range_after_cursor = *cursor_position..replace_range.end;
22314                                let text_after_cursor = buffer
22315                                    .text_for_range(
22316                                        buffer.anchor_before(range_after_cursor.start)
22317                                            ..buffer.anchor_after(range_after_cursor.end),
22318                                    )
22319                                    .collect::<String>()
22320                                    .to_ascii_lowercase();
22321                                completion
22322                                    .label
22323                                    .text
22324                                    .to_ascii_lowercase()
22325                                    .ends_with(&text_after_cursor)
22326                            } else {
22327                                true
22328                            }
22329                        }
22330                    }
22331                }
22332            };
22333
22334            if should_replace {
22335                replace_range.clone()
22336            } else {
22337                insert_range.clone()
22338            }
22339        } else {
22340            replace_range.clone()
22341        }
22342    };
22343
22344    if range_to_replace
22345        .end
22346        .cmp(cursor_position, &buffer_snapshot)
22347        .is_lt()
22348    {
22349        range_to_replace.end = *cursor_position;
22350    }
22351
22352    CompletionEdit {
22353        new_text,
22354        replace_range: range_to_replace.to_offset(buffer),
22355        snippet,
22356    }
22357}
22358
22359struct CompletionEdit {
22360    new_text: String,
22361    replace_range: Range<usize>,
22362    snippet: Option<Snippet>,
22363}
22364
22365fn insert_extra_newline_brackets(
22366    buffer: &MultiBufferSnapshot,
22367    range: Range<usize>,
22368    language: &language::LanguageScope,
22369) -> bool {
22370    let leading_whitespace_len = buffer
22371        .reversed_chars_at(range.start)
22372        .take_while(|c| c.is_whitespace() && *c != '\n')
22373        .map(|c| c.len_utf8())
22374        .sum::<usize>();
22375    let trailing_whitespace_len = buffer
22376        .chars_at(range.end)
22377        .take_while(|c| c.is_whitespace() && *c != '\n')
22378        .map(|c| c.len_utf8())
22379        .sum::<usize>();
22380    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22381
22382    language.brackets().any(|(pair, enabled)| {
22383        let pair_start = pair.start.trim_end();
22384        let pair_end = pair.end.trim_start();
22385
22386        enabled
22387            && pair.newline
22388            && buffer.contains_str_at(range.end, pair_end)
22389            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22390    })
22391}
22392
22393fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22394    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22395        [(buffer, range, _)] => (*buffer, range.clone()),
22396        _ => return false,
22397    };
22398    let pair = {
22399        let mut result: Option<BracketMatch> = None;
22400
22401        for pair in buffer
22402            .all_bracket_ranges(range.clone())
22403            .filter(move |pair| {
22404                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22405            })
22406        {
22407            let len = pair.close_range.end - pair.open_range.start;
22408
22409            if let Some(existing) = &result {
22410                let existing_len = existing.close_range.end - existing.open_range.start;
22411                if len > existing_len {
22412                    continue;
22413                }
22414            }
22415
22416            result = Some(pair);
22417        }
22418
22419        result
22420    };
22421    let Some(pair) = pair else {
22422        return false;
22423    };
22424    pair.newline_only
22425        && buffer
22426            .chars_for_range(pair.open_range.end..range.start)
22427            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22428            .all(|c| c.is_whitespace() && c != '\n')
22429}
22430
22431fn update_uncommitted_diff_for_buffer(
22432    editor: Entity<Editor>,
22433    project: &Entity<Project>,
22434    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22435    buffer: Entity<MultiBuffer>,
22436    cx: &mut App,
22437) -> Task<()> {
22438    let mut tasks = Vec::new();
22439    project.update(cx, |project, cx| {
22440        for buffer in buffers {
22441            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22442                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22443            }
22444        }
22445    });
22446    cx.spawn(async move |cx| {
22447        let diffs = future::join_all(tasks).await;
22448        if editor
22449            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22450            .unwrap_or(false)
22451        {
22452            return;
22453        }
22454
22455        buffer
22456            .update(cx, |buffer, cx| {
22457                for diff in diffs.into_iter().flatten() {
22458                    buffer.add_diff(diff, cx);
22459                }
22460            })
22461            .ok();
22462    })
22463}
22464
22465fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22466    let tab_size = tab_size.get() as usize;
22467    let mut width = offset;
22468
22469    for ch in text.chars() {
22470        width += if ch == '\t' {
22471            tab_size - (width % tab_size)
22472        } else {
22473            1
22474        };
22475    }
22476
22477    width - offset
22478}
22479
22480#[cfg(test)]
22481mod tests {
22482    use super::*;
22483
22484    #[test]
22485    fn test_string_size_with_expanded_tabs() {
22486        let nz = |val| NonZeroU32::new(val).unwrap();
22487        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22488        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22489        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22490        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22491        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22492        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22493        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22494        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22495    }
22496}
22497
22498/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22499struct WordBreakingTokenizer<'a> {
22500    input: &'a str,
22501}
22502
22503impl<'a> WordBreakingTokenizer<'a> {
22504    fn new(input: &'a str) -> Self {
22505        Self { input }
22506    }
22507}
22508
22509fn is_char_ideographic(ch: char) -> bool {
22510    use unicode_script::Script::*;
22511    use unicode_script::UnicodeScript;
22512    matches!(ch.script(), Han | Tangut | Yi)
22513}
22514
22515fn is_grapheme_ideographic(text: &str) -> bool {
22516    text.chars().any(is_char_ideographic)
22517}
22518
22519fn is_grapheme_whitespace(text: &str) -> bool {
22520    text.chars().any(|x| x.is_whitespace())
22521}
22522
22523fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22524    text.chars()
22525        .next()
22526        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22527}
22528
22529#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22530enum WordBreakToken<'a> {
22531    Word { token: &'a str, grapheme_len: usize },
22532    InlineWhitespace { token: &'a str, grapheme_len: usize },
22533    Newline,
22534}
22535
22536impl<'a> Iterator for WordBreakingTokenizer<'a> {
22537    /// Yields a span, the count of graphemes in the token, and whether it was
22538    /// whitespace. Note that it also breaks at word boundaries.
22539    type Item = WordBreakToken<'a>;
22540
22541    fn next(&mut self) -> Option<Self::Item> {
22542        use unicode_segmentation::UnicodeSegmentation;
22543        if self.input.is_empty() {
22544            return None;
22545        }
22546
22547        let mut iter = self.input.graphemes(true).peekable();
22548        let mut offset = 0;
22549        let mut grapheme_len = 0;
22550        if let Some(first_grapheme) = iter.next() {
22551            let is_newline = first_grapheme == "\n";
22552            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22553            offset += first_grapheme.len();
22554            grapheme_len += 1;
22555            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22556                if let Some(grapheme) = iter.peek().copied()
22557                    && should_stay_with_preceding_ideograph(grapheme)
22558                {
22559                    offset += grapheme.len();
22560                    grapheme_len += 1;
22561                }
22562            } else {
22563                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22564                let mut next_word_bound = words.peek().copied();
22565                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22566                    next_word_bound = words.next();
22567                }
22568                while let Some(grapheme) = iter.peek().copied() {
22569                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22570                        break;
22571                    };
22572                    if is_grapheme_whitespace(grapheme) != is_whitespace
22573                        || (grapheme == "\n") != is_newline
22574                    {
22575                        break;
22576                    };
22577                    offset += grapheme.len();
22578                    grapheme_len += 1;
22579                    iter.next();
22580                }
22581            }
22582            let token = &self.input[..offset];
22583            self.input = &self.input[offset..];
22584            if token == "\n" {
22585                Some(WordBreakToken::Newline)
22586            } else if is_whitespace {
22587                Some(WordBreakToken::InlineWhitespace {
22588                    token,
22589                    grapheme_len,
22590                })
22591            } else {
22592                Some(WordBreakToken::Word {
22593                    token,
22594                    grapheme_len,
22595                })
22596            }
22597        } else {
22598            None
22599        }
22600    }
22601}
22602
22603#[test]
22604fn test_word_breaking_tokenizer() {
22605    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22606        ("", &[]),
22607        ("  ", &[whitespace("  ", 2)]),
22608        ("Ʒ", &[word("Ʒ", 1)]),
22609        ("Ǽ", &[word("Ǽ", 1)]),
22610        ("", &[word("", 1)]),
22611        ("⋑⋑", &[word("⋑⋑", 2)]),
22612        (
22613            "原理,进而",
22614            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22615        ),
22616        (
22617            "hello world",
22618            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22619        ),
22620        (
22621            "hello, world",
22622            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22623        ),
22624        (
22625            "  hello world",
22626            &[
22627                whitespace("  ", 2),
22628                word("hello", 5),
22629                whitespace(" ", 1),
22630                word("world", 5),
22631            ],
22632        ),
22633        (
22634            "这是什么 \n 钢笔",
22635            &[
22636                word("", 1),
22637                word("", 1),
22638                word("", 1),
22639                word("", 1),
22640                whitespace(" ", 1),
22641                newline(),
22642                whitespace(" ", 1),
22643                word("", 1),
22644                word("", 1),
22645            ],
22646        ),
22647        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22648    ];
22649
22650    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22651        WordBreakToken::Word {
22652            token,
22653            grapheme_len,
22654        }
22655    }
22656
22657    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22658        WordBreakToken::InlineWhitespace {
22659            token,
22660            grapheme_len,
22661        }
22662    }
22663
22664    fn newline() -> WordBreakToken<'static> {
22665        WordBreakToken::Newline
22666    }
22667
22668    for (input, result) in tests {
22669        assert_eq!(
22670            WordBreakingTokenizer::new(input)
22671                .collect::<Vec<_>>()
22672                .as_slice(),
22673            *result,
22674        );
22675    }
22676}
22677
22678fn wrap_with_prefix(
22679    first_line_prefix: String,
22680    subsequent_lines_prefix: String,
22681    unwrapped_text: String,
22682    wrap_column: usize,
22683    tab_size: NonZeroU32,
22684    preserve_existing_whitespace: bool,
22685) -> String {
22686    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22687    let subsequent_lines_prefix_len =
22688        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22689    let mut wrapped_text = String::new();
22690    let mut current_line = first_line_prefix;
22691    let mut is_first_line = true;
22692
22693    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22694    let mut current_line_len = first_line_prefix_len;
22695    let mut in_whitespace = false;
22696    for token in tokenizer {
22697        let have_preceding_whitespace = in_whitespace;
22698        match token {
22699            WordBreakToken::Word {
22700                token,
22701                grapheme_len,
22702            } => {
22703                in_whitespace = false;
22704                let current_prefix_len = if is_first_line {
22705                    first_line_prefix_len
22706                } else {
22707                    subsequent_lines_prefix_len
22708                };
22709                if current_line_len + grapheme_len > wrap_column
22710                    && current_line_len != current_prefix_len
22711                {
22712                    wrapped_text.push_str(current_line.trim_end());
22713                    wrapped_text.push('\n');
22714                    is_first_line = false;
22715                    current_line = subsequent_lines_prefix.clone();
22716                    current_line_len = subsequent_lines_prefix_len;
22717                }
22718                current_line.push_str(token);
22719                current_line_len += grapheme_len;
22720            }
22721            WordBreakToken::InlineWhitespace {
22722                mut token,
22723                mut grapheme_len,
22724            } => {
22725                in_whitespace = true;
22726                if have_preceding_whitespace && !preserve_existing_whitespace {
22727                    continue;
22728                }
22729                if !preserve_existing_whitespace {
22730                    // Keep a single whitespace grapheme as-is
22731                    if let Some(first) =
22732                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22733                    {
22734                        token = first;
22735                    } else {
22736                        token = " ";
22737                    }
22738                    grapheme_len = 1;
22739                }
22740                let current_prefix_len = if is_first_line {
22741                    first_line_prefix_len
22742                } else {
22743                    subsequent_lines_prefix_len
22744                };
22745                if current_line_len + grapheme_len > wrap_column {
22746                    wrapped_text.push_str(current_line.trim_end());
22747                    wrapped_text.push('\n');
22748                    is_first_line = false;
22749                    current_line = subsequent_lines_prefix.clone();
22750                    current_line_len = subsequent_lines_prefix_len;
22751                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22752                    current_line.push_str(token);
22753                    current_line_len += grapheme_len;
22754                }
22755            }
22756            WordBreakToken::Newline => {
22757                in_whitespace = true;
22758                let current_prefix_len = if is_first_line {
22759                    first_line_prefix_len
22760                } else {
22761                    subsequent_lines_prefix_len
22762                };
22763                if preserve_existing_whitespace {
22764                    wrapped_text.push_str(current_line.trim_end());
22765                    wrapped_text.push('\n');
22766                    is_first_line = false;
22767                    current_line = subsequent_lines_prefix.clone();
22768                    current_line_len = subsequent_lines_prefix_len;
22769                } else if have_preceding_whitespace {
22770                    continue;
22771                } else if current_line_len + 1 > wrap_column
22772                    && current_line_len != current_prefix_len
22773                {
22774                    wrapped_text.push_str(current_line.trim_end());
22775                    wrapped_text.push('\n');
22776                    is_first_line = false;
22777                    current_line = subsequent_lines_prefix.clone();
22778                    current_line_len = subsequent_lines_prefix_len;
22779                } else if current_line_len != current_prefix_len {
22780                    current_line.push(' ');
22781                    current_line_len += 1;
22782                }
22783            }
22784        }
22785    }
22786
22787    if !current_line.is_empty() {
22788        wrapped_text.push_str(&current_line);
22789    }
22790    wrapped_text
22791}
22792
22793#[test]
22794fn test_wrap_with_prefix() {
22795    assert_eq!(
22796        wrap_with_prefix(
22797            "# ".to_string(),
22798            "# ".to_string(),
22799            "abcdefg".to_string(),
22800            4,
22801            NonZeroU32::new(4).unwrap(),
22802            false,
22803        ),
22804        "# abcdefg"
22805    );
22806    assert_eq!(
22807        wrap_with_prefix(
22808            "".to_string(),
22809            "".to_string(),
22810            "\thello world".to_string(),
22811            8,
22812            NonZeroU32::new(4).unwrap(),
22813            false,
22814        ),
22815        "hello\nworld"
22816    );
22817    assert_eq!(
22818        wrap_with_prefix(
22819            "// ".to_string(),
22820            "// ".to_string(),
22821            "xx \nyy zz aa bb cc".to_string(),
22822            12,
22823            NonZeroU32::new(4).unwrap(),
22824            false,
22825        ),
22826        "// xx yy zz\n// aa bb cc"
22827    );
22828    assert_eq!(
22829        wrap_with_prefix(
22830            String::new(),
22831            String::new(),
22832            "这是什么 \n 钢笔".to_string(),
22833            3,
22834            NonZeroU32::new(4).unwrap(),
22835            false,
22836        ),
22837        "这是什\n么 钢\n"
22838    );
22839    assert_eq!(
22840        wrap_with_prefix(
22841            String::new(),
22842            String::new(),
22843            format!("foo{}bar", '\u{2009}'), // thin space
22844            80,
22845            NonZeroU32::new(4).unwrap(),
22846            false,
22847        ),
22848        format!("foo{}bar", '\u{2009}')
22849    );
22850}
22851
22852pub trait CollaborationHub {
22853    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22854    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22855    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22856}
22857
22858impl CollaborationHub for Entity<Project> {
22859    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22860        self.read(cx).collaborators()
22861    }
22862
22863    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22864        self.read(cx).user_store().read(cx).participant_indices()
22865    }
22866
22867    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22868        let this = self.read(cx);
22869        let user_ids = this.collaborators().values().map(|c| c.user_id);
22870        this.user_store().read(cx).participant_names(user_ids, cx)
22871    }
22872}
22873
22874pub trait SemanticsProvider {
22875    fn hover(
22876        &self,
22877        buffer: &Entity<Buffer>,
22878        position: text::Anchor,
22879        cx: &mut App,
22880    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22881
22882    fn inline_values(
22883        &self,
22884        buffer_handle: Entity<Buffer>,
22885        range: Range<text::Anchor>,
22886        cx: &mut App,
22887    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22888
22889    fn inlay_hints(
22890        &self,
22891        buffer_handle: Entity<Buffer>,
22892        range: Range<text::Anchor>,
22893        cx: &mut App,
22894    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22895
22896    fn resolve_inlay_hint(
22897        &self,
22898        hint: InlayHint,
22899        buffer_handle: Entity<Buffer>,
22900        server_id: LanguageServerId,
22901        cx: &mut App,
22902    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22903
22904    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22905
22906    fn document_highlights(
22907        &self,
22908        buffer: &Entity<Buffer>,
22909        position: text::Anchor,
22910        cx: &mut App,
22911    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22912
22913    fn definitions(
22914        &self,
22915        buffer: &Entity<Buffer>,
22916        position: text::Anchor,
22917        kind: GotoDefinitionKind,
22918        cx: &mut App,
22919    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22920
22921    fn range_for_rename(
22922        &self,
22923        buffer: &Entity<Buffer>,
22924        position: text::Anchor,
22925        cx: &mut App,
22926    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22927
22928    fn perform_rename(
22929        &self,
22930        buffer: &Entity<Buffer>,
22931        position: text::Anchor,
22932        new_name: String,
22933        cx: &mut App,
22934    ) -> Option<Task<Result<ProjectTransaction>>>;
22935}
22936
22937pub trait CompletionProvider {
22938    fn completions(
22939        &self,
22940        excerpt_id: ExcerptId,
22941        buffer: &Entity<Buffer>,
22942        buffer_position: text::Anchor,
22943        trigger: CompletionContext,
22944        window: &mut Window,
22945        cx: &mut Context<Editor>,
22946    ) -> Task<Result<Vec<CompletionResponse>>>;
22947
22948    fn resolve_completions(
22949        &self,
22950        _buffer: Entity<Buffer>,
22951        _completion_indices: Vec<usize>,
22952        _completions: Rc<RefCell<Box<[Completion]>>>,
22953        _cx: &mut Context<Editor>,
22954    ) -> Task<Result<bool>> {
22955        Task::ready(Ok(false))
22956    }
22957
22958    fn apply_additional_edits_for_completion(
22959        &self,
22960        _buffer: Entity<Buffer>,
22961        _completions: Rc<RefCell<Box<[Completion]>>>,
22962        _completion_index: usize,
22963        _push_to_history: bool,
22964        _cx: &mut Context<Editor>,
22965    ) -> Task<Result<Option<language::Transaction>>> {
22966        Task::ready(Ok(None))
22967    }
22968
22969    fn is_completion_trigger(
22970        &self,
22971        buffer: &Entity<Buffer>,
22972        position: language::Anchor,
22973        text: &str,
22974        trigger_in_words: bool,
22975        menu_is_open: bool,
22976        cx: &mut Context<Editor>,
22977    ) -> bool;
22978
22979    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22980
22981    fn sort_completions(&self) -> bool {
22982        true
22983    }
22984
22985    fn filter_completions(&self) -> bool {
22986        true
22987    }
22988}
22989
22990pub trait CodeActionProvider {
22991    fn id(&self) -> Arc<str>;
22992
22993    fn code_actions(
22994        &self,
22995        buffer: &Entity<Buffer>,
22996        range: Range<text::Anchor>,
22997        window: &mut Window,
22998        cx: &mut App,
22999    ) -> Task<Result<Vec<CodeAction>>>;
23000
23001    fn apply_code_action(
23002        &self,
23003        buffer_handle: Entity<Buffer>,
23004        action: CodeAction,
23005        excerpt_id: ExcerptId,
23006        push_to_history: bool,
23007        window: &mut Window,
23008        cx: &mut App,
23009    ) -> Task<Result<ProjectTransaction>>;
23010}
23011
23012impl CodeActionProvider for Entity<Project> {
23013    fn id(&self) -> Arc<str> {
23014        "project".into()
23015    }
23016
23017    fn code_actions(
23018        &self,
23019        buffer: &Entity<Buffer>,
23020        range: Range<text::Anchor>,
23021        _window: &mut Window,
23022        cx: &mut App,
23023    ) -> Task<Result<Vec<CodeAction>>> {
23024        self.update(cx, |project, cx| {
23025            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23026            let code_actions = project.code_actions(buffer, range, None, cx);
23027            cx.background_spawn(async move {
23028                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23029                Ok(code_lens_actions
23030                    .context("code lens fetch")?
23031                    .into_iter()
23032                    .flatten()
23033                    .chain(
23034                        code_actions
23035                            .context("code action fetch")?
23036                            .into_iter()
23037                            .flatten(),
23038                    )
23039                    .collect())
23040            })
23041        })
23042    }
23043
23044    fn apply_code_action(
23045        &self,
23046        buffer_handle: Entity<Buffer>,
23047        action: CodeAction,
23048        _excerpt_id: ExcerptId,
23049        push_to_history: bool,
23050        _window: &mut Window,
23051        cx: &mut App,
23052    ) -> Task<Result<ProjectTransaction>> {
23053        self.update(cx, |project, cx| {
23054            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23055        })
23056    }
23057}
23058
23059fn snippet_completions(
23060    project: &Project,
23061    buffer: &Entity<Buffer>,
23062    buffer_position: text::Anchor,
23063    cx: &mut App,
23064) -> Task<Result<CompletionResponse>> {
23065    let languages = buffer.read(cx).languages_at(buffer_position);
23066    let snippet_store = project.snippets().read(cx);
23067
23068    let scopes: Vec<_> = languages
23069        .iter()
23070        .filter_map(|language| {
23071            let language_name = language.lsp_id();
23072            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23073
23074            if snippets.is_empty() {
23075                None
23076            } else {
23077                Some((language.default_scope(), snippets))
23078            }
23079        })
23080        .collect();
23081
23082    if scopes.is_empty() {
23083        return Task::ready(Ok(CompletionResponse {
23084            completions: vec![],
23085            display_options: CompletionDisplayOptions::default(),
23086            is_incomplete: false,
23087        }));
23088    }
23089
23090    let snapshot = buffer.read(cx).text_snapshot();
23091    let executor = cx.background_executor().clone();
23092
23093    cx.background_spawn(async move {
23094        let mut is_incomplete = false;
23095        let mut completions: Vec<Completion> = Vec::new();
23096        for (scope, snippets) in scopes.into_iter() {
23097            let classifier =
23098                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23099
23100            const MAX_WORD_PREFIX_LEN: usize = 128;
23101            let last_word: String = snapshot
23102                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23103                .take(MAX_WORD_PREFIX_LEN)
23104                .take_while(|c| classifier.is_word(*c))
23105                .collect::<String>()
23106                .chars()
23107                .rev()
23108                .collect();
23109
23110            if last_word.is_empty() {
23111                return Ok(CompletionResponse {
23112                    completions: vec![],
23113                    display_options: CompletionDisplayOptions::default(),
23114                    is_incomplete: true,
23115                });
23116            }
23117
23118            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23119            let to_lsp = |point: &text::Anchor| {
23120                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23121                point_to_lsp(end)
23122            };
23123            let lsp_end = to_lsp(&buffer_position);
23124
23125            let candidates = snippets
23126                .iter()
23127                .enumerate()
23128                .flat_map(|(ix, snippet)| {
23129                    snippet
23130                        .prefix
23131                        .iter()
23132                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23133                })
23134                .collect::<Vec<StringMatchCandidate>>();
23135
23136            const MAX_RESULTS: usize = 100;
23137            let mut matches = fuzzy::match_strings(
23138                &candidates,
23139                &last_word,
23140                last_word.chars().any(|c| c.is_uppercase()),
23141                true,
23142                MAX_RESULTS,
23143                &Default::default(),
23144                executor.clone(),
23145            )
23146            .await;
23147
23148            if matches.len() >= MAX_RESULTS {
23149                is_incomplete = true;
23150            }
23151
23152            // Remove all candidates where the query's start does not match the start of any word in the candidate
23153            if let Some(query_start) = last_word.chars().next() {
23154                matches.retain(|string_match| {
23155                    split_words(&string_match.string).any(|word| {
23156                        // Check that the first codepoint of the word as lowercase matches the first
23157                        // codepoint of the query as lowercase
23158                        word.chars()
23159                            .flat_map(|codepoint| codepoint.to_lowercase())
23160                            .zip(query_start.to_lowercase())
23161                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23162                    })
23163                });
23164            }
23165
23166            let matched_strings = matches
23167                .into_iter()
23168                .map(|m| m.string)
23169                .collect::<HashSet<_>>();
23170
23171            completions.extend(snippets.iter().filter_map(|snippet| {
23172                let matching_prefix = snippet
23173                    .prefix
23174                    .iter()
23175                    .find(|prefix| matched_strings.contains(*prefix))?;
23176                let start = as_offset - last_word.len();
23177                let start = snapshot.anchor_before(start);
23178                let range = start..buffer_position;
23179                let lsp_start = to_lsp(&start);
23180                let lsp_range = lsp::Range {
23181                    start: lsp_start,
23182                    end: lsp_end,
23183                };
23184                Some(Completion {
23185                    replace_range: range,
23186                    new_text: snippet.body.clone(),
23187                    source: CompletionSource::Lsp {
23188                        insert_range: None,
23189                        server_id: LanguageServerId(usize::MAX),
23190                        resolved: true,
23191                        lsp_completion: Box::new(lsp::CompletionItem {
23192                            label: snippet.prefix.first().unwrap().clone(),
23193                            kind: Some(CompletionItemKind::SNIPPET),
23194                            label_details: snippet.description.as_ref().map(|description| {
23195                                lsp::CompletionItemLabelDetails {
23196                                    detail: Some(description.clone()),
23197                                    description: None,
23198                                }
23199                            }),
23200                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23201                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23202                                lsp::InsertReplaceEdit {
23203                                    new_text: snippet.body.clone(),
23204                                    insert: lsp_range,
23205                                    replace: lsp_range,
23206                                },
23207                            )),
23208                            filter_text: Some(snippet.body.clone()),
23209                            sort_text: Some(char::MAX.to_string()),
23210                            ..lsp::CompletionItem::default()
23211                        }),
23212                        lsp_defaults: None,
23213                    },
23214                    label: CodeLabel::plain(matching_prefix.clone(), None),
23215                    icon_path: None,
23216                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23217                        single_line: snippet.name.clone().into(),
23218                        plain_text: snippet
23219                            .description
23220                            .clone()
23221                            .map(|description| description.into()),
23222                    }),
23223                    insert_text_mode: None,
23224                    confirm: None,
23225                })
23226            }))
23227        }
23228
23229        Ok(CompletionResponse {
23230            completions,
23231            display_options: CompletionDisplayOptions::default(),
23232            is_incomplete,
23233        })
23234    })
23235}
23236
23237impl CompletionProvider for Entity<Project> {
23238    fn completions(
23239        &self,
23240        _excerpt_id: ExcerptId,
23241        buffer: &Entity<Buffer>,
23242        buffer_position: text::Anchor,
23243        options: CompletionContext,
23244        _window: &mut Window,
23245        cx: &mut Context<Editor>,
23246    ) -> Task<Result<Vec<CompletionResponse>>> {
23247        self.update(cx, |project, cx| {
23248            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23249            let project_completions = project.completions(buffer, buffer_position, options, cx);
23250            cx.background_spawn(async move {
23251                let mut responses = project_completions.await?;
23252                let snippets = snippets.await?;
23253                if !snippets.completions.is_empty() {
23254                    responses.push(snippets);
23255                }
23256                Ok(responses)
23257            })
23258        })
23259    }
23260
23261    fn resolve_completions(
23262        &self,
23263        buffer: Entity<Buffer>,
23264        completion_indices: Vec<usize>,
23265        completions: Rc<RefCell<Box<[Completion]>>>,
23266        cx: &mut Context<Editor>,
23267    ) -> Task<Result<bool>> {
23268        self.update(cx, |project, cx| {
23269            project.lsp_store().update(cx, |lsp_store, cx| {
23270                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23271            })
23272        })
23273    }
23274
23275    fn apply_additional_edits_for_completion(
23276        &self,
23277        buffer: Entity<Buffer>,
23278        completions: Rc<RefCell<Box<[Completion]>>>,
23279        completion_index: usize,
23280        push_to_history: bool,
23281        cx: &mut Context<Editor>,
23282    ) -> Task<Result<Option<language::Transaction>>> {
23283        self.update(cx, |project, cx| {
23284            project.lsp_store().update(cx, |lsp_store, cx| {
23285                lsp_store.apply_additional_edits_for_completion(
23286                    buffer,
23287                    completions,
23288                    completion_index,
23289                    push_to_history,
23290                    cx,
23291                )
23292            })
23293        })
23294    }
23295
23296    fn is_completion_trigger(
23297        &self,
23298        buffer: &Entity<Buffer>,
23299        position: language::Anchor,
23300        text: &str,
23301        trigger_in_words: bool,
23302        menu_is_open: bool,
23303        cx: &mut Context<Editor>,
23304    ) -> bool {
23305        let mut chars = text.chars();
23306        let char = if let Some(char) = chars.next() {
23307            char
23308        } else {
23309            return false;
23310        };
23311        if chars.next().is_some() {
23312            return false;
23313        }
23314
23315        let buffer = buffer.read(cx);
23316        let snapshot = buffer.snapshot();
23317        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23318            return false;
23319        }
23320        let classifier = snapshot
23321            .char_classifier_at(position)
23322            .scope_context(Some(CharScopeContext::Completion));
23323        if trigger_in_words && classifier.is_word(char) {
23324            return true;
23325        }
23326
23327        buffer.completion_triggers().contains(text)
23328    }
23329}
23330
23331impl SemanticsProvider for Entity<Project> {
23332    fn hover(
23333        &self,
23334        buffer: &Entity<Buffer>,
23335        position: text::Anchor,
23336        cx: &mut App,
23337    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23338        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23339    }
23340
23341    fn document_highlights(
23342        &self,
23343        buffer: &Entity<Buffer>,
23344        position: text::Anchor,
23345        cx: &mut App,
23346    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23347        Some(self.update(cx, |project, cx| {
23348            project.document_highlights(buffer, position, cx)
23349        }))
23350    }
23351
23352    fn definitions(
23353        &self,
23354        buffer: &Entity<Buffer>,
23355        position: text::Anchor,
23356        kind: GotoDefinitionKind,
23357        cx: &mut App,
23358    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23359        Some(self.update(cx, |project, cx| match kind {
23360            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23361            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23362            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23363            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23364        }))
23365    }
23366
23367    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23368        self.update(cx, |project, cx| {
23369            if project
23370                .active_debug_session(cx)
23371                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23372            {
23373                return true;
23374            }
23375
23376            buffer.update(cx, |buffer, cx| {
23377                project.any_language_server_supports_inlay_hints(buffer, cx)
23378            })
23379        })
23380    }
23381
23382    fn inline_values(
23383        &self,
23384        buffer_handle: Entity<Buffer>,
23385        range: Range<text::Anchor>,
23386        cx: &mut App,
23387    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23388        self.update(cx, |project, cx| {
23389            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23390
23391            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23392        })
23393    }
23394
23395    fn inlay_hints(
23396        &self,
23397        buffer_handle: Entity<Buffer>,
23398        range: Range<text::Anchor>,
23399        cx: &mut App,
23400    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23401        Some(self.update(cx, |project, cx| {
23402            project.inlay_hints(buffer_handle, range, cx)
23403        }))
23404    }
23405
23406    fn resolve_inlay_hint(
23407        &self,
23408        hint: InlayHint,
23409        buffer_handle: Entity<Buffer>,
23410        server_id: LanguageServerId,
23411        cx: &mut App,
23412    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23413        Some(self.update(cx, |project, cx| {
23414            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23415        }))
23416    }
23417
23418    fn range_for_rename(
23419        &self,
23420        buffer: &Entity<Buffer>,
23421        position: text::Anchor,
23422        cx: &mut App,
23423    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23424        Some(self.update(cx, |project, cx| {
23425            let buffer = buffer.clone();
23426            let task = project.prepare_rename(buffer.clone(), position, cx);
23427            cx.spawn(async move |_, cx| {
23428                Ok(match task.await? {
23429                    PrepareRenameResponse::Success(range) => Some(range),
23430                    PrepareRenameResponse::InvalidPosition => None,
23431                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23432                        // Fallback on using TreeSitter info to determine identifier range
23433                        buffer.read_with(cx, |buffer, _| {
23434                            let snapshot = buffer.snapshot();
23435                            let (range, kind) = snapshot.surrounding_word(position, None);
23436                            if kind != Some(CharKind::Word) {
23437                                return None;
23438                            }
23439                            Some(
23440                                snapshot.anchor_before(range.start)
23441                                    ..snapshot.anchor_after(range.end),
23442                            )
23443                        })?
23444                    }
23445                })
23446            })
23447        }))
23448    }
23449
23450    fn perform_rename(
23451        &self,
23452        buffer: &Entity<Buffer>,
23453        position: text::Anchor,
23454        new_name: String,
23455        cx: &mut App,
23456    ) -> Option<Task<Result<ProjectTransaction>>> {
23457        Some(self.update(cx, |project, cx| {
23458            project.perform_rename(buffer.clone(), position, new_name, cx)
23459        }))
23460    }
23461}
23462
23463fn inlay_hint_settings(
23464    location: Anchor,
23465    snapshot: &MultiBufferSnapshot,
23466    cx: &mut Context<Editor>,
23467) -> InlayHintSettings {
23468    let file = snapshot.file_at(location);
23469    let language = snapshot.language_at(location).map(|l| l.name());
23470    language_settings(language, file, cx).inlay_hints
23471}
23472
23473fn consume_contiguous_rows(
23474    contiguous_row_selections: &mut Vec<Selection<Point>>,
23475    selection: &Selection<Point>,
23476    display_map: &DisplaySnapshot,
23477    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23478) -> (MultiBufferRow, MultiBufferRow) {
23479    contiguous_row_selections.push(selection.clone());
23480    let start_row = starting_row(selection, display_map);
23481    let mut end_row = ending_row(selection, display_map);
23482
23483    while let Some(next_selection) = selections.peek() {
23484        if next_selection.start.row <= end_row.0 {
23485            end_row = ending_row(next_selection, display_map);
23486            contiguous_row_selections.push(selections.next().unwrap().clone());
23487        } else {
23488            break;
23489        }
23490    }
23491    (start_row, end_row)
23492}
23493
23494fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23495    if selection.start.column > 0 {
23496        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23497    } else {
23498        MultiBufferRow(selection.start.row)
23499    }
23500}
23501
23502fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23503    if next_selection.end.column > 0 || next_selection.is_empty() {
23504        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23505    } else {
23506        MultiBufferRow(next_selection.end.row)
23507    }
23508}
23509
23510impl EditorSnapshot {
23511    pub fn remote_selections_in_range<'a>(
23512        &'a self,
23513        range: &'a Range<Anchor>,
23514        collaboration_hub: &dyn CollaborationHub,
23515        cx: &'a App,
23516    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23517        let participant_names = collaboration_hub.user_names(cx);
23518        let participant_indices = collaboration_hub.user_participant_indices(cx);
23519        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23520        let collaborators_by_replica_id = collaborators_by_peer_id
23521            .values()
23522            .map(|collaborator| (collaborator.replica_id, collaborator))
23523            .collect::<HashMap<_, _>>();
23524        self.buffer_snapshot()
23525            .selections_in_range(range, false)
23526            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23527                if replica_id == ReplicaId::AGENT {
23528                    Some(RemoteSelection {
23529                        replica_id,
23530                        selection,
23531                        cursor_shape,
23532                        line_mode,
23533                        collaborator_id: CollaboratorId::Agent,
23534                        user_name: Some("Agent".into()),
23535                        color: cx.theme().players().agent(),
23536                    })
23537                } else {
23538                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23539                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23540                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23541                    Some(RemoteSelection {
23542                        replica_id,
23543                        selection,
23544                        cursor_shape,
23545                        line_mode,
23546                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23547                        user_name,
23548                        color: if let Some(index) = participant_index {
23549                            cx.theme().players().color_for_participant(index.0)
23550                        } else {
23551                            cx.theme().players().absent()
23552                        },
23553                    })
23554                }
23555            })
23556    }
23557
23558    pub fn hunks_for_ranges(
23559        &self,
23560        ranges: impl IntoIterator<Item = Range<Point>>,
23561    ) -> Vec<MultiBufferDiffHunk> {
23562        let mut hunks = Vec::new();
23563        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23564            HashMap::default();
23565        for query_range in ranges {
23566            let query_rows =
23567                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23568            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23569                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23570            ) {
23571                // Include deleted hunks that are adjacent to the query range, because
23572                // otherwise they would be missed.
23573                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23574                if hunk.status().is_deleted() {
23575                    intersects_range |= hunk.row_range.start == query_rows.end;
23576                    intersects_range |= hunk.row_range.end == query_rows.start;
23577                }
23578                if intersects_range {
23579                    if !processed_buffer_rows
23580                        .entry(hunk.buffer_id)
23581                        .or_default()
23582                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23583                    {
23584                        continue;
23585                    }
23586                    hunks.push(hunk);
23587                }
23588            }
23589        }
23590
23591        hunks
23592    }
23593
23594    fn display_diff_hunks_for_rows<'a>(
23595        &'a self,
23596        display_rows: Range<DisplayRow>,
23597        folded_buffers: &'a HashSet<BufferId>,
23598    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23599        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23600        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23601
23602        self.buffer_snapshot()
23603            .diff_hunks_in_range(buffer_start..buffer_end)
23604            .filter_map(|hunk| {
23605                if folded_buffers.contains(&hunk.buffer_id) {
23606                    return None;
23607                }
23608
23609                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23610                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23611
23612                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23613                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23614
23615                let display_hunk = if hunk_display_start.column() != 0 {
23616                    DisplayDiffHunk::Folded {
23617                        display_row: hunk_display_start.row(),
23618                    }
23619                } else {
23620                    let mut end_row = hunk_display_end.row();
23621                    if hunk_display_end.column() > 0 {
23622                        end_row.0 += 1;
23623                    }
23624                    let is_created_file = hunk.is_created_file();
23625                    DisplayDiffHunk::Unfolded {
23626                        status: hunk.status(),
23627                        diff_base_byte_range: hunk.diff_base_byte_range,
23628                        display_row_range: hunk_display_start.row()..end_row,
23629                        multi_buffer_range: Anchor::range_in_buffer(
23630                            hunk.excerpt_id,
23631                            hunk.buffer_id,
23632                            hunk.buffer_range,
23633                        ),
23634                        is_created_file,
23635                    }
23636                };
23637
23638                Some(display_hunk)
23639            })
23640    }
23641
23642    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23643        self.display_snapshot
23644            .buffer_snapshot()
23645            .language_at(position)
23646    }
23647
23648    pub fn is_focused(&self) -> bool {
23649        self.is_focused
23650    }
23651
23652    pub fn placeholder_text(&self) -> Option<String> {
23653        self.placeholder_display_snapshot
23654            .as_ref()
23655            .map(|display_map| display_map.text())
23656    }
23657
23658    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23659        self.scroll_anchor.scroll_position(&self.display_snapshot)
23660    }
23661
23662    fn gutter_dimensions(
23663        &self,
23664        font_id: FontId,
23665        font_size: Pixels,
23666        max_line_number_width: Pixels,
23667        cx: &App,
23668    ) -> Option<GutterDimensions> {
23669        if !self.show_gutter {
23670            return None;
23671        }
23672
23673        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23674        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23675
23676        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23677            matches!(
23678                ProjectSettings::get_global(cx).git.git_gutter,
23679                GitGutterSetting::TrackedFiles
23680            )
23681        });
23682        let gutter_settings = EditorSettings::get_global(cx).gutter;
23683        let show_line_numbers = self
23684            .show_line_numbers
23685            .unwrap_or(gutter_settings.line_numbers);
23686        let line_gutter_width = if show_line_numbers {
23687            // Avoid flicker-like gutter resizes when the line number gains another digit by
23688            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23689            let min_width_for_number_on_gutter =
23690                ch_advance * gutter_settings.min_line_number_digits as f32;
23691            max_line_number_width.max(min_width_for_number_on_gutter)
23692        } else {
23693            0.0.into()
23694        };
23695
23696        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23697        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23698
23699        let git_blame_entries_width =
23700            self.git_blame_gutter_max_author_length
23701                .map(|max_author_length| {
23702                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23703                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23704
23705                    /// The number of characters to dedicate to gaps and margins.
23706                    const SPACING_WIDTH: usize = 4;
23707
23708                    let max_char_count = max_author_length.min(renderer.max_author_length())
23709                        + ::git::SHORT_SHA_LENGTH
23710                        + MAX_RELATIVE_TIMESTAMP.len()
23711                        + SPACING_WIDTH;
23712
23713                    ch_advance * max_char_count
23714                });
23715
23716        let is_singleton = self.buffer_snapshot().is_singleton();
23717
23718        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23719        left_padding += if !is_singleton {
23720            ch_width * 4.0
23721        } else if show_runnables || show_breakpoints {
23722            ch_width * 3.0
23723        } else if show_git_gutter && show_line_numbers {
23724            ch_width * 2.0
23725        } else if show_git_gutter || show_line_numbers {
23726            ch_width
23727        } else {
23728            px(0.)
23729        };
23730
23731        let shows_folds = is_singleton && gutter_settings.folds;
23732
23733        let right_padding = if shows_folds && show_line_numbers {
23734            ch_width * 4.0
23735        } else if shows_folds || (!is_singleton && show_line_numbers) {
23736            ch_width * 3.0
23737        } else if show_line_numbers {
23738            ch_width
23739        } else {
23740            px(0.)
23741        };
23742
23743        Some(GutterDimensions {
23744            left_padding,
23745            right_padding,
23746            width: line_gutter_width + left_padding + right_padding,
23747            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23748            git_blame_entries_width,
23749        })
23750    }
23751
23752    pub fn render_crease_toggle(
23753        &self,
23754        buffer_row: MultiBufferRow,
23755        row_contains_cursor: bool,
23756        editor: Entity<Editor>,
23757        window: &mut Window,
23758        cx: &mut App,
23759    ) -> Option<AnyElement> {
23760        let folded = self.is_line_folded(buffer_row);
23761        let mut is_foldable = false;
23762
23763        if let Some(crease) = self
23764            .crease_snapshot
23765            .query_row(buffer_row, self.buffer_snapshot())
23766        {
23767            is_foldable = true;
23768            match crease {
23769                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23770                    if let Some(render_toggle) = render_toggle {
23771                        let toggle_callback =
23772                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23773                                if folded {
23774                                    editor.update(cx, |editor, cx| {
23775                                        editor.fold_at(buffer_row, window, cx)
23776                                    });
23777                                } else {
23778                                    editor.update(cx, |editor, cx| {
23779                                        editor.unfold_at(buffer_row, window, cx)
23780                                    });
23781                                }
23782                            });
23783                        return Some((render_toggle)(
23784                            buffer_row,
23785                            folded,
23786                            toggle_callback,
23787                            window,
23788                            cx,
23789                        ));
23790                    }
23791                }
23792            }
23793        }
23794
23795        is_foldable |= self.starts_indent(buffer_row);
23796
23797        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23798            Some(
23799                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23800                    .toggle_state(folded)
23801                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23802                        if folded {
23803                            this.unfold_at(buffer_row, window, cx);
23804                        } else {
23805                            this.fold_at(buffer_row, window, cx);
23806                        }
23807                    }))
23808                    .into_any_element(),
23809            )
23810        } else {
23811            None
23812        }
23813    }
23814
23815    pub fn render_crease_trailer(
23816        &self,
23817        buffer_row: MultiBufferRow,
23818        window: &mut Window,
23819        cx: &mut App,
23820    ) -> Option<AnyElement> {
23821        let folded = self.is_line_folded(buffer_row);
23822        if let Crease::Inline { render_trailer, .. } = self
23823            .crease_snapshot
23824            .query_row(buffer_row, self.buffer_snapshot())?
23825        {
23826            let render_trailer = render_trailer.as_ref()?;
23827            Some(render_trailer(buffer_row, folded, window, cx))
23828        } else {
23829            None
23830        }
23831    }
23832}
23833
23834impl Deref for EditorSnapshot {
23835    type Target = DisplaySnapshot;
23836
23837    fn deref(&self) -> &Self::Target {
23838        &self.display_snapshot
23839    }
23840}
23841
23842#[derive(Clone, Debug, PartialEq, Eq)]
23843pub enum EditorEvent {
23844    InputIgnored {
23845        text: Arc<str>,
23846    },
23847    InputHandled {
23848        utf16_range_to_replace: Option<Range<isize>>,
23849        text: Arc<str>,
23850    },
23851    ExcerptsAdded {
23852        buffer: Entity<Buffer>,
23853        predecessor: ExcerptId,
23854        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23855    },
23856    ExcerptsRemoved {
23857        ids: Vec<ExcerptId>,
23858        removed_buffer_ids: Vec<BufferId>,
23859    },
23860    BufferFoldToggled {
23861        ids: Vec<ExcerptId>,
23862        folded: bool,
23863    },
23864    ExcerptsEdited {
23865        ids: Vec<ExcerptId>,
23866    },
23867    ExcerptsExpanded {
23868        ids: Vec<ExcerptId>,
23869    },
23870    BufferEdited,
23871    Edited {
23872        transaction_id: clock::Lamport,
23873    },
23874    Reparsed(BufferId),
23875    Focused,
23876    FocusedIn,
23877    Blurred,
23878    DirtyChanged,
23879    Saved,
23880    TitleChanged,
23881    SelectionsChanged {
23882        local: bool,
23883    },
23884    ScrollPositionChanged {
23885        local: bool,
23886        autoscroll: bool,
23887    },
23888    TransactionUndone {
23889        transaction_id: clock::Lamport,
23890    },
23891    TransactionBegun {
23892        transaction_id: clock::Lamport,
23893    },
23894    CursorShapeChanged,
23895    BreadcrumbsChanged,
23896    PushedToNavHistory {
23897        anchor: Anchor,
23898        is_deactivate: bool,
23899    },
23900}
23901
23902impl EventEmitter<EditorEvent> for Editor {}
23903
23904impl Focusable for Editor {
23905    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23906        self.focus_handle.clone()
23907    }
23908}
23909
23910impl Render for Editor {
23911    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23912        let settings = ThemeSettings::get_global(cx);
23913
23914        let mut text_style = match self.mode {
23915            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23916                color: cx.theme().colors().editor_foreground,
23917                font_family: settings.ui_font.family.clone(),
23918                font_features: settings.ui_font.features.clone(),
23919                font_fallbacks: settings.ui_font.fallbacks.clone(),
23920                font_size: rems(0.875).into(),
23921                font_weight: settings.ui_font.weight,
23922                line_height: relative(settings.buffer_line_height.value()),
23923                ..Default::default()
23924            },
23925            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23926                color: cx.theme().colors().editor_foreground,
23927                font_family: settings.buffer_font.family.clone(),
23928                font_features: settings.buffer_font.features.clone(),
23929                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23930                font_size: settings.buffer_font_size(cx).into(),
23931                font_weight: settings.buffer_font.weight,
23932                line_height: relative(settings.buffer_line_height.value()),
23933                ..Default::default()
23934            },
23935        };
23936        if let Some(text_style_refinement) = &self.text_style_refinement {
23937            text_style.refine(text_style_refinement)
23938        }
23939
23940        let background = match self.mode {
23941            EditorMode::SingleLine => cx.theme().system().transparent,
23942            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23943            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23944            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23945        };
23946
23947        EditorElement::new(
23948            &cx.entity(),
23949            EditorStyle {
23950                background,
23951                border: cx.theme().colors().border,
23952                local_player: cx.theme().players().local(),
23953                text: text_style,
23954                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23955                syntax: cx.theme().syntax().clone(),
23956                status: cx.theme().status().clone(),
23957                inlay_hints_style: make_inlay_hints_style(cx),
23958                edit_prediction_styles: make_suggestion_styles(cx),
23959                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23960                show_underlines: self.diagnostics_enabled(),
23961            },
23962        )
23963    }
23964}
23965
23966impl EntityInputHandler for Editor {
23967    fn text_for_range(
23968        &mut self,
23969        range_utf16: Range<usize>,
23970        adjusted_range: &mut Option<Range<usize>>,
23971        _: &mut Window,
23972        cx: &mut Context<Self>,
23973    ) -> Option<String> {
23974        let snapshot = self.buffer.read(cx).read(cx);
23975        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23976        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23977        if (start.0..end.0) != range_utf16 {
23978            adjusted_range.replace(start.0..end.0);
23979        }
23980        Some(snapshot.text_for_range(start..end).collect())
23981    }
23982
23983    fn selected_text_range(
23984        &mut self,
23985        ignore_disabled_input: bool,
23986        _: &mut Window,
23987        cx: &mut Context<Self>,
23988    ) -> Option<UTF16Selection> {
23989        // Prevent the IME menu from appearing when holding down an alphabetic key
23990        // while input is disabled.
23991        if !ignore_disabled_input && !self.input_enabled {
23992            return None;
23993        }
23994
23995        let selection = self
23996            .selections
23997            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23998        let range = selection.range();
23999
24000        Some(UTF16Selection {
24001            range: range.start.0..range.end.0,
24002            reversed: selection.reversed,
24003        })
24004    }
24005
24006    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24007        let snapshot = self.buffer.read(cx).read(cx);
24008        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24009        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24010    }
24011
24012    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24013        self.clear_highlights::<InputComposition>(cx);
24014        self.ime_transaction.take();
24015    }
24016
24017    fn replace_text_in_range(
24018        &mut self,
24019        range_utf16: Option<Range<usize>>,
24020        text: &str,
24021        window: &mut Window,
24022        cx: &mut Context<Self>,
24023    ) {
24024        if !self.input_enabled {
24025            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24026            return;
24027        }
24028
24029        self.transact(window, cx, |this, window, cx| {
24030            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24031                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24032                Some(this.selection_replacement_ranges(range_utf16, cx))
24033            } else {
24034                this.marked_text_ranges(cx)
24035            };
24036
24037            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24038                let newest_selection_id = this.selections.newest_anchor().id;
24039                this.selections
24040                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24041                    .iter()
24042                    .zip(ranges_to_replace.iter())
24043                    .find_map(|(selection, range)| {
24044                        if selection.id == newest_selection_id {
24045                            Some(
24046                                (range.start.0 as isize - selection.head().0 as isize)
24047                                    ..(range.end.0 as isize - selection.head().0 as isize),
24048                            )
24049                        } else {
24050                            None
24051                        }
24052                    })
24053            });
24054
24055            cx.emit(EditorEvent::InputHandled {
24056                utf16_range_to_replace: range_to_replace,
24057                text: text.into(),
24058            });
24059
24060            if let Some(new_selected_ranges) = new_selected_ranges {
24061                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24062                    selections.select_ranges(new_selected_ranges)
24063                });
24064                this.backspace(&Default::default(), window, cx);
24065            }
24066
24067            this.handle_input(text, window, cx);
24068        });
24069
24070        if let Some(transaction) = self.ime_transaction {
24071            self.buffer.update(cx, |buffer, cx| {
24072                buffer.group_until_transaction(transaction, cx);
24073            });
24074        }
24075
24076        self.unmark_text(window, cx);
24077    }
24078
24079    fn replace_and_mark_text_in_range(
24080        &mut self,
24081        range_utf16: Option<Range<usize>>,
24082        text: &str,
24083        new_selected_range_utf16: Option<Range<usize>>,
24084        window: &mut Window,
24085        cx: &mut Context<Self>,
24086    ) {
24087        if !self.input_enabled {
24088            return;
24089        }
24090
24091        let transaction = self.transact(window, cx, |this, window, cx| {
24092            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24093                let snapshot = this.buffer.read(cx).read(cx);
24094                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24095                    for marked_range in &mut marked_ranges {
24096                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24097                        marked_range.start.0 += relative_range_utf16.start;
24098                        marked_range.start =
24099                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24100                        marked_range.end =
24101                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24102                    }
24103                }
24104                Some(marked_ranges)
24105            } else if let Some(range_utf16) = range_utf16 {
24106                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24107                Some(this.selection_replacement_ranges(range_utf16, cx))
24108            } else {
24109                None
24110            };
24111
24112            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24113                let newest_selection_id = this.selections.newest_anchor().id;
24114                this.selections
24115                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24116                    .iter()
24117                    .zip(ranges_to_replace.iter())
24118                    .find_map(|(selection, range)| {
24119                        if selection.id == newest_selection_id {
24120                            Some(
24121                                (range.start.0 as isize - selection.head().0 as isize)
24122                                    ..(range.end.0 as isize - selection.head().0 as isize),
24123                            )
24124                        } else {
24125                            None
24126                        }
24127                    })
24128            });
24129
24130            cx.emit(EditorEvent::InputHandled {
24131                utf16_range_to_replace: range_to_replace,
24132                text: text.into(),
24133            });
24134
24135            if let Some(ranges) = ranges_to_replace {
24136                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24137                    s.select_ranges(ranges)
24138                });
24139            }
24140
24141            let marked_ranges = {
24142                let snapshot = this.buffer.read(cx).read(cx);
24143                this.selections
24144                    .disjoint_anchors_arc()
24145                    .iter()
24146                    .map(|selection| {
24147                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24148                    })
24149                    .collect::<Vec<_>>()
24150            };
24151
24152            if text.is_empty() {
24153                this.unmark_text(window, cx);
24154            } else {
24155                this.highlight_text::<InputComposition>(
24156                    marked_ranges.clone(),
24157                    HighlightStyle {
24158                        underline: Some(UnderlineStyle {
24159                            thickness: px(1.),
24160                            color: None,
24161                            wavy: false,
24162                        }),
24163                        ..Default::default()
24164                    },
24165                    cx,
24166                );
24167            }
24168
24169            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24170            let use_autoclose = this.use_autoclose;
24171            let use_auto_surround = this.use_auto_surround;
24172            this.set_use_autoclose(false);
24173            this.set_use_auto_surround(false);
24174            this.handle_input(text, window, cx);
24175            this.set_use_autoclose(use_autoclose);
24176            this.set_use_auto_surround(use_auto_surround);
24177
24178            if let Some(new_selected_range) = new_selected_range_utf16 {
24179                let snapshot = this.buffer.read(cx).read(cx);
24180                let new_selected_ranges = marked_ranges
24181                    .into_iter()
24182                    .map(|marked_range| {
24183                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24184                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24185                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24186                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24187                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24188                    })
24189                    .collect::<Vec<_>>();
24190
24191                drop(snapshot);
24192                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24193                    selections.select_ranges(new_selected_ranges)
24194                });
24195            }
24196        });
24197
24198        self.ime_transaction = self.ime_transaction.or(transaction);
24199        if let Some(transaction) = self.ime_transaction {
24200            self.buffer.update(cx, |buffer, cx| {
24201                buffer.group_until_transaction(transaction, cx);
24202            });
24203        }
24204
24205        if self.text_highlights::<InputComposition>(cx).is_none() {
24206            self.ime_transaction.take();
24207        }
24208    }
24209
24210    fn bounds_for_range(
24211        &mut self,
24212        range_utf16: Range<usize>,
24213        element_bounds: gpui::Bounds<Pixels>,
24214        window: &mut Window,
24215        cx: &mut Context<Self>,
24216    ) -> Option<gpui::Bounds<Pixels>> {
24217        let text_layout_details = self.text_layout_details(window);
24218        let CharacterDimensions {
24219            em_width,
24220            em_advance,
24221            line_height,
24222        } = self.character_dimensions(window);
24223
24224        let snapshot = self.snapshot(window, cx);
24225        let scroll_position = snapshot.scroll_position();
24226        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24227
24228        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24229        let x = Pixels::from(
24230            ScrollOffset::from(
24231                snapshot.x_for_display_point(start, &text_layout_details)
24232                    + self.gutter_dimensions.full_width(),
24233            ) - scroll_left,
24234        );
24235        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24236
24237        Some(Bounds {
24238            origin: element_bounds.origin + point(x, y),
24239            size: size(em_width, line_height),
24240        })
24241    }
24242
24243    fn character_index_for_point(
24244        &mut self,
24245        point: gpui::Point<Pixels>,
24246        _window: &mut Window,
24247        _cx: &mut Context<Self>,
24248    ) -> Option<usize> {
24249        let position_map = self.last_position_map.as_ref()?;
24250        if !position_map.text_hitbox.contains(&point) {
24251            return None;
24252        }
24253        let display_point = position_map.point_for_position(point).previous_valid;
24254        let anchor = position_map
24255            .snapshot
24256            .display_point_to_anchor(display_point, Bias::Left);
24257        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24258        Some(utf16_offset.0)
24259    }
24260}
24261
24262trait SelectionExt {
24263    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24264    fn spanned_rows(
24265        &self,
24266        include_end_if_at_line_start: bool,
24267        map: &DisplaySnapshot,
24268    ) -> Range<MultiBufferRow>;
24269}
24270
24271impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24272    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24273        let start = self
24274            .start
24275            .to_point(map.buffer_snapshot())
24276            .to_display_point(map);
24277        let end = self
24278            .end
24279            .to_point(map.buffer_snapshot())
24280            .to_display_point(map);
24281        if self.reversed {
24282            end..start
24283        } else {
24284            start..end
24285        }
24286    }
24287
24288    fn spanned_rows(
24289        &self,
24290        include_end_if_at_line_start: bool,
24291        map: &DisplaySnapshot,
24292    ) -> Range<MultiBufferRow> {
24293        let start = self.start.to_point(map.buffer_snapshot());
24294        let mut end = self.end.to_point(map.buffer_snapshot());
24295        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24296            end.row -= 1;
24297        }
24298
24299        let buffer_start = map.prev_line_boundary(start).0;
24300        let buffer_end = map.next_line_boundary(end).0;
24301        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24302    }
24303}
24304
24305impl<T: InvalidationRegion> InvalidationStack<T> {
24306    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24307    where
24308        S: Clone + ToOffset,
24309    {
24310        while let Some(region) = self.last() {
24311            let all_selections_inside_invalidation_ranges =
24312                if selections.len() == region.ranges().len() {
24313                    selections
24314                        .iter()
24315                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24316                        .all(|(selection, invalidation_range)| {
24317                            let head = selection.head().to_offset(buffer);
24318                            invalidation_range.start <= head && invalidation_range.end >= head
24319                        })
24320                } else {
24321                    false
24322                };
24323
24324            if all_selections_inside_invalidation_ranges {
24325                break;
24326            } else {
24327                self.pop();
24328            }
24329        }
24330    }
24331}
24332
24333impl<T> Default for InvalidationStack<T> {
24334    fn default() -> Self {
24335        Self(Default::default())
24336    }
24337}
24338
24339impl<T> Deref for InvalidationStack<T> {
24340    type Target = Vec<T>;
24341
24342    fn deref(&self) -> &Self::Target {
24343        &self.0
24344    }
24345}
24346
24347impl<T> DerefMut for InvalidationStack<T> {
24348    fn deref_mut(&mut self) -> &mut Self::Target {
24349        &mut self.0
24350    }
24351}
24352
24353impl InvalidationRegion for SnippetState {
24354    fn ranges(&self) -> &[Range<Anchor>] {
24355        &self.ranges[self.active_index]
24356    }
24357}
24358
24359fn edit_prediction_edit_text(
24360    current_snapshot: &BufferSnapshot,
24361    edits: &[(Range<Anchor>, String)],
24362    edit_preview: &EditPreview,
24363    include_deletions: bool,
24364    cx: &App,
24365) -> HighlightedText {
24366    let edits = edits
24367        .iter()
24368        .map(|(anchor, text)| {
24369            (
24370                anchor.start.text_anchor..anchor.end.text_anchor,
24371                text.clone(),
24372            )
24373        })
24374        .collect::<Vec<_>>();
24375
24376    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24377}
24378
24379fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24380    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24381    // Just show the raw edit text with basic styling
24382    let mut text = String::new();
24383    let mut highlights = Vec::new();
24384
24385    let insertion_highlight_style = HighlightStyle {
24386        color: Some(cx.theme().colors().text),
24387        ..Default::default()
24388    };
24389
24390    for (_, edit_text) in edits {
24391        let start_offset = text.len();
24392        text.push_str(edit_text);
24393        let end_offset = text.len();
24394
24395        if start_offset < end_offset {
24396            highlights.push((start_offset..end_offset, insertion_highlight_style));
24397        }
24398    }
24399
24400    HighlightedText {
24401        text: text.into(),
24402        highlights,
24403    }
24404}
24405
24406pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24407    match severity {
24408        lsp::DiagnosticSeverity::ERROR => colors.error,
24409        lsp::DiagnosticSeverity::WARNING => colors.warning,
24410        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24411        lsp::DiagnosticSeverity::HINT => colors.info,
24412        _ => colors.ignored,
24413    }
24414}
24415
24416pub fn styled_runs_for_code_label<'a>(
24417    label: &'a CodeLabel,
24418    syntax_theme: &'a theme::SyntaxTheme,
24419) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24420    let fade_out = HighlightStyle {
24421        fade_out: Some(0.35),
24422        ..Default::default()
24423    };
24424
24425    let mut prev_end = label.filter_range.end;
24426    label
24427        .runs
24428        .iter()
24429        .enumerate()
24430        .flat_map(move |(ix, (range, highlight_id))| {
24431            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24432                style
24433            } else {
24434                return Default::default();
24435            };
24436            let muted_style = style.highlight(fade_out);
24437
24438            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24439            if range.start >= label.filter_range.end {
24440                if range.start > prev_end {
24441                    runs.push((prev_end..range.start, fade_out));
24442                }
24443                runs.push((range.clone(), muted_style));
24444            } else if range.end <= label.filter_range.end {
24445                runs.push((range.clone(), style));
24446            } else {
24447                runs.push((range.start..label.filter_range.end, style));
24448                runs.push((label.filter_range.end..range.end, muted_style));
24449            }
24450            prev_end = cmp::max(prev_end, range.end);
24451
24452            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24453                runs.push((prev_end..label.text.len(), fade_out));
24454            }
24455
24456            runs
24457        })
24458}
24459
24460pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24461    let mut prev_index = 0;
24462    let mut prev_codepoint: Option<char> = None;
24463    text.char_indices()
24464        .chain([(text.len(), '\0')])
24465        .filter_map(move |(index, codepoint)| {
24466            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24467            let is_boundary = index == text.len()
24468                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24469                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24470            if is_boundary {
24471                let chunk = &text[prev_index..index];
24472                prev_index = index;
24473                Some(chunk)
24474            } else {
24475                None
24476            }
24477        })
24478}
24479
24480pub trait RangeToAnchorExt: Sized {
24481    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24482
24483    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24484        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24485        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24486    }
24487}
24488
24489impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24490    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24491        let start_offset = self.start.to_offset(snapshot);
24492        let end_offset = self.end.to_offset(snapshot);
24493        if start_offset == end_offset {
24494            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24495        } else {
24496            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24497        }
24498    }
24499}
24500
24501pub trait RowExt {
24502    fn as_f64(&self) -> f64;
24503
24504    fn next_row(&self) -> Self;
24505
24506    fn previous_row(&self) -> Self;
24507
24508    fn minus(&self, other: Self) -> u32;
24509}
24510
24511impl RowExt for DisplayRow {
24512    fn as_f64(&self) -> f64 {
24513        self.0 as _
24514    }
24515
24516    fn next_row(&self) -> Self {
24517        Self(self.0 + 1)
24518    }
24519
24520    fn previous_row(&self) -> Self {
24521        Self(self.0.saturating_sub(1))
24522    }
24523
24524    fn minus(&self, other: Self) -> u32 {
24525        self.0 - other.0
24526    }
24527}
24528
24529impl RowExt for MultiBufferRow {
24530    fn as_f64(&self) -> f64 {
24531        self.0 as _
24532    }
24533
24534    fn next_row(&self) -> Self {
24535        Self(self.0 + 1)
24536    }
24537
24538    fn previous_row(&self) -> Self {
24539        Self(self.0.saturating_sub(1))
24540    }
24541
24542    fn minus(&self, other: Self) -> u32 {
24543        self.0 - other.0
24544    }
24545}
24546
24547trait RowRangeExt {
24548    type Row;
24549
24550    fn len(&self) -> usize;
24551
24552    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24553}
24554
24555impl RowRangeExt for Range<MultiBufferRow> {
24556    type Row = MultiBufferRow;
24557
24558    fn len(&self) -> usize {
24559        (self.end.0 - self.start.0) as usize
24560    }
24561
24562    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24563        (self.start.0..self.end.0).map(MultiBufferRow)
24564    }
24565}
24566
24567impl RowRangeExt for Range<DisplayRow> {
24568    type Row = DisplayRow;
24569
24570    fn len(&self) -> usize {
24571        (self.end.0 - self.start.0) as usize
24572    }
24573
24574    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24575        (self.start.0..self.end.0).map(DisplayRow)
24576    }
24577}
24578
24579/// If select range has more than one line, we
24580/// just point the cursor to range.start.
24581fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24582    if range.start.row == range.end.row {
24583        range
24584    } else {
24585        range.start..range.start
24586    }
24587}
24588pub struct KillRing(ClipboardItem);
24589impl Global for KillRing {}
24590
24591const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24592
24593enum BreakpointPromptEditAction {
24594    Log,
24595    Condition,
24596    HitCondition,
24597}
24598
24599struct BreakpointPromptEditor {
24600    pub(crate) prompt: Entity<Editor>,
24601    editor: WeakEntity<Editor>,
24602    breakpoint_anchor: Anchor,
24603    breakpoint: Breakpoint,
24604    edit_action: BreakpointPromptEditAction,
24605    block_ids: HashSet<CustomBlockId>,
24606    editor_margins: Arc<Mutex<EditorMargins>>,
24607    _subscriptions: Vec<Subscription>,
24608}
24609
24610impl BreakpointPromptEditor {
24611    const MAX_LINES: u8 = 4;
24612
24613    fn new(
24614        editor: WeakEntity<Editor>,
24615        breakpoint_anchor: Anchor,
24616        breakpoint: Breakpoint,
24617        edit_action: BreakpointPromptEditAction,
24618        window: &mut Window,
24619        cx: &mut Context<Self>,
24620    ) -> Self {
24621        let base_text = match edit_action {
24622            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24623            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24624            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24625        }
24626        .map(|msg| msg.to_string())
24627        .unwrap_or_default();
24628
24629        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24630        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24631
24632        let prompt = cx.new(|cx| {
24633            let mut prompt = Editor::new(
24634                EditorMode::AutoHeight {
24635                    min_lines: 1,
24636                    max_lines: Some(Self::MAX_LINES as usize),
24637                },
24638                buffer,
24639                None,
24640                window,
24641                cx,
24642            );
24643            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24644            prompt.set_show_cursor_when_unfocused(false, cx);
24645            prompt.set_placeholder_text(
24646                match edit_action {
24647                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24648                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24649                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24650                },
24651                window,
24652                cx,
24653            );
24654
24655            prompt
24656        });
24657
24658        Self {
24659            prompt,
24660            editor,
24661            breakpoint_anchor,
24662            breakpoint,
24663            edit_action,
24664            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24665            block_ids: Default::default(),
24666            _subscriptions: vec![],
24667        }
24668    }
24669
24670    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24671        self.block_ids.extend(block_ids)
24672    }
24673
24674    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24675        if let Some(editor) = self.editor.upgrade() {
24676            let message = self
24677                .prompt
24678                .read(cx)
24679                .buffer
24680                .read(cx)
24681                .as_singleton()
24682                .expect("A multi buffer in breakpoint prompt isn't possible")
24683                .read(cx)
24684                .as_rope()
24685                .to_string();
24686
24687            editor.update(cx, |editor, cx| {
24688                editor.edit_breakpoint_at_anchor(
24689                    self.breakpoint_anchor,
24690                    self.breakpoint.clone(),
24691                    match self.edit_action {
24692                        BreakpointPromptEditAction::Log => {
24693                            BreakpointEditAction::EditLogMessage(message.into())
24694                        }
24695                        BreakpointPromptEditAction::Condition => {
24696                            BreakpointEditAction::EditCondition(message.into())
24697                        }
24698                        BreakpointPromptEditAction::HitCondition => {
24699                            BreakpointEditAction::EditHitCondition(message.into())
24700                        }
24701                    },
24702                    cx,
24703                );
24704
24705                editor.remove_blocks(self.block_ids.clone(), None, cx);
24706                cx.focus_self(window);
24707            });
24708        }
24709    }
24710
24711    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24712        self.editor
24713            .update(cx, |editor, cx| {
24714                editor.remove_blocks(self.block_ids.clone(), None, cx);
24715                window.focus(&editor.focus_handle);
24716            })
24717            .log_err();
24718    }
24719
24720    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24721        let settings = ThemeSettings::get_global(cx);
24722        let text_style = TextStyle {
24723            color: if self.prompt.read(cx).read_only(cx) {
24724                cx.theme().colors().text_disabled
24725            } else {
24726                cx.theme().colors().text
24727            },
24728            font_family: settings.buffer_font.family.clone(),
24729            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24730            font_size: settings.buffer_font_size(cx).into(),
24731            font_weight: settings.buffer_font.weight,
24732            line_height: relative(settings.buffer_line_height.value()),
24733            ..Default::default()
24734        };
24735        EditorElement::new(
24736            &self.prompt,
24737            EditorStyle {
24738                background: cx.theme().colors().editor_background,
24739                local_player: cx.theme().players().local(),
24740                text: text_style,
24741                ..Default::default()
24742            },
24743        )
24744    }
24745}
24746
24747impl Render for BreakpointPromptEditor {
24748    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24749        let editor_margins = *self.editor_margins.lock();
24750        let gutter_dimensions = editor_margins.gutter;
24751        h_flex()
24752            .key_context("Editor")
24753            .bg(cx.theme().colors().editor_background)
24754            .border_y_1()
24755            .border_color(cx.theme().status().info_border)
24756            .size_full()
24757            .py(window.line_height() / 2.5)
24758            .on_action(cx.listener(Self::confirm))
24759            .on_action(cx.listener(Self::cancel))
24760            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24761            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24762    }
24763}
24764
24765impl Focusable for BreakpointPromptEditor {
24766    fn focus_handle(&self, cx: &App) -> FocusHandle {
24767        self.prompt.focus_handle(cx)
24768    }
24769}
24770
24771fn all_edits_insertions_or_deletions(
24772    edits: &Vec<(Range<Anchor>, String)>,
24773    snapshot: &MultiBufferSnapshot,
24774) -> bool {
24775    let mut all_insertions = true;
24776    let mut all_deletions = true;
24777
24778    for (range, new_text) in edits.iter() {
24779        let range_is_empty = range.to_offset(snapshot).is_empty();
24780        let text_is_empty = new_text.is_empty();
24781
24782        if range_is_empty != text_is_empty {
24783            if range_is_empty {
24784                all_deletions = false;
24785            } else {
24786                all_insertions = false;
24787            }
24788        } else {
24789            return false;
24790        }
24791
24792        if !all_insertions && !all_deletions {
24793            return false;
24794        }
24795    }
24796    all_insertions || all_deletions
24797}
24798
24799struct MissingEditPredictionKeybindingTooltip;
24800
24801impl Render for MissingEditPredictionKeybindingTooltip {
24802    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24803        ui::tooltip_container(cx, |container, cx| {
24804            container
24805                .flex_shrink_0()
24806                .max_w_80()
24807                .min_h(rems_from_px(124.))
24808                .justify_between()
24809                .child(
24810                    v_flex()
24811                        .flex_1()
24812                        .text_ui_sm(cx)
24813                        .child(Label::new("Conflict with Accept Keybinding"))
24814                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24815                )
24816                .child(
24817                    h_flex()
24818                        .pb_1()
24819                        .gap_1()
24820                        .items_end()
24821                        .w_full()
24822                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24823                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24824                        }))
24825                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24826                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24827                        })),
24828                )
24829        })
24830    }
24831}
24832
24833#[derive(Debug, Clone, Copy, PartialEq)]
24834pub struct LineHighlight {
24835    pub background: Background,
24836    pub border: Option<gpui::Hsla>,
24837    pub include_gutter: bool,
24838    pub type_id: Option<TypeId>,
24839}
24840
24841struct LineManipulationResult {
24842    pub new_text: String,
24843    pub line_count_before: usize,
24844    pub line_count_after: usize,
24845}
24846
24847fn render_diff_hunk_controls(
24848    row: u32,
24849    status: &DiffHunkStatus,
24850    hunk_range: Range<Anchor>,
24851    is_created_file: bool,
24852    line_height: Pixels,
24853    editor: &Entity<Editor>,
24854    _window: &mut Window,
24855    cx: &mut App,
24856) -> AnyElement {
24857    h_flex()
24858        .h(line_height)
24859        .mr_1()
24860        .gap_1()
24861        .px_0p5()
24862        .pb_1()
24863        .border_x_1()
24864        .border_b_1()
24865        .border_color(cx.theme().colors().border_variant)
24866        .rounded_b_lg()
24867        .bg(cx.theme().colors().editor_background)
24868        .gap_1()
24869        .block_mouse_except_scroll()
24870        .shadow_md()
24871        .child(if status.has_secondary_hunk() {
24872            Button::new(("stage", row as u64), "Stage")
24873                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24874                .tooltip({
24875                    let focus_handle = editor.focus_handle(cx);
24876                    move |window, cx| {
24877                        Tooltip::for_action_in(
24878                            "Stage Hunk",
24879                            &::git::ToggleStaged,
24880                            &focus_handle,
24881                            window,
24882                            cx,
24883                        )
24884                    }
24885                })
24886                .on_click({
24887                    let editor = editor.clone();
24888                    move |_event, _window, cx| {
24889                        editor.update(cx, |editor, cx| {
24890                            editor.stage_or_unstage_diff_hunks(
24891                                true,
24892                                vec![hunk_range.start..hunk_range.start],
24893                                cx,
24894                            );
24895                        });
24896                    }
24897                })
24898        } else {
24899            Button::new(("unstage", row as u64), "Unstage")
24900                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24901                .tooltip({
24902                    let focus_handle = editor.focus_handle(cx);
24903                    move |window, cx| {
24904                        Tooltip::for_action_in(
24905                            "Unstage Hunk",
24906                            &::git::ToggleStaged,
24907                            &focus_handle,
24908                            window,
24909                            cx,
24910                        )
24911                    }
24912                })
24913                .on_click({
24914                    let editor = editor.clone();
24915                    move |_event, _window, cx| {
24916                        editor.update(cx, |editor, cx| {
24917                            editor.stage_or_unstage_diff_hunks(
24918                                false,
24919                                vec![hunk_range.start..hunk_range.start],
24920                                cx,
24921                            );
24922                        });
24923                    }
24924                })
24925        })
24926        .child(
24927            Button::new(("restore", row as u64), "Restore")
24928                .tooltip({
24929                    let focus_handle = editor.focus_handle(cx);
24930                    move |window, cx| {
24931                        Tooltip::for_action_in(
24932                            "Restore Hunk",
24933                            &::git::Restore,
24934                            &focus_handle,
24935                            window,
24936                            cx,
24937                        )
24938                    }
24939                })
24940                .on_click({
24941                    let editor = editor.clone();
24942                    move |_event, window, cx| {
24943                        editor.update(cx, |editor, cx| {
24944                            let snapshot = editor.snapshot(window, cx);
24945                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24946                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24947                        });
24948                    }
24949                })
24950                .disabled(is_created_file),
24951        )
24952        .when(
24953            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24954            |el| {
24955                el.child(
24956                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24957                        .shape(IconButtonShape::Square)
24958                        .icon_size(IconSize::Small)
24959                        // .disabled(!has_multiple_hunks)
24960                        .tooltip({
24961                            let focus_handle = editor.focus_handle(cx);
24962                            move |window, cx| {
24963                                Tooltip::for_action_in(
24964                                    "Next Hunk",
24965                                    &GoToHunk,
24966                                    &focus_handle,
24967                                    window,
24968                                    cx,
24969                                )
24970                            }
24971                        })
24972                        .on_click({
24973                            let editor = editor.clone();
24974                            move |_event, window, cx| {
24975                                editor.update(cx, |editor, cx| {
24976                                    let snapshot = editor.snapshot(window, cx);
24977                                    let position =
24978                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24979                                    editor.go_to_hunk_before_or_after_position(
24980                                        &snapshot,
24981                                        position,
24982                                        Direction::Next,
24983                                        window,
24984                                        cx,
24985                                    );
24986                                    editor.expand_selected_diff_hunks(cx);
24987                                });
24988                            }
24989                        }),
24990                )
24991                .child(
24992                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24993                        .shape(IconButtonShape::Square)
24994                        .icon_size(IconSize::Small)
24995                        // .disabled(!has_multiple_hunks)
24996                        .tooltip({
24997                            let focus_handle = editor.focus_handle(cx);
24998                            move |window, cx| {
24999                                Tooltip::for_action_in(
25000                                    "Previous Hunk",
25001                                    &GoToPreviousHunk,
25002                                    &focus_handle,
25003                                    window,
25004                                    cx,
25005                                )
25006                            }
25007                        })
25008                        .on_click({
25009                            let editor = editor.clone();
25010                            move |_event, window, cx| {
25011                                editor.update(cx, |editor, cx| {
25012                                    let snapshot = editor.snapshot(window, cx);
25013                                    let point =
25014                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25015                                    editor.go_to_hunk_before_or_after_position(
25016                                        &snapshot,
25017                                        point,
25018                                        Direction::Prev,
25019                                        window,
25020                                        cx,
25021                                    );
25022                                    editor.expand_selected_diff_hunks(cx);
25023                                });
25024                            }
25025                        }),
25026                )
25027            },
25028        )
25029        .into_any_element()
25030}
25031
25032pub fn multibuffer_context_lines(cx: &App) -> u32 {
25033    EditorSettings::try_get(cx)
25034        .map(|settings| settings.excerpt_context_lines)
25035        .unwrap_or(2)
25036        .min(32)
25037}